浏览代码

expat 2021-05-23 (a28238bd)

Code extracted from:

    https://github.com/libexpat/libexpat.git

at commit a28238bdeebc087071777001245df1876a11f5ee (R_2_4_1).
Expat Upstream 4 年之前
父节点
当前提交
2da34f062a
共有 20 个文件被更改,包括 1405 次插入163 次删除
  1. 82 7
      README.md
  2. 5 2
      lib/ascii.h
  3. 3 1
      lib/asciitab.h
  4. 32 6
      lib/expat.h
  5. 8 1
      lib/expat_external.h
  6. 3 1
      lib/iasciitab.h
  7. 49 9
      lib/internal.h
  8. 3 1
      lib/latin1tab.h
  9. 2 2
      lib/nametab.h
  10. 4 9
      lib/siphash.h
  11. 3 1
      lib/utf8tab.h
  12. 4 15
      lib/winconfig.h
  13. 1144 78
      lib/xmlparse.c
  14. 11 6
      lib/xmlrole.c
  15. 4 1
      lib/xmlrole.h
  16. 25 17
      lib/xmltok.c
  17. 5 1
      lib/xmltok.h
  18. 11 3
      lib/xmltok_impl.c
  19. 2 1
      lib/xmltok_impl.h
  20. 5 1
      lib/xmltok_ns.c

+ 82 - 7
README.md

@@ -1,12 +1,14 @@
-[![Travis CI Build Status](https://travis-ci.org/libexpat/libexpat.svg?branch=master)](https://travis-ci.org/libexpat/libexpat)
+[![Run Linux Travis CI tasks](https://github.com/libexpat/libexpat/actions/workflows/linux.yml/badge.svg)](https://github.com/libexpat/libexpat/actions/workflows/linux.yml)
 [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/libexpat/libexpat?svg=true)](https://ci.appveyor.com/project/libexpat/libexpat)
 [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/libexpat/libexpat?svg=true)](https://ci.appveyor.com/project/libexpat/libexpat)
 [![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
 [![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
+[![Downloads SourceForge](https://img.shields.io/sourceforge/dt/expat?label=Downloads%20SourceForge)](https://sourceforge.net/projects/expat/files/)
+[![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
 
 
 
 
-# Expat, Release 2.2.10
+# Expat, Release 2.4.1
 
 
 This is Expat, a C library for parsing XML, started by
 This is Expat, a C library for parsing XML, started by
-[James Clark](https://en.wikipedia.org/wiki/James_Clark_(programmer)) in 1997.
+[James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997.
 Expat is a stream-oriented XML parser.  This means that you register
 Expat is a stream-oriented XML parser.  This means that you register
 handlers with the parser before starting the parse.  These handlers
 handlers with the parser before starting the parse.  These handlers
 are called when the parser discovers the associated structures in the
 are called when the parser discovers the associated structures in the
@@ -14,13 +16,14 @@ document being parsed.  A start tag is an example of the kind of
 structures for which you may register handlers.
 structures for which you may register handlers.
 
 
 Expat supports the following compilers:
 Expat supports the following compilers:
+
 - GNU GCC >=4.5
 - GNU GCC >=4.5
 - LLVM Clang >=3.5
 - LLVM Clang >=3.5
-- Microsoft Visual Studio >=9.0/2008
+- Microsoft Visual Studio >=15.0/2017 (rolling `${today} minus 5 years`)
 
 
 Windows users can use the
 Windows users can use the
-[`expat_win32` package](https://sourceforge.net/projects/expat/files/expat_win32/),
-which includes both precompiled libraries and executables, and source code for
+[`expat-win32bin-*.*.*.{exe,zip}` download](https://github.com/libexpat/libexpat/releases),
+which includes both pre-compiled libraries and executables, and source code for
 developers.
 developers.
 
 
 Expat is [free software](https://www.gnu.org/philosophy/free-sw.en.html).
 Expat is [free software](https://www.gnu.org/philosophy/free-sw.en.html).
@@ -30,6 +33,67 @@ contained in the file
 distributed with this package.
 distributed with this package.
 This license is the same as the MIT/X Consortium license.
 This license is the same as the MIT/X Consortium license.
 
 
+
+## Using libexpat in your CMake-Based Project
+
+There are two ways of using libexpat with CMake:
+
+### a) Module Mode
+
+This approach leverages CMake's own [module `FindEXPAT`](https://cmake.org/cmake/help/latest/module/FindEXPAT.html).
+
+Notice the *uppercase* `EXPAT` in the following example:
+
+```cmake
+cmake_minimum_required(VERSION 3.0)  # or 3.10, see below
+
+project(hello VERSION 1.0.0)
+
+find_package(EXPAT 2.2.8 MODULE REQUIRED)
+
+add_executable(hello
+    hello.c
+)
+
+# a) for CMake >=3.10 (see CMake's FindEXPAT docs)
+target_link_libraries(hello PUBLIC EXPAT::EXPAT)
+
+# b) for CMake >=3.0
+target_include_directories(hello PRIVATE ${EXPAT_INCLUDE_DIRS})
+target_link_libraries(hello PUBLIC ${EXPAT_LIBRARIES})
+```
+
+### b) Config Mode
+
+This approach requires files from…
+
+- libexpat >=2.2.8 where packaging uses the CMake build system
+or
+- libexpat >=2.3.0 where packaging uses the GNU Autotools build system
+  on Linux
+or
+- libexpat >=2.4.0 where packaging uses the GNU Autotools build system
+  on macOS or MinGW.
+
+Notice the *lowercase* `expat` in the following example:
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+
+project(hello VERSION 1.0.0)
+
+find_package(expat 2.2.8 CONFIG REQUIRED char dtd ns)
+
+add_executable(hello
+    hello.c
+)
+
+target_link_libraries(hello PUBLIC expat::expat)
+```
+
+
+## Building from a Git Clone
+
 If you are building Expat from a check-out from the
 If you are building Expat from a check-out from the
 [Git repository](https://github.com/libexpat/libexpat/),
 [Git repository](https://github.com/libexpat/libexpat/),
 you need to run a script that generates the configure script using the
 you need to run a script that generates the configure script using the
@@ -43,6 +107,11 @@ autoconf 2.58 or newer. Run the script like this:
 Once this has been done, follow the same instructions as for building
 Once this has been done, follow the same instructions as for building
 from a source distribution.
 from a source distribution.
 
 
+
+## Building from a Source Distribution
+
+### a) Building with the configure script (i.e. GNU Autotools)
+
 To build Expat from a source distribution, you first run the
 To build Expat from a source distribution, you first run the
 configuration shell script in the top level distribution directory:
 configuration shell script in the top level distribution directory:
 
 
@@ -132,8 +201,14 @@ A reference manual is available in the file `doc/reference.html` in this
 distribution.
 distribution.
 
 
 
 
-The CMake build system is still *experimental* and will replace the primary
+### b) Building with CMake
+
+The CMake build system is still *experimental* and may replace the primary
 build system based on GNU Autotools at some point when it is ready.
 build system based on GNU Autotools at some point when it is ready.
+
+
+#### Available Options
+
 For an idea of the available (non-advanced) options for building with CMake:
 For an idea of the available (non-advanced) options for building with CMake:
 
 
 ```console
 ```console

+ 5 - 2
lib/ascii.h

@@ -6,8 +6,11 @@
                         \___/_/\_\ .__/ \__,_|\__|
                         \___/_/\_\ .__/ \__,_|\__|
                                  |_| XML parser
                                  |_| XML parser
 
 
-   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 1999-2000 Thai Open Source Software Center Ltd
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2007      Karl Waclawek <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 3 - 1
lib/asciitab.h

@@ -7,7 +7,9 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 32 - 6
lib/expat.h

@@ -7,7 +7,14 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2000-2005 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2001-2002 Greg Stein <[email protected]>
+   Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2016      Cristian Rodríguez <[email protected]>
+   Copyright (c) 2016      Thomas Beutlich <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -115,7 +122,11 @@ enum XML_Error {
   XML_ERROR_RESERVED_PREFIX_XMLNS,
   XML_ERROR_RESERVED_PREFIX_XMLNS,
   XML_ERROR_RESERVED_NAMESPACE_URI,
   XML_ERROR_RESERVED_NAMESPACE_URI,
   /* Added in 2.2.1. */
   /* Added in 2.2.1. */
-  XML_ERROR_INVALID_ARGUMENT
+  XML_ERROR_INVALID_ARGUMENT,
+  /* Added in 2.3.0. */
+  XML_ERROR_NO_BUFFER,
+  /* Added in 2.4.0. */
+  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
 };
 };
 
 
 enum XML_Content_Type {
 enum XML_Content_Type {
@@ -513,7 +524,7 @@ typedef struct {
    Otherwise it must return XML_STATUS_ERROR.
    Otherwise it must return XML_STATUS_ERROR.
 
 
    If info does not describe a suitable encoding, then the parser will
    If info does not describe a suitable encoding, then the parser will
-   return an XML_UNKNOWN_ENCODING error.
+   return an XML_ERROR_UNKNOWN_ENCODING error.
 */
 */
 typedef int(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData,
 typedef int(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData,
                                                  const XML_Char *name,
                                                  const XML_Char *name,
@@ -997,7 +1008,10 @@ enum XML_FeatureEnum {
   XML_FEATURE_SIZEOF_XML_LCHAR,
   XML_FEATURE_SIZEOF_XML_LCHAR,
   XML_FEATURE_NS,
   XML_FEATURE_NS,
   XML_FEATURE_LARGE_SIZE,
   XML_FEATURE_LARGE_SIZE,
-  XML_FEATURE_ATTR_INFO
+  XML_FEATURE_ATTR_INFO,
+  /* Added in Expat 2.4.0. */
+  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
+  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
   /* Additional features must be added to the end of this enum. */
   /* Additional features must be added to the end of this enum. */
 };
 };
 
 
@@ -1010,12 +1024,24 @@ typedef struct {
 XMLPARSEAPI(const XML_Feature *)
 XMLPARSEAPI(const XML_Feature *)
 XML_GetFeatureList(void);
 XML_GetFeatureList(void);
 
 
+#ifdef XML_DTD
+/* Added in Expat 2.4.0. */
+XMLPARSEAPI(XML_Bool)
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+    XML_Parser parser, float maximumAmplificationFactor);
+
+/* Added in Expat 2.4.0. */
+XMLPARSEAPI(XML_Bool)
+XML_SetBillionLaughsAttackProtectionActivationThreshold(
+    XML_Parser parser, unsigned long long activationThresholdBytes);
+#endif
+
 /* Expat follows the semantic versioning convention.
 /* Expat follows the semantic versioning convention.
    See http://semver.org.
    See http://semver.org.
 */
 */
 #define XML_MAJOR_VERSION 2
 #define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 10
+#define XML_MINOR_VERSION 4
+#define XML_MICRO_VERSION 1
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 8 - 1
lib/expat_external.h

@@ -7,7 +7,14 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2000-2004 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2001-2002 Greg Stein <[email protected]>
+   Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
+   Copyright (c) 2016      Cristian Rodríguez <[email protected]>
+   Copyright (c) 2016-2019 Sebastian Pipping <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
+   Copyright (c) 2018      Yury Gribov <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 3 - 1
lib/iasciitab.h

@@ -7,7 +7,9 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 49 - 9
lib/internal.h

@@ -25,8 +25,12 @@
                         \___/_/\_\ .__/ \__,_|\__|
                         \___/_/\_\ .__/ \__,_|\__|
                                  |_| XML parser
                                  |_| XML parser
 
 
-   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
+   Copyright (c) 2003      Greg Stein <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2018      Yury Gribov <[email protected]>
+   Copyright (c) 2019      David Loffredo <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -101,22 +105,58 @@
 #  endif
 #  endif
 #endif
 #endif
 
 
+#include <limits.h> // ULONG_MAX
+
+#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
+#  define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
+#  if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u"
+#  else
+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+#  endif
+#else
+#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
+#  if ! defined(ULONG_MAX)
+#    error Compiler did not define ULONG_MAX for us
+#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
+#  else
+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+#  endif
+#endif
+
 #ifndef UNUSED_P
 #ifndef UNUSED_P
 #  define UNUSED_P(p) (void)p
 #  define UNUSED_P(p) (void)p
 #endif
 #endif
 
 
+/* NOTE BEGIN If you ever patch these defaults to greater values
+              for non-attack XML payload in your environment,
+              please file a bug report with libexpat.  Thank you!
+*/
+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT   \
+  100.0f
+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT    \
+  8388608 // 8 MiB, 2^23
+/* NOTE END */
+
+#include "expat.h" // so we can use type XML_Parser below
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#ifdef XML_ENABLE_VISIBILITY
-#  if XML_ENABLE_VISIBILITY
-__attribute__((visibility("default")))
-#  endif
+void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
+                                                const char **fromLimRef);
+
+#if defined(XML_DTD)
+unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
+unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
+const char *unsignedCharToPrintable(unsigned char c);
 #endif
 #endif
-void
-_INTERNAL_trim_to_complete_utf8_characters(const char *from,
-                                           const char **fromLimRef);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 3 - 1
lib/latin1tab.h

@@ -7,7 +7,9 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 2 - 2
lib/nametab.h

@@ -6,8 +6,8 @@
                         \___/_/\_\ .__/ \__,_|\__|
                         \___/_/\_\ .__/ \__,_|\__|
                                  |_| XML parser
                                  |_| XML parser
 
 
-   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000 Clark Cooper <[email protected]>
+   Copyright (c) 2017 Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 4 - 9
lib/siphash.h

@@ -11,6 +11,9 @@
  * --------------------------------------------------------------------------
  * --------------------------------------------------------------------------
  * HISTORY:
  * HISTORY:
  *
  *
+ * 2020-10-03  (Sebastian Pipping)
+ *   - Drop support for Visual Studio 9.0/2008 and earlier
+ *
  * 2019-08-03  (Sebastian Pipping)
  * 2019-08-03  (Sebastian Pipping)
  *   - Mark part of sip24_valid as to be excluded from clang-format
  *   - Mark part of sip24_valid as to be excluded from clang-format
  *   - Re-format code using clang-format 9
  *   - Re-format code using clang-format 9
@@ -96,15 +99,7 @@
 #define SIPHASH_H
 #define SIPHASH_H
 
 
 #include <stddef.h> /* size_t */
 #include <stddef.h> /* size_t */
-
-#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
-/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-#else
-#  include <stdint.h> /* uint64_t uint32_t uint8_t */
-#endif
+#include <stdint.h> /* uint64_t uint32_t uint8_t */
 
 
 /*
 /*
  * Workaround to not require a C++11 compiler for using ULL suffix
  * Workaround to not require a C++11 compiler for using ULL suffix

+ 3 - 1
lib/utf8tab.h

@@ -7,7 +7,9 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 4 - 15
lib/winconfig.h

@@ -6,8 +6,10 @@
                         \___/_/\_\ .__/ \__,_|\__|
                         \___/_/\_\ .__/ \__,_|\__|
                                  |_| XML parser
                                  |_| XML parser
 
 
-   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Greg Stein <[email protected]>
+   Copyright (c) 2005      Karl Waclawek <[email protected]>
+   Copyright (c) 2017-2021 Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -40,17 +42,4 @@
 #include <memory.h>
 #include <memory.h>
 #include <string.h>
 #include <string.h>
 
 
-#if defined(HAVE_EXPAT_CONFIG_H) /* e.g. MinGW */
-#  include <expat_config.h>
-#else /* !defined(HAVE_EXPAT_CONFIG_H) */
-
-#  define XML_NS 1
-#  define XML_DTD 1
-#  define XML_CONTEXT_BYTES 1024
-
-/* we will assume all Windows platforms are little endian */
-#  define BYTEORDER 1234
-
-#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
-
 #endif /* ndef WINCONFIG_H */
 #endif /* ndef WINCONFIG_H */

+ 1144 - 78
lib/xmlparse.c

@@ -1,4 +1,4 @@
-/* 5cd169f2942b85c05e0b1b96f9990f91ac3d07e470ad7ce906ac8590c8ed4f35 (2.2.10+)
+/* 8539b9040d9d901366a62560a064af7cb99811335784b363abc039c5b0ebc416 (2.4.1+)
                             __  __            _
                             __  __            _
                          ___\ \/ /_ __   __ _| |_
                          ___\ \/ /_ __   __ _| |_
                         / _ \\  /| '_ \ / _` | __|
                         / _ \\  /| '_ \ / _` | __|
@@ -7,7 +7,31 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2000-2006 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2001-2002 Greg Stein <[email protected]>
+   Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <[email protected]>
+   Copyright (c) 2016      Eric Rahm <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2016      Gaurav <[email protected]>
+   Copyright (c) 2016      Thomas Beutlich <[email protected]>
+   Copyright (c) 2016      Gustavo Grieco <[email protected]>
+   Copyright (c) 2016      Pascal Cuoq <[email protected]>
+   Copyright (c) 2016      Ed Schouten <[email protected]>
+   Copyright (c) 2017-2018 Rhodri James <[email protected]>
+   Copyright (c) 2017      Václav Slavík <[email protected]>
+   Copyright (c) 2017      Viktor Szakats <[email protected]>
+   Copyright (c) 2017      Chanho Park <[email protected]>
+   Copyright (c) 2017      Rolf Eike Beer <[email protected]>
+   Copyright (c) 2017      Hans Wennborg <[email protected]>
+   Copyright (c) 2018      Anton Maklakov <[email protected]>
+   Copyright (c) 2018      Benjamin Peterson <[email protected]>
+   Copyright (c) 2018      Marco Maggi <[email protected]>
+   Copyright (c) 2018      Mariusz Zaborski <[email protected]>
+   Copyright (c) 2019      David Loffredo <[email protected]>
+   Copyright (c) 2019-2020 Ben Wagner <[email protected]>
+   Copyright (c) 2019      Vadim Zeitlin <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -47,17 +71,8 @@
 #include <limits.h> /* UINT_MAX */
 #include <limits.h> /* UINT_MAX */
 #include <stdio.h>  /* fprintf */
 #include <stdio.h>  /* fprintf */
 #include <stdlib.h> /* getenv, rand_s */
 #include <stdlib.h> /* getenv, rand_s */
-
-#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
-/* vs2008/9.0 and earlier lack stdint.h; _MSC_VER 1600 is vs2010/10.0 */
-#  if defined(_WIN64)
-typedef unsigned __int64 uintptr_t;
-#  else
-typedef unsigned __int32 uintptr_t;
-#  endif
-#else
-#  include <stdint.h> /* uintptr_t */
-#endif
+#include <stdint.h> /* uintptr_t */
+#include <math.h>   /* isnan */
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #  define getpid GetCurrentProcessId
 #  define getpid GetCurrentProcessId
@@ -73,9 +88,9 @@ typedef unsigned __int32 uintptr_t;
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #  include "winconfig.h"
 #  include "winconfig.h"
-#elif defined(HAVE_EXPAT_CONFIG_H)
-#  include <expat_config.h>
-#endif /* ndef _WIN32 */
+#endif
+
+#include <expat_config.h>
 
 
 #include "ascii.h"
 #include "ascii.h"
 #include "expat.h"
 #include "expat.h"
@@ -382,6 +397,31 @@ typedef struct open_internal_entity {
   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
 } OPEN_INTERNAL_ENTITY;
 } OPEN_INTERNAL_ENTITY;
 
 
+enum XML_Account {
+  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat parser */
+  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
+                                   expansion */
+  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted already */
+};
+
+#ifdef XML_DTD
+typedef unsigned long long XmlBigCount;
+typedef struct accounting {
+  XmlBigCount countBytesDirect;
+  XmlBigCount countBytesIndirect;
+  int debugLevel;
+  float maximumAmplificationFactor; // >=1.0
+  unsigned long long activationThresholdBytes;
+} ACCOUNTING;
+
+typedef struct entity_stats {
+  unsigned int countEverOpened;
+  unsigned int currentDepth;
+  unsigned int maximumDepthSeen;
+  int debugLevel;
+} ENTITY_STATS;
+#endif /* XML_DTD */
+
 typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
 typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
                                          const char *end, const char **endPtr);
                                          const char *end, const char **endPtr);
 
 
@@ -412,16 +452,18 @@ static enum XML_Error initializeEncoding(XML_Parser parser);
 static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
 static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
                                const char *s, const char *end, int tok,
                                const char *s, const char *end, int tok,
                                const char *next, const char **nextPtr,
                                const char *next, const char **nextPtr,
-                               XML_Bool haveMore, XML_Bool allowClosingDoctype);
+                               XML_Bool haveMore, XML_Bool allowClosingDoctype,
+                               enum XML_Account account);
 static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
 static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
                                             XML_Bool betweenDecl);
                                             XML_Bool betweenDecl);
 static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
 static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
                                 const ENCODING *enc, const char *start,
                                 const ENCODING *enc, const char *start,
                                 const char *end, const char **endPtr,
                                 const char *end, const char **endPtr,
-                                XML_Bool haveMore);
+                                XML_Bool haveMore, enum XML_Account account);
 static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
 static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
                                      const char **startPtr, const char *end,
                                      const char **startPtr, const char *end,
-                                     const char **nextPtr, XML_Bool haveMore);
+                                     const char **nextPtr, XML_Bool haveMore,
+                                     enum XML_Account account);
 #ifdef XML_DTD
 #ifdef XML_DTD
 static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
 static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
                                       const char **startPtr, const char *end,
                                       const char **startPtr, const char *end,
@@ -431,7 +473,8 @@ static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
 static void freeBindings(XML_Parser parser, BINDING *bindings);
 static void freeBindings(XML_Parser parser, BINDING *bindings);
 static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
 static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
                                 const char *s, TAG_NAME *tagNamePtr,
                                 const char *s, TAG_NAME *tagNamePtr,
-                                BINDING **bindingsPtr);
+                                BINDING **bindingsPtr,
+                                enum XML_Account account);
 static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
 static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
                                  BINDING **bindingsPtr);
                                  BINDING **bindingsPtr);
@@ -440,15 +483,18 @@ static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
                            XML_Parser parser);
                            XML_Parser parser);
 static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
 static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
                                           XML_Bool isCdata, const char *,
                                           XML_Bool isCdata, const char *,
-                                          const char *, STRING_POOL *);
+                                          const char *, STRING_POOL *,
+                                          enum XML_Account account);
 static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
 static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
                                            XML_Bool isCdata, const char *,
                                            XML_Bool isCdata, const char *,
-                                           const char *, STRING_POOL *);
+                                           const char *, STRING_POOL *,
+                                           enum XML_Account account);
 static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
 static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
                                     const char *start, const char *end);
                                     const char *start, const char *end);
 static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
 static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
 static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
 static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
-                                       const char *start, const char *end);
+                                       const char *start, const char *end,
+                                       enum XML_Account account);
 static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
 static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
                                        const char *start, const char *end);
                                        const char *start, const char *end);
 static int reportComment(XML_Parser parser, const ENCODING *enc,
 static int reportComment(XML_Parser parser, const ENCODING *enc,
@@ -512,6 +558,34 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
 
 
 static void parserInit(XML_Parser parser, const XML_Char *encodingName);
 static void parserInit(XML_Parser parser, const XML_Char *encodingName);
 
 
+#ifdef XML_DTD
+static float accountingGetCurrentAmplification(XML_Parser rootParser);
+static void accountingReportStats(XML_Parser originParser, const char *epilog);
+static void accountingOnAbort(XML_Parser originParser);
+static void accountingReportDiff(XML_Parser rootParser,
+                                 unsigned int levelsAwayFromRootParser,
+                                 const char *before, const char *after,
+                                 ptrdiff_t bytesMore, int source_line,
+                                 enum XML_Account account);
+static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
+                                        const char *before, const char *after,
+                                        int source_line,
+                                        enum XML_Account account);
+
+static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
+                                      const char *action, int sourceLine);
+static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
+                                 int sourceLine);
+static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
+                                  int sourceLine);
+
+static XML_Parser getRootParserOf(XML_Parser parser,
+                                  unsigned int *outLevelDiff);
+#endif /* XML_DTD */
+
+static unsigned long getDebugLevel(const char *variableName,
+                                   unsigned long defaultDebugLevel);
+
 #define poolStart(pool) ((pool)->start)
 #define poolStart(pool) ((pool)->start)
 #define poolEnd(pool) ((pool)->ptr)
 #define poolEnd(pool) ((pool)->ptr)
 #define poolLength(pool) ((pool)->ptr - (pool)->start)
 #define poolLength(pool) ((pool)->ptr - (pool)->start)
@@ -625,6 +699,10 @@ struct XML_ParserStruct {
   enum XML_ParamEntityParsing m_paramEntityParsing;
   enum XML_ParamEntityParsing m_paramEntityParsing;
 #endif
 #endif
   unsigned long m_hash_secret_salt;
   unsigned long m_hash_secret_salt;
+#ifdef XML_DTD
+  ACCOUNTING m_accounting;
+  ENTITY_STATS m_entity_stats;
+#endif
 };
 };
 
 
 #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
 #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
@@ -809,9 +887,8 @@ gather_time_entropy(void) {
 
 
 static unsigned long
 static unsigned long
 ENTROPY_DEBUG(const char *label, unsigned long entropy) {
 ENTROPY_DEBUG(const char *label, unsigned long entropy) {
-  const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
-  if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
-    fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
+  if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) {
+    fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
             (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
             (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
   }
   }
   return entropy;
   return entropy;
@@ -1073,6 +1150,18 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
 #endif
 #endif
   parser->m_hash_secret_salt = 0;
   parser->m_hash_secret_salt = 0;
+
+#ifdef XML_DTD
+  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
+  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
+  parser->m_accounting.maximumAmplificationFactor
+      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
+  parser->m_accounting.activationThresholdBytes
+      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
+
+  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
+  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
+#endif
 }
 }
 
 
 /* moves list of bindings to m_freeBindingList */
 /* moves list of bindings to m_freeBindingList */
@@ -1893,6 +1982,12 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
     parser->m_errorCode = XML_ERROR_FINISHED;
     parser->m_errorCode = XML_ERROR_FINISHED;
     return XML_STATUS_ERROR;
     return XML_STATUS_ERROR;
   case XML_INITIALIZED:
   case XML_INITIALIZED:
+    /* Has someone called XML_GetBuffer successfully before? */
+    if (! parser->m_bufferPtr) {
+      parser->m_errorCode = XML_ERROR_NO_BUFFER;
+      return XML_STATUS_ERROR;
+    }
+
     if (parser->m_parentParser == NULL && ! startParsing(parser)) {
     if (parser->m_parentParser == NULL && ! startParsing(parser)) {
       parser->m_errorCode = XML_ERROR_NO_MEMORY;
       parser->m_errorCode = XML_ERROR_NO_MEMORY;
       return XML_STATUS_ERROR;
       return XML_STATUS_ERROR;
@@ -2337,6 +2432,14 @@ XML_ErrorString(enum XML_Error code) {
   /* Added in 2.2.5. */
   /* Added in 2.2.5. */
   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
     return XML_L("invalid argument");
     return XML_L("invalid argument");
+    /* Added in 2.3.0. */
+  case XML_ERROR_NO_BUFFER:
+    return XML_L(
+        "a successful prior call to function XML_GetBuffer is required");
+  /* Added in 2.4.0. */
+  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
+    return XML_L(
+        "limit on input amplification factor (from DTD and entities) breached");
   }
   }
   return NULL;
   return NULL;
 }
 }
@@ -2373,41 +2476,75 @@ XML_ExpatVersionInfo(void) {
 
 
 const XML_Feature *XMLCALL
 const XML_Feature *XMLCALL
 XML_GetFeatureList(void) {
 XML_GetFeatureList(void) {
-  static const XML_Feature features[]
-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
-          sizeof(XML_Char)},
-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
-          sizeof(XML_LChar)},
+  static const XML_Feature features[] = {
+      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+       sizeof(XML_Char)},
+      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+       sizeof(XML_LChar)},
 #ifdef XML_UNICODE
 #ifdef XML_UNICODE
-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
 #endif
 #endif
 #ifdef XML_UNICODE_WCHAR_T
 #ifdef XML_UNICODE_WCHAR_T
-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
 #endif
 #endif
 #ifdef XML_DTD
 #ifdef XML_DTD
-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
 #endif
 #endif
 #ifdef XML_CONTEXT_BYTES
 #ifdef XML_CONTEXT_BYTES
-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
-          XML_CONTEXT_BYTES},
+      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+       XML_CONTEXT_BYTES},
 #endif
 #endif
 #ifdef XML_MIN_SIZE
 #ifdef XML_MIN_SIZE
-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
 #endif
 #endif
 #ifdef XML_NS
 #ifdef XML_NS
-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
 #endif
 #endif
 #ifdef XML_LARGE_SIZE
 #ifdef XML_LARGE_SIZE
-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
 #endif
 #endif
 #ifdef XML_ATTR_INFO
 #ifdef XML_ATTR_INFO
-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
 #endif
 #endif
-         {XML_FEATURE_END, NULL, 0}};
+#ifdef XML_DTD
+      /* Added in Expat 2.4.0. */
+      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
+       XML_L("XML_BLAP_MAX_AMP"),
+       (long int)
+           EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
+      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
+       XML_L("XML_BLAP_ACT_THRES"),
+       EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
+#endif
+      {XML_FEATURE_END, NULL, 0}};
 
 
   return features;
   return features;
 }
 }
 
 
+#ifdef XML_DTD
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+    XML_Parser parser, float maximumAmplificationFactor) {
+  if ((parser == NULL) || (parser->m_parentParser != NULL)
+      || isnan(maximumAmplificationFactor)
+      || (maximumAmplificationFactor < 1.0f)) {
+    return XML_FALSE;
+  }
+  parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
+  return XML_TRUE;
+}
+
+XML_Bool XMLCALL
+XML_SetBillionLaughsAttackProtectionActivationThreshold(
+    XML_Parser parser, unsigned long long activationThresholdBytes) {
+  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
+    return XML_FALSE;
+  }
+  parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
+  return XML_TRUE;
+}
+#endif /* XML_DTD */
+
 /* Initially tag->rawName always points into the parse buffer;
 /* Initially tag->rawName always points into the parse buffer;
    for those TAG instances opened while the current parse buffer was
    for those TAG instances opened while the current parse buffer was
    processed, and not yet closed, we need to store tag->rawName in a more
    processed, and not yet closed, we need to store tag->rawName in a more
@@ -2460,9 +2597,9 @@ storeRawNames(XML_Parser parser) {
 static enum XML_Error PTRCALL
 static enum XML_Error PTRCALL
 contentProcessor(XML_Parser parser, const char *start, const char *end,
 contentProcessor(XML_Parser parser, const char *start, const char *end,
                  const char **endPtr) {
                  const char **endPtr) {
-  enum XML_Error result
-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+  enum XML_Error result = doContent(
+      parser, 0, parser->m_encoding, start, end, endPtr,
+      (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
   if (result == XML_ERROR_NONE) {
   if (result == XML_ERROR_NONE) {
     if (! storeRawNames(parser))
     if (! storeRawNames(parser))
       return XML_ERROR_NO_MEMORY;
       return XML_ERROR_NO_MEMORY;
@@ -2487,6 +2624,14 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
   switch (tok) {
   switch (tok) {
   case XML_TOK_BOM:
   case XML_TOK_BOM:
+#ifdef XML_DTD
+    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
+                                  XML_ACCOUNT_DIRECT)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+#endif /* XML_DTD */
+
     /* If we are at the end of the buffer, this would cause the next stage,
     /* If we are at the end of the buffer, this would cause the next stage,
        i.e. externalEntityInitProcessor3, to pass control directly to
        i.e. externalEntityInitProcessor3, to pass control directly to
        doContent (by detecting XML_TOK_NONE) without processing any xml text
        doContent (by detecting XML_TOK_NONE) without processing any xml text
@@ -2524,6 +2669,10 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
   const char *next = start; /* XmlContentTok doesn't always set the last arg */
   const char *next = start; /* XmlContentTok doesn't always set the last arg */
   parser->m_eventPtr = start;
   parser->m_eventPtr = start;
   tok = XmlContentTok(parser->m_encoding, start, end, &next);
   tok = XmlContentTok(parser->m_encoding, start, end, &next);
+  /* Note: These bytes are accounted later in:
+           - processXmlDecl
+           - externalEntityContentProcessor
+  */
   parser->m_eventEndPtr = next;
   parser->m_eventEndPtr = next;
 
 
   switch (tok) {
   switch (tok) {
@@ -2565,7 +2714,8 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
                                const char *end, const char **endPtr) {
                                const char *end, const char **endPtr) {
   enum XML_Error result
   enum XML_Error result
       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
+                  XML_ACCOUNT_ENTITY_EXPANSION);
   if (result == XML_ERROR_NONE) {
   if (result == XML_ERROR_NONE) {
     if (! storeRawNames(parser))
     if (! storeRawNames(parser))
       return XML_ERROR_NO_MEMORY;
       return XML_ERROR_NO_MEMORY;
@@ -2576,7 +2726,7 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
 static enum XML_Error
 static enum XML_Error
 doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
 doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
           const char *s, const char *end, const char **nextPtr,
           const char *s, const char *end, const char **nextPtr,
-          XML_Bool haveMore) {
+          XML_Bool haveMore, enum XML_Account account) {
   /* save one level of indirection */
   /* save one level of indirection */
   DTD *const dtd = parser->m_dtd;
   DTD *const dtd = parser->m_dtd;
 
 
@@ -2594,6 +2744,17 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
   for (;;) {
   for (;;) {
     const char *next = s; /* XmlContentTok doesn't always set the last arg */
     const char *next = s; /* XmlContentTok doesn't always set the last arg */
     int tok = XmlContentTok(enc, s, end, &next);
     int tok = XmlContentTok(enc, s, end, &next);
+#ifdef XML_DTD
+    const char *accountAfter
+        = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
+              ? (haveMore ? s /* i.e. 0 bytes */ : end)
+              : next;
+    if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
+                                  account)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+#endif
     *eventEndPP = next;
     *eventEndPP = next;
     switch (tok) {
     switch (tok) {
     case XML_TOK_TRAILING_CR:
     case XML_TOK_TRAILING_CR:
@@ -2649,6 +2810,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
       if (ch) {
       if (ch) {
+#ifdef XML_DTD
+        /* NOTE: We are replacing 4-6 characters original input for 1 character
+         *       so there is no amplification and hence recording without
+         *       protection. */
+        accountingDiffTolerated(parser, tok, (char *)&ch,
+                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
+                                XML_ACCOUNT_ENTITY_EXPANSION);
+#endif /* XML_DTD */
         if (parser->m_characterDataHandler)
         if (parser->m_characterDataHandler)
           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
         else if (parser->m_defaultHandler)
         else if (parser->m_defaultHandler)
@@ -2767,7 +2936,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
       }
       }
       tag->name.str = (XML_Char *)tag->buf;
       tag->name.str = (XML_Char *)tag->buf;
       *toPtr = XML_T('\0');
       *toPtr = XML_T('\0');
-      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+      result
+          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
       if (result)
       if (result)
         return result;
         return result;
       if (parser->m_startElementHandler)
       if (parser->m_startElementHandler)
@@ -2791,7 +2961,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
       if (! name.str)
       if (! name.str)
         return XML_ERROR_NO_MEMORY;
         return XML_ERROR_NO_MEMORY;
       poolFinish(&parser->m_tempPool);
       poolFinish(&parser->m_tempPool);
-      result = storeAtts(parser, enc, s, &name, &bindings);
+      result = storeAtts(parser, enc, s, &name, &bindings,
+                         XML_ACCOUNT_NONE /* token spans whole start tag */);
       if (result != XML_ERROR_NONE) {
       if (result != XML_ERROR_NONE) {
         freeBindings(parser, bindings);
         freeBindings(parser, bindings);
         return result;
         return result;
@@ -2926,7 +3097,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
       /* END disabled code */
       /* END disabled code */
       else if (parser->m_defaultHandler)
       else if (parser->m_defaultHandler)
         reportDefault(parser, enc, s, next);
         reportDefault(parser, enc, s, next);
-      result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+      result
+          = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
       if (result != XML_ERROR_NONE)
       if (result != XML_ERROR_NONE)
         return result;
         return result;
       else if (! next) {
       else if (! next) {
@@ -3055,7 +3227,8 @@ freeBindings(XML_Parser parser, BINDING *bindings) {
 */
 */
 static enum XML_Error
 static enum XML_Error
 storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
 storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
+          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
+          enum XML_Account account) {
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   ELEMENT_TYPE *elementType;
   ELEMENT_TYPE *elementType;
   int nDefaultAtts;
   int nDefaultAtts;
@@ -3165,7 +3338,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
       /* normalize the attribute value */
       /* normalize the attribute value */
       result = storeAttributeValue(
       result = storeAttributeValue(
           parser, enc, isCdata, parser->m_atts[i].valuePtr,
           parser, enc, isCdata, parser->m_atts[i].valuePtr,
-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
+          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
       if (result)
       if (result)
         return result;
         return result;
       appAtts[attIndex] = poolStart(&parser->m_tempPool);
       appAtts[attIndex] = poolStart(&parser->m_tempPool);
@@ -3554,9 +3727,9 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
 static enum XML_Error PTRCALL
 static enum XML_Error PTRCALL
 cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
 cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
                       const char **endPtr) {
                       const char **endPtr) {
-  enum XML_Error result
-      = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
-                       (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+  enum XML_Error result = doCdataSection(
+      parser, parser->m_encoding, &start, end, endPtr,
+      (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
   if (result != XML_ERROR_NONE)
   if (result != XML_ERROR_NONE)
     return result;
     return result;
   if (start) {
   if (start) {
@@ -3576,7 +3749,8 @@ cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
 */
 */
 static enum XML_Error
 static enum XML_Error
 doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
 doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
-               const char *end, const char **nextPtr, XML_Bool haveMore) {
+               const char *end, const char **nextPtr, XML_Bool haveMore,
+               enum XML_Account account) {
   const char *s = *startPtr;
   const char *s = *startPtr;
   const char **eventPP;
   const char **eventPP;
   const char **eventEndPP;
   const char **eventEndPP;
@@ -3594,6 +3768,14 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
   for (;;) {
   for (;;) {
     const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
     const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
     int tok = XmlCdataSectionTok(enc, s, end, &next);
     int tok = XmlCdataSectionTok(enc, s, end, &next);
+#ifdef XML_DTD
+    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+#else
+    UNUSED_P(account);
+#endif
     *eventEndPP = next;
     *eventEndPP = next;
     switch (tok) {
     switch (tok) {
     case XML_TOK_CDATA_SECT_CLOSE:
     case XML_TOK_CDATA_SECT_CLOSE:
@@ -3738,6 +3920,13 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
   *eventPP = s;
   *eventPP = s;
   *startPtr = NULL;
   *startPtr = NULL;
   tok = XmlIgnoreSectionTok(enc, s, end, &next);
   tok = XmlIgnoreSectionTok(enc, s, end, &next);
+#  ifdef XML_DTD
+  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+                                XML_ACCOUNT_DIRECT)) {
+    accountingOnAbort(parser);
+    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+  }
+#  endif
   *eventEndPP = next;
   *eventEndPP = next;
   switch (tok) {
   switch (tok) {
   case XML_TOK_IGNORE_SECT:
   case XML_TOK_IGNORE_SECT:
@@ -3822,6 +4011,15 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
   const char *versionend;
   const char *versionend;
   const XML_Char *storedversion = NULL;
   const XML_Char *storedversion = NULL;
   int standalone = -1;
   int standalone = -1;
+
+#ifdef XML_DTD
+  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
+                                XML_ACCOUNT_DIRECT)) {
+    accountingOnAbort(parser);
+    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+  }
+#endif
+
   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
@@ -3971,6 +4169,10 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
 
 
   for (;;) {
   for (;;) {
     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
+    /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
+             - storeEntityValue
+             - processXmlDecl
+    */
     parser->m_eventEndPtr = next;
     parser->m_eventEndPtr = next;
     if (tok <= 0) {
     if (tok <= 0) {
       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
@@ -3989,7 +4191,8 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
         break;
         break;
       }
       }
       /* found end of entity value - can store it now */
       /* found end of entity value - can store it now */
-      return storeEntityValue(parser, parser->m_encoding, s, end);
+      return storeEntityValue(parser, parser->m_encoding, s, end,
+                              XML_ACCOUNT_DIRECT);
     } else if (tok == XML_TOK_XML_DECL) {
     } else if (tok == XML_TOK_XML_DECL) {
       enum XML_Error result;
       enum XML_Error result;
       result = processXmlDecl(parser, 0, start, next);
       result = processXmlDecl(parser, 0, start, next);
@@ -4016,6 +4219,14 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
     */
     */
     else if (tok == XML_TOK_BOM && next == end
     else if (tok == XML_TOK_BOM && next == end
              && ! parser->m_parsingStatus.finalBuffer) {
              && ! parser->m_parsingStatus.finalBuffer) {
+#  ifdef XML_DTD
+      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+                                    XML_ACCOUNT_DIRECT)) {
+        accountingOnAbort(parser);
+        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+      }
+#  endif
+
       *nextPtr = next;
       *nextPtr = next;
       return XML_ERROR_NONE;
       return XML_ERROR_NONE;
     }
     }
@@ -4058,16 +4269,24 @@ externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
   }
   }
   /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
   /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
      However, when parsing an external subset, doProlog will not accept a BOM
      However, when parsing an external subset, doProlog will not accept a BOM
-     as valid, and report a syntax error, so we have to skip the BOM
+     as valid, and report a syntax error, so we have to skip the BOM, and
+     account for the BOM bytes.
   */
   */
   else if (tok == XML_TOK_BOM) {
   else if (tok == XML_TOK_BOM) {
+    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+                                  XML_ACCOUNT_DIRECT)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+
     s = next;
     s = next;
     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   }
   }
 
 
   parser->m_processor = prologProcessor;
   parser->m_processor = prologProcessor;
   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+                  XML_ACCOUNT_DIRECT);
 }
 }
 
 
 static enum XML_Error PTRCALL
 static enum XML_Error PTRCALL
@@ -4080,6 +4299,9 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
 
 
   for (;;) {
   for (;;) {
     tok = XmlPrologTok(enc, start, end, &next);
     tok = XmlPrologTok(enc, start, end, &next);
+    /* Note: These bytes are accounted later in:
+             - storeEntityValue
+    */
     if (tok <= 0) {
     if (tok <= 0) {
       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
         *nextPtr = s;
         *nextPtr = s;
@@ -4097,7 +4319,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
         break;
         break;
       }
       }
       /* found end of entity value - can store it now */
       /* found end of entity value - can store it now */
-      return storeEntityValue(parser, enc, s, end);
+      return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
     }
     }
     start = next;
     start = next;
   }
   }
@@ -4111,13 +4333,14 @@ prologProcessor(XML_Parser parser, const char *s, const char *end,
   const char *next = s;
   const char *next = s;
   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+                  XML_ACCOUNT_DIRECT);
 }
 }
 
 
 static enum XML_Error
 static enum XML_Error
 doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
 doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
-         XML_Bool allowClosingDoctype) {
+         XML_Bool allowClosingDoctype, enum XML_Account account) {
 #ifdef XML_DTD
 #ifdef XML_DTD
   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
 #endif /* XML_DTD */
 #endif /* XML_DTD */
@@ -4144,6 +4367,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
 
 
+#ifndef XML_DTD
+  UNUSED_P(account);
+#endif
+
   /* save one level of indirection */
   /* save one level of indirection */
   DTD *const dtd = parser->m_dtd;
   DTD *const dtd = parser->m_dtd;
 
 
@@ -4208,6 +4435,19 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
       }
       }
     }
     }
     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
+#ifdef XML_DTD
+    switch (role) {
+    case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
+    case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
+    case XML_ROLE_TEXT_DECL:      // bytes accounted in processXmlDecl
+      break;
+    default:
+      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
+        accountingOnAbort(parser);
+        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+      }
+    }
+#endif
     switch (role) {
     switch (role) {
     case XML_ROLE_XML_DECL: {
     case XML_ROLE_XML_DECL: {
       enum XML_Error result = processXmlDecl(parser, 0, s, next);
       enum XML_Error result = processXmlDecl(parser, 0, s, next);
@@ -4483,7 +4723,8 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
         const XML_Char *attVal;
         const XML_Char *attVal;
         enum XML_Error result = storeAttributeValue(
         enum XML_Error result = storeAttributeValue(
             parser, enc, parser->m_declAttributeIsCdata,
             parser, enc, parser->m_declAttributeIsCdata,
-            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
+            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
+            XML_ACCOUNT_NONE);
         if (result)
         if (result)
           return result;
           return result;
         attVal = poolStart(&dtd->pool);
         attVal = poolStart(&dtd->pool);
@@ -4516,8 +4757,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
       break;
       break;
     case XML_ROLE_ENTITY_VALUE:
     case XML_ROLE_ENTITY_VALUE:
       if (dtd->keepProcessing) {
       if (dtd->keepProcessing) {
-        enum XML_Error result = storeEntityValue(
-            parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+        enum XML_Error result
+            = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
+                               next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
         if (parser->m_declEntity) {
         if (parser->m_declEntity) {
           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
           parser->m_declEntity->textLen
           parser->m_declEntity->textLen
@@ -4907,12 +5149,15 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
         if (parser->m_externalEntityRefHandler) {
         if (parser->m_externalEntityRefHandler) {
           dtd->paramEntityRead = XML_FALSE;
           dtd->paramEntityRead = XML_FALSE;
           entity->open = XML_TRUE;
           entity->open = XML_TRUE;
+          entityTrackingOnOpen(parser, entity, __LINE__);
           if (! parser->m_externalEntityRefHandler(
           if (! parser->m_externalEntityRefHandler(
                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
                   entity->systemId, entity->publicId)) {
                   entity->systemId, entity->publicId)) {
+            entityTrackingOnClose(parser, entity, __LINE__);
             entity->open = XML_FALSE;
             entity->open = XML_FALSE;
             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
           }
           }
+          entityTrackingOnClose(parser, entity, __LINE__);
           entity->open = XML_FALSE;
           entity->open = XML_FALSE;
           handleDefault = XML_FALSE;
           handleDefault = XML_FALSE;
           if (! dtd->paramEntityRead) {
           if (! dtd->paramEntityRead) {
@@ -5110,6 +5355,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
   for (;;) {
   for (;;) {
     const char *next = NULL;
     const char *next = NULL;
     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+#ifdef XML_DTD
+    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
+                                  XML_ACCOUNT_DIRECT)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+#endif
     parser->m_eventEndPtr = next;
     parser->m_eventEndPtr = next;
     switch (tok) {
     switch (tok) {
     /* report partial linebreak - it might be the last token */
     /* report partial linebreak - it might be the last token */
@@ -5183,6 +5435,9 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
       return XML_ERROR_NO_MEMORY;
       return XML_ERROR_NO_MEMORY;
   }
   }
   entity->open = XML_TRUE;
   entity->open = XML_TRUE;
+#ifdef XML_DTD
+  entityTrackingOnOpen(parser, entity, __LINE__);
+#endif
   entity->processed = 0;
   entity->processed = 0;
   openEntity->next = parser->m_openInternalEntities;
   openEntity->next = parser->m_openInternalEntities;
   parser->m_openInternalEntities = openEntity;
   parser->m_openInternalEntities = openEntity;
@@ -5201,17 +5456,22 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
     int tok
     int tok
         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
-                      tok, next, &next, XML_FALSE, XML_FALSE);
+                      tok, next, &next, XML_FALSE, XML_FALSE,
+                      XML_ACCOUNT_ENTITY_EXPANSION);
   } else
   } else
 #endif /* XML_DTD */
 #endif /* XML_DTD */
     result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
     result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
-                       textStart, textEnd, &next, XML_FALSE);
+                       textStart, textEnd, &next, XML_FALSE,
+                       XML_ACCOUNT_ENTITY_EXPANSION);
 
 
   if (result == XML_ERROR_NONE) {
   if (result == XML_ERROR_NONE) {
     if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
     if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
       entity->processed = (int)(next - textStart);
       entity->processed = (int)(next - textStart);
       parser->m_processor = internalEntityProcessor;
       parser->m_processor = internalEntityProcessor;
     } else {
     } else {
+#ifdef XML_DTD
+      entityTrackingOnClose(parser, entity, __LINE__);
+#endif /* XML_DTD */
       entity->open = XML_FALSE;
       entity->open = XML_FALSE;
       parser->m_openInternalEntities = openEntity->next;
       parser->m_openInternalEntities = openEntity->next;
       /* put openEntity back in list of free instances */
       /* put openEntity back in list of free instances */
@@ -5244,12 +5504,13 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
     int tok
     int tok
         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
-                      tok, next, &next, XML_FALSE, XML_TRUE);
+                      tok, next, &next, XML_FALSE, XML_TRUE,
+                      XML_ACCOUNT_ENTITY_EXPANSION);
   } else
   } else
 #endif /* XML_DTD */
 #endif /* XML_DTD */
     result = doContent(parser, openEntity->startTagLevel,
     result = doContent(parser, openEntity->startTagLevel,
                        parser->m_internalEncoding, textStart, textEnd, &next,
                        parser->m_internalEncoding, textStart, textEnd, &next,
-                       XML_FALSE);
+                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
 
 
   if (result != XML_ERROR_NONE)
   if (result != XML_ERROR_NONE)
     return result;
     return result;
@@ -5258,6 +5519,9 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
     entity->processed = (int)(next - (const char *)entity->textPtr);
     entity->processed = (int)(next - (const char *)entity->textPtr);
     return result;
     return result;
   } else {
   } else {
+#ifdef XML_DTD
+    entityTrackingOnClose(parser, entity, __LINE__);
+#endif
     entity->open = XML_FALSE;
     entity->open = XML_FALSE;
     parser->m_openInternalEntities = openEntity->next;
     parser->m_openInternalEntities = openEntity->next;
     /* put openEntity back in list of free instances */
     /* put openEntity back in list of free instances */
@@ -5271,7 +5535,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
     parser->m_processor = prologProcessor;
     parser->m_processor = prologProcessor;
     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
     return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
     return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
+                    XML_ACCOUNT_DIRECT);
   } else
   } else
 #endif /* XML_DTD */
 #endif /* XML_DTD */
   {
   {
@@ -5279,7 +5544,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
     /* see externalEntityContentProcessor vs contentProcessor */
     /* see externalEntityContentProcessor vs contentProcessor */
     return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
     return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
                      s, end, nextPtr,
                      s, end, nextPtr,
-                     (XML_Bool)! parser->m_parsingStatus.finalBuffer);
+                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
+                     XML_ACCOUNT_DIRECT);
   }
   }
 }
 }
 
 
@@ -5294,9 +5560,10 @@ errorProcessor(XML_Parser parser, const char *s, const char *end,
 
 
 static enum XML_Error
 static enum XML_Error
 storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
 storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
-                    const char *ptr, const char *end, STRING_POOL *pool) {
+                    const char *ptr, const char *end, STRING_POOL *pool,
+                    enum XML_Account account) {
   enum XML_Error result
   enum XML_Error result
-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
+      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
   if (result)
   if (result)
     return result;
     return result;
   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
@@ -5308,11 +5575,23 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
 
 
 static enum XML_Error
 static enum XML_Error
 appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
 appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
-                     const char *ptr, const char *end, STRING_POOL *pool) {
+                     const char *ptr, const char *end, STRING_POOL *pool,
+                     enum XML_Account account) {
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+#ifndef XML_DTD
+  UNUSED_P(account);
+#endif
+
   for (;;) {
   for (;;) {
-    const char *next;
+    const char *next
+        = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+#ifdef XML_DTD
+    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
+      accountingOnAbort(parser);
+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+    }
+#endif
     switch (tok) {
     switch (tok) {
     case XML_TOK_NONE:
     case XML_TOK_NONE:
       return XML_ERROR_NONE;
       return XML_ERROR_NONE;
@@ -5372,6 +5651,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
       if (ch) {
       if (ch) {
+#ifdef XML_DTD
+        /* NOTE: We are replacing 4-6 characters original input for 1 character
+         *       so there is no amplification and hence recording without
+         *       protection. */
+        accountingDiffTolerated(parser, tok, (char *)&ch,
+                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
+                                XML_ACCOUNT_ENTITY_EXPANSION);
+#endif /* XML_DTD */
         if (! poolAppendChar(pool, ch))
         if (! poolAppendChar(pool, ch))
           return XML_ERROR_NO_MEMORY;
           return XML_ERROR_NO_MEMORY;
         break;
         break;
@@ -5449,9 +5736,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
         enum XML_Error result;
         enum XML_Error result;
         const XML_Char *textEnd = entity->textPtr + entity->textLen;
         const XML_Char *textEnd = entity->textPtr + entity->textLen;
         entity->open = XML_TRUE;
         entity->open = XML_TRUE;
+#ifdef XML_DTD
+        entityTrackingOnOpen(parser, entity, __LINE__);
+#endif
         result = appendAttributeValue(parser, parser->m_internalEncoding,
         result = appendAttributeValue(parser, parser->m_internalEncoding,
                                       isCdata, (const char *)entity->textPtr,
                                       isCdata, (const char *)entity->textPtr,
-                                      (const char *)textEnd, pool);
+                                      (const char *)textEnd, pool,
+                                      XML_ACCOUNT_ENTITY_EXPANSION);
+#ifdef XML_DTD
+        entityTrackingOnClose(parser, entity, __LINE__);
+#endif
         entity->open = XML_FALSE;
         entity->open = XML_FALSE;
         if (result)
         if (result)
           return result;
           return result;
@@ -5481,13 +5775,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
 
 
 static enum XML_Error
 static enum XML_Error
 storeEntityValue(XML_Parser parser, const ENCODING *enc,
 storeEntityValue(XML_Parser parser, const ENCODING *enc,
-                 const char *entityTextPtr, const char *entityTextEnd) {
+                 const char *entityTextPtr, const char *entityTextEnd,
+                 enum XML_Account account) {
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   STRING_POOL *pool = &(dtd->entityValuePool);
   STRING_POOL *pool = &(dtd->entityValuePool);
   enum XML_Error result = XML_ERROR_NONE;
   enum XML_Error result = XML_ERROR_NONE;
 #ifdef XML_DTD
 #ifdef XML_DTD
   int oldInEntityValue = parser->m_prologState.inEntityValue;
   int oldInEntityValue = parser->m_prologState.inEntityValue;
   parser->m_prologState.inEntityValue = 1;
   parser->m_prologState.inEntityValue = 1;
+#else
+  UNUSED_P(account);
 #endif /* XML_DTD */
 #endif /* XML_DTD */
   /* never return Null for the value argument in EntityDeclHandler,
   /* never return Null for the value argument in EntityDeclHandler,
      since this would indicate an external entity; therefore we
      since this would indicate an external entity; therefore we
@@ -5498,8 +5795,19 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
   }
   }
 
 
   for (;;) {
   for (;;) {
-    const char *next;
+    const char *next
+        = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+
+#ifdef XML_DTD
+    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
+                                  account)) {
+      accountingOnAbort(parser);
+      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
+      goto endEntityValue;
+    }
+#endif
+
     switch (tok) {
     switch (tok) {
     case XML_TOK_PARAM_ENTITY_REF:
     case XML_TOK_PARAM_ENTITY_REF:
 #ifdef XML_DTD
 #ifdef XML_DTD
@@ -5535,13 +5843,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
           if (parser->m_externalEntityRefHandler) {
           if (parser->m_externalEntityRefHandler) {
             dtd->paramEntityRead = XML_FALSE;
             dtd->paramEntityRead = XML_FALSE;
             entity->open = XML_TRUE;
             entity->open = XML_TRUE;
+            entityTrackingOnOpen(parser, entity, __LINE__);
             if (! parser->m_externalEntityRefHandler(
             if (! parser->m_externalEntityRefHandler(
                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
                     entity->systemId, entity->publicId)) {
                     entity->systemId, entity->publicId)) {
+              entityTrackingOnClose(parser, entity, __LINE__);
               entity->open = XML_FALSE;
               entity->open = XML_FALSE;
               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
               goto endEntityValue;
               goto endEntityValue;
             }
             }
+            entityTrackingOnClose(parser, entity, __LINE__);
             entity->open = XML_FALSE;
             entity->open = XML_FALSE;
             if (! dtd->paramEntityRead)
             if (! dtd->paramEntityRead)
               dtd->keepProcessing = dtd->standalone;
               dtd->keepProcessing = dtd->standalone;
@@ -5549,9 +5860,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
             dtd->keepProcessing = dtd->standalone;
             dtd->keepProcessing = dtd->standalone;
         } else {
         } else {
           entity->open = XML_TRUE;
           entity->open = XML_TRUE;
+          entityTrackingOnOpen(parser, entity, __LINE__);
           result = storeEntityValue(
           result = storeEntityValue(
               parser, parser->m_internalEncoding, (const char *)entity->textPtr,
               parser, parser->m_internalEncoding, (const char *)entity->textPtr,
-              (const char *)(entity->textPtr + entity->textLen));
+              (const char *)(entity->textPtr + entity->textLen),
+              XML_ACCOUNT_ENTITY_EXPANSION);
+          entityTrackingOnClose(parser, entity, __LINE__);
           entity->open = XML_FALSE;
           entity->open = XML_FALSE;
           if (result)
           if (result)
             goto endEntityValue;
             goto endEntityValue;
@@ -6912,3 +7226,755 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
   memcpy(result, s, charsRequired * sizeof(XML_Char));
   memcpy(result, s, charsRequired * sizeof(XML_Char));
   return result;
   return result;
 }
 }
+
+#ifdef XML_DTD
+
+static float
+accountingGetCurrentAmplification(XML_Parser rootParser) {
+  const XmlBigCount countBytesOutput
+      = rootParser->m_accounting.countBytesDirect
+        + rootParser->m_accounting.countBytesIndirect;
+  const float amplificationFactor
+      = rootParser->m_accounting.countBytesDirect
+            ? (countBytesOutput
+               / (float)(rootParser->m_accounting.countBytesDirect))
+            : 1.0f;
+  assert(! rootParser->m_parentParser);
+  return amplificationFactor;
+}
+
+static void
+accountingReportStats(XML_Parser originParser, const char *epilog) {
+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+  assert(! rootParser->m_parentParser);
+
+  if (rootParser->m_accounting.debugLevel < 1) {
+    return;
+  }
+
+  const float amplificationFactor
+      = accountingGetCurrentAmplification(rootParser);
+  fprintf(stderr,
+          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
+              "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
+          (void *)rootParser, rootParser->m_accounting.countBytesDirect,
+          rootParser->m_accounting.countBytesIndirect,
+          (double)amplificationFactor, epilog);
+}
+
+static void
+accountingOnAbort(XML_Parser originParser) {
+  accountingReportStats(originParser, " ABORTING\n");
+}
+
+static void
+accountingReportDiff(XML_Parser rootParser,
+                     unsigned int levelsAwayFromRootParser, const char *before,
+                     const char *after, ptrdiff_t bytesMore, int source_line,
+                     enum XML_Account account) {
+  assert(! rootParser->m_parentParser);
+
+  fprintf(stderr,
+          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
+          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
+          levelsAwayFromRootParser, source_line, 10, "");
+
+  const char ellipis[] = "[..]";
+  const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
+  const unsigned int contextLength = 10;
+
+  /* Note: Performance is of no concern here */
+  const char *walker = before;
+  if ((rootParser->m_accounting.debugLevel >= 3)
+      || (after - before)
+             <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
+    for (; walker < after; walker++) {
+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+    }
+  } else {
+    for (; walker < before + contextLength; walker++) {
+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+    }
+    fprintf(stderr, ellipis);
+    walker = after - contextLength;
+    for (; walker < after; walker++) {
+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
+    }
+  }
+  fprintf(stderr, "\"\n");
+}
+
+static XML_Bool
+accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
+                        const char *after, int source_line,
+                        enum XML_Account account) {
+  /* Note: We need to check the token type *first* to be sure that
+   *       we can even access variable <after>, safely.
+   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
+  switch (tok) {
+  case XML_TOK_INVALID:
+  case XML_TOK_PARTIAL:
+  case XML_TOK_PARTIAL_CHAR:
+  case XML_TOK_NONE:
+    return XML_TRUE;
+  }
+
+  if (account == XML_ACCOUNT_NONE)
+    return XML_TRUE; /* because these bytes have been accounted for, already */
+
+  unsigned int levelsAwayFromRootParser;
+  const XML_Parser rootParser
+      = getRootParserOf(originParser, &levelsAwayFromRootParser);
+  assert(! rootParser->m_parentParser);
+
+  const int isDirect
+      = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
+  const ptrdiff_t bytesMore = after - before;
+
+  XmlBigCount *const additionTarget
+      = isDirect ? &rootParser->m_accounting.countBytesDirect
+                 : &rootParser->m_accounting.countBytesIndirect;
+
+  /* Detect and avoid integer overflow */
+  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
+    return XML_FALSE;
+  *additionTarget += bytesMore;
+
+  const XmlBigCount countBytesOutput
+      = rootParser->m_accounting.countBytesDirect
+        + rootParser->m_accounting.countBytesIndirect;
+  const float amplificationFactor
+      = accountingGetCurrentAmplification(rootParser);
+  const XML_Bool tolerated
+      = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
+        || (amplificationFactor
+            <= rootParser->m_accounting.maximumAmplificationFactor);
+
+  if (rootParser->m_accounting.debugLevel >= 2) {
+    accountingReportStats(rootParser, "");
+    accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
+                         bytesMore, source_line, account);
+  }
+
+  return tolerated;
+}
+
+unsigned long long
+testingAccountingGetCountBytesDirect(XML_Parser parser) {
+  if (! parser)
+    return 0;
+  return parser->m_accounting.countBytesDirect;
+}
+
+unsigned long long
+testingAccountingGetCountBytesIndirect(XML_Parser parser) {
+  if (! parser)
+    return 0;
+  return parser->m_accounting.countBytesIndirect;
+}
+
+static void
+entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
+                          const char *action, int sourceLine) {
+  assert(! rootParser->m_parentParser);
+  if (rootParser->m_entity_stats.debugLevel < 1)
+    return;
+
+#  if defined(XML_UNICODE)
+  const char *const entityName = "[..]";
+#  else
+  const char *const entityName = entity->name;
+#  endif
+
+  fprintf(
+      stderr,
+      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
+      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
+      rootParser->m_entity_stats.currentDepth,
+      rootParser->m_entity_stats.maximumDepthSeen,
+      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
+      entity->is_param ? "%" : "&", entityName, action, entity->textLen,
+      sourceLine);
+}
+
+static void
+entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+  assert(! rootParser->m_parentParser);
+
+  rootParser->m_entity_stats.countEverOpened++;
+  rootParser->m_entity_stats.currentDepth++;
+  if (rootParser->m_entity_stats.currentDepth
+      > rootParser->m_entity_stats.maximumDepthSeen) {
+    rootParser->m_entity_stats.maximumDepthSeen++;
+  }
+
+  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
+}
+
+static void
+entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
+  assert(! rootParser->m_parentParser);
+
+  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
+  rootParser->m_entity_stats.currentDepth--;
+}
+
+static XML_Parser
+getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
+  XML_Parser rootParser = parser;
+  unsigned int stepsTakenUpwards = 0;
+  while (rootParser->m_parentParser) {
+    rootParser = rootParser->m_parentParser;
+    stepsTakenUpwards++;
+  }
+  assert(! rootParser->m_parentParser);
+  if (outLevelDiff != NULL) {
+    *outLevelDiff = stepsTakenUpwards;
+  }
+  return rootParser;
+}
+
+const char *
+unsignedCharToPrintable(unsigned char c) {
+  switch (c) {
+  case 0:
+    return "\\0";
+  case 1:
+    return "\\x1";
+  case 2:
+    return "\\x2";
+  case 3:
+    return "\\x3";
+  case 4:
+    return "\\x4";
+  case 5:
+    return "\\x5";
+  case 6:
+    return "\\x6";
+  case 7:
+    return "\\x7";
+  case 8:
+    return "\\x8";
+  case 9:
+    return "\\t";
+  case 10:
+    return "\\n";
+  case 11:
+    return "\\xB";
+  case 12:
+    return "\\xC";
+  case 13:
+    return "\\r";
+  case 14:
+    return "\\xE";
+  case 15:
+    return "\\xF";
+  case 16:
+    return "\\x10";
+  case 17:
+    return "\\x11";
+  case 18:
+    return "\\x12";
+  case 19:
+    return "\\x13";
+  case 20:
+    return "\\x14";
+  case 21:
+    return "\\x15";
+  case 22:
+    return "\\x16";
+  case 23:
+    return "\\x17";
+  case 24:
+    return "\\x18";
+  case 25:
+    return "\\x19";
+  case 26:
+    return "\\x1A";
+  case 27:
+    return "\\x1B";
+  case 28:
+    return "\\x1C";
+  case 29:
+    return "\\x1D";
+  case 30:
+    return "\\x1E";
+  case 31:
+    return "\\x1F";
+  case 32:
+    return " ";
+  case 33:
+    return "!";
+  case 34:
+    return "\\\"";
+  case 35:
+    return "#";
+  case 36:
+    return "$";
+  case 37:
+    return "%";
+  case 38:
+    return "&";
+  case 39:
+    return "'";
+  case 40:
+    return "(";
+  case 41:
+    return ")";
+  case 42:
+    return "*";
+  case 43:
+    return "+";
+  case 44:
+    return ",";
+  case 45:
+    return "-";
+  case 46:
+    return ".";
+  case 47:
+    return "/";
+  case 48:
+    return "0";
+  case 49:
+    return "1";
+  case 50:
+    return "2";
+  case 51:
+    return "3";
+  case 52:
+    return "4";
+  case 53:
+    return "5";
+  case 54:
+    return "6";
+  case 55:
+    return "7";
+  case 56:
+    return "8";
+  case 57:
+    return "9";
+  case 58:
+    return ":";
+  case 59:
+    return ";";
+  case 60:
+    return "<";
+  case 61:
+    return "=";
+  case 62:
+    return ">";
+  case 63:
+    return "?";
+  case 64:
+    return "@";
+  case 65:
+    return "A";
+  case 66:
+    return "B";
+  case 67:
+    return "C";
+  case 68:
+    return "D";
+  case 69:
+    return "E";
+  case 70:
+    return "F";
+  case 71:
+    return "G";
+  case 72:
+    return "H";
+  case 73:
+    return "I";
+  case 74:
+    return "J";
+  case 75:
+    return "K";
+  case 76:
+    return "L";
+  case 77:
+    return "M";
+  case 78:
+    return "N";
+  case 79:
+    return "O";
+  case 80:
+    return "P";
+  case 81:
+    return "Q";
+  case 82:
+    return "R";
+  case 83:
+    return "S";
+  case 84:
+    return "T";
+  case 85:
+    return "U";
+  case 86:
+    return "V";
+  case 87:
+    return "W";
+  case 88:
+    return "X";
+  case 89:
+    return "Y";
+  case 90:
+    return "Z";
+  case 91:
+    return "[";
+  case 92:
+    return "\\\\";
+  case 93:
+    return "]";
+  case 94:
+    return "^";
+  case 95:
+    return "_";
+  case 96:
+    return "`";
+  case 97:
+    return "a";
+  case 98:
+    return "b";
+  case 99:
+    return "c";
+  case 100:
+    return "d";
+  case 101:
+    return "e";
+  case 102:
+    return "f";
+  case 103:
+    return "g";
+  case 104:
+    return "h";
+  case 105:
+    return "i";
+  case 106:
+    return "j";
+  case 107:
+    return "k";
+  case 108:
+    return "l";
+  case 109:
+    return "m";
+  case 110:
+    return "n";
+  case 111:
+    return "o";
+  case 112:
+    return "p";
+  case 113:
+    return "q";
+  case 114:
+    return "r";
+  case 115:
+    return "s";
+  case 116:
+    return "t";
+  case 117:
+    return "u";
+  case 118:
+    return "v";
+  case 119:
+    return "w";
+  case 120:
+    return "x";
+  case 121:
+    return "y";
+  case 122:
+    return "z";
+  case 123:
+    return "{";
+  case 124:
+    return "|";
+  case 125:
+    return "}";
+  case 126:
+    return "~";
+  case 127:
+    return "\\x7F";
+  case 128:
+    return "\\x80";
+  case 129:
+    return "\\x81";
+  case 130:
+    return "\\x82";
+  case 131:
+    return "\\x83";
+  case 132:
+    return "\\x84";
+  case 133:
+    return "\\x85";
+  case 134:
+    return "\\x86";
+  case 135:
+    return "\\x87";
+  case 136:
+    return "\\x88";
+  case 137:
+    return "\\x89";
+  case 138:
+    return "\\x8A";
+  case 139:
+    return "\\x8B";
+  case 140:
+    return "\\x8C";
+  case 141:
+    return "\\x8D";
+  case 142:
+    return "\\x8E";
+  case 143:
+    return "\\x8F";
+  case 144:
+    return "\\x90";
+  case 145:
+    return "\\x91";
+  case 146:
+    return "\\x92";
+  case 147:
+    return "\\x93";
+  case 148:
+    return "\\x94";
+  case 149:
+    return "\\x95";
+  case 150:
+    return "\\x96";
+  case 151:
+    return "\\x97";
+  case 152:
+    return "\\x98";
+  case 153:
+    return "\\x99";
+  case 154:
+    return "\\x9A";
+  case 155:
+    return "\\x9B";
+  case 156:
+    return "\\x9C";
+  case 157:
+    return "\\x9D";
+  case 158:
+    return "\\x9E";
+  case 159:
+    return "\\x9F";
+  case 160:
+    return "\\xA0";
+  case 161:
+    return "\\xA1";
+  case 162:
+    return "\\xA2";
+  case 163:
+    return "\\xA3";
+  case 164:
+    return "\\xA4";
+  case 165:
+    return "\\xA5";
+  case 166:
+    return "\\xA6";
+  case 167:
+    return "\\xA7";
+  case 168:
+    return "\\xA8";
+  case 169:
+    return "\\xA9";
+  case 170:
+    return "\\xAA";
+  case 171:
+    return "\\xAB";
+  case 172:
+    return "\\xAC";
+  case 173:
+    return "\\xAD";
+  case 174:
+    return "\\xAE";
+  case 175:
+    return "\\xAF";
+  case 176:
+    return "\\xB0";
+  case 177:
+    return "\\xB1";
+  case 178:
+    return "\\xB2";
+  case 179:
+    return "\\xB3";
+  case 180:
+    return "\\xB4";
+  case 181:
+    return "\\xB5";
+  case 182:
+    return "\\xB6";
+  case 183:
+    return "\\xB7";
+  case 184:
+    return "\\xB8";
+  case 185:
+    return "\\xB9";
+  case 186:
+    return "\\xBA";
+  case 187:
+    return "\\xBB";
+  case 188:
+    return "\\xBC";
+  case 189:
+    return "\\xBD";
+  case 190:
+    return "\\xBE";
+  case 191:
+    return "\\xBF";
+  case 192:
+    return "\\xC0";
+  case 193:
+    return "\\xC1";
+  case 194:
+    return "\\xC2";
+  case 195:
+    return "\\xC3";
+  case 196:
+    return "\\xC4";
+  case 197:
+    return "\\xC5";
+  case 198:
+    return "\\xC6";
+  case 199:
+    return "\\xC7";
+  case 200:
+    return "\\xC8";
+  case 201:
+    return "\\xC9";
+  case 202:
+    return "\\xCA";
+  case 203:
+    return "\\xCB";
+  case 204:
+    return "\\xCC";
+  case 205:
+    return "\\xCD";
+  case 206:
+    return "\\xCE";
+  case 207:
+    return "\\xCF";
+  case 208:
+    return "\\xD0";
+  case 209:
+    return "\\xD1";
+  case 210:
+    return "\\xD2";
+  case 211:
+    return "\\xD3";
+  case 212:
+    return "\\xD4";
+  case 213:
+    return "\\xD5";
+  case 214:
+    return "\\xD6";
+  case 215:
+    return "\\xD7";
+  case 216:
+    return "\\xD8";
+  case 217:
+    return "\\xD9";
+  case 218:
+    return "\\xDA";
+  case 219:
+    return "\\xDB";
+  case 220:
+    return "\\xDC";
+  case 221:
+    return "\\xDD";
+  case 222:
+    return "\\xDE";
+  case 223:
+    return "\\xDF";
+  case 224:
+    return "\\xE0";
+  case 225:
+    return "\\xE1";
+  case 226:
+    return "\\xE2";
+  case 227:
+    return "\\xE3";
+  case 228:
+    return "\\xE4";
+  case 229:
+    return "\\xE5";
+  case 230:
+    return "\\xE6";
+  case 231:
+    return "\\xE7";
+  case 232:
+    return "\\xE8";
+  case 233:
+    return "\\xE9";
+  case 234:
+    return "\\xEA";
+  case 235:
+    return "\\xEB";
+  case 236:
+    return "\\xEC";
+  case 237:
+    return "\\xED";
+  case 238:
+    return "\\xEE";
+  case 239:
+    return "\\xEF";
+  case 240:
+    return "\\xF0";
+  case 241:
+    return "\\xF1";
+  case 242:
+    return "\\xF2";
+  case 243:
+    return "\\xF3";
+  case 244:
+    return "\\xF4";
+  case 245:
+    return "\\xF5";
+  case 246:
+    return "\\xF6";
+  case 247:
+    return "\\xF7";
+  case 248:
+    return "\\xF8";
+  case 249:
+    return "\\xF9";
+  case 250:
+    return "\\xFA";
+  case 251:
+    return "\\xFB";
+  case 252:
+    return "\\xFC";
+  case 253:
+    return "\\xFD";
+  case 254:
+    return "\\xFE";
+  case 255:
+    return "\\xFF";
+  default:
+    assert(0); /* never gets here */
+    return "dead code";
+  }
+  assert(0); /* never gets here */
+}
+
+#endif /* XML_DTD */
+
+static unsigned long
+getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
+  const char *const valueOrNull = getenv(variableName);
+  if (valueOrNull == NULL) {
+    return defaultDebugLevel;
+  }
+  const char *const value = valueOrNull;
+
+  errno = 0;
+  char *afterValue = (char *)value;
+  unsigned long debugLevel = strtoul(value, &afterValue, 10);
+  if ((errno != 0) || (afterValue[0] != '\0')) {
+    errno = 0;
+    return defaultDebugLevel;
+  }
+
+  return debugLevel;
+}

+ 11 - 6
lib/xmlrole.c

@@ -7,7 +7,14 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Greg Stein <[email protected]>
+   Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
+   Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
+   Copyright (c) 2019      David Loffredo <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -34,11 +41,9 @@
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #  include "winconfig.h"
 #  include "winconfig.h"
-#else
-#  ifdef HAVE_EXPAT_CONFIG_H
-#    include <expat_config.h>
-#  endif
-#endif /* ndef _WIN32 */
+#endif
+
+#include <expat_config.h>
 
 
 #include "expat_external.h"
 #include "expat_external.h"
 #include "internal.h"
 #include "internal.h"

+ 4 - 1
lib/xmlrole.h

@@ -7,7 +7,10 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Karl Waclawek <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 25 - 17
lib/xmltok.c

@@ -7,7 +7,19 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2002      Greg Stein <[email protected]>
+   Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2016      Pascal Cuoq <[email protected]>
+   Copyright (c) 2016      Don Lewis <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
+   Copyright (c) 2017      Alexander Bluhm <[email protected]>
+   Copyright (c) 2017      Benbuck Nason <[email protected]>
+   Copyright (c) 2017      José Gutiérrez de la Concha <[email protected]>
+   Copyright (c) 2019      David Loffredo <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -32,23 +44,13 @@
 
 
 #include <stddef.h>
 #include <stddef.h>
 #include <string.h> /* memcpy */
 #include <string.h> /* memcpy */
-
-#if defined(_MSC_VER) && (_MSC_VER <= 1700)
-/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
-#  define bool int
-#  define false 0
-#  define true 1
-#else
-#  include <stdbool.h>
-#endif
+#include <stdbool.h>
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #  include "winconfig.h"
 #  include "winconfig.h"
-#else
-#  ifdef HAVE_EXPAT_CONFIG_H
-#    include <expat_config.h>
-#  endif
-#endif /* ndef _WIN32 */
+#endif
+
+#include <expat_config.h>
 
 
 #include "expat_external.h"
 #include "expat_external.h"
 #include "internal.h"
 #include "internal.h"
@@ -269,8 +271,14 @@ sb_byteToAscii(const ENCODING *enc, const char *p) {
 
 
 #define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p))
 #define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p))
 #define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p))
 #define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p))
-#define IS_INVALID_CHAR(enc, p, n)                                             \
-  (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#ifdef XML_MIN_SIZE
+#  define IS_INVALID_CHAR(enc, p, n)                                           \
+    (AS_NORMAL_ENCODING(enc)->isInvalid##n                                     \
+     && AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#else
+#  define IS_INVALID_CHAR(enc, p, n)                                           \
+    (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
+#endif
 
 
 #ifdef XML_MIN_SIZE
 #ifdef XML_MIN_SIZE
 #  define IS_NAME_CHAR_MINBPC(enc, p)                                          \
 #  define IS_NAME_CHAR_MINBPC(enc, p)                                          \

+ 5 - 1
lib/xmltok.h

@@ -7,7 +7,11 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2002-2005 Karl Waclawek <[email protected]>
+   Copyright (c) 2016-2017 Sebastian Pipping <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 11 - 3
lib/xmltok_impl.c

@@ -1,4 +1,4 @@
-/* This file is included!
+/* This file is included (from xmltok.c, 1-3 times depending on XML_MIN_SIZE)!
                             __  __            _
                             __  __            _
                          ___\ \/ /_ __   __ _| |_
                          ___\ \/ /_ __   __ _| |_
                         / _ \\  /| '_ \ / _` | __|
                         / _ \\  /| '_ \ / _` | __|
@@ -7,7 +7,15 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
+   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2017      Rhodri James <[email protected]>
+   Copyright (c) 2018      Benjamin Peterson <[email protected]>
+   Copyright (c) 2018      Anton Maklakov <[email protected]>
+   Copyright (c) 2019      David Loffredo <[email protected]>
+   Copyright (c) 2020      Boris Kolpackov <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -32,7 +40,7 @@
 
 
 #ifdef XML_TOK_IMPL_C
 #ifdef XML_TOK_IMPL_C
 
 
-#  ifndef IS_INVALID_CHAR
+#  ifndef IS_INVALID_CHAR // i.e. for UTF-16 and XML_MIN_SIZE not defined
 #    define IS_INVALID_CHAR(enc, ptr, n) (0)
 #    define IS_INVALID_CHAR(enc, ptr, n) (0)
 #  endif
 #  endif
 
 

+ 2 - 1
lib/xmltok_impl.h

@@ -7,7 +7,8 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2017-2019 Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining

+ 5 - 1
lib/xmltok_ns.c

@@ -7,7 +7,11 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
-   Copyright (c) 2000-2017 Expat development team
+   Copyright (c) 2000      Clark Cooper <[email protected]>
+   Copyright (c) 2002      Greg Stein <[email protected]>
+   Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
+   Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
+   Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:
 
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
    Permission is  hereby granted,  free of charge,  to any  person obtaining