Martin Prikryl 12 سال پیش
والد
کامیت
4dad4a32f0
100فایلهای تغییر یافته به همراه15332 افزوده شده و 945 حذف شده
  1. 1 1
      dotnet/properties/AssemblyInfo.cs
  2. 0 2
      libs/.gitignore
  3. 32 0
      libs/expat/lib/amigaconfig.h
  4. 92 0
      libs/expat/lib/ascii.h
  5. 36 0
      libs/expat/lib/asciitab.h
  6. 1047 0
      libs/expat/lib/expat.h
  7. 115 0
      libs/expat/lib/expat_external.h
  8. 37 0
      libs/expat/lib/iasciitab.h
  9. 73 0
      libs/expat/lib/internal.h
  10. 36 0
      libs/expat/lib/latin1tab.h
  11. 73 0
      libs/expat/lib/libexpat.def
  12. 242 0
      libs/expat/lib/libexpat.vcxproj
  13. 73 0
      libs/expat/lib/libexpatw.def
  14. 53 0
      libs/expat/lib/macconfig.h
  15. 150 0
      libs/expat/lib/nametab.h
  16. 37 0
      libs/expat/lib/utf8tab.h
  17. 32 0
      libs/expat/lib/winconfig.h
  18. 6403 0
      libs/expat/lib/xmlparse.c
  19. 1336 0
      libs/expat/lib/xmlrole.c
  20. 114 0
      libs/expat/lib/xmlrole.h
  21. 1651 0
      libs/expat/lib/xmltok.c
  22. 316 0
      libs/expat/lib/xmltok.h
  23. 1786 0
      libs/expat/lib/xmltok_impl.c
  24. 46 0
      libs/expat/lib/xmltok_impl.h
  25. 115 0
      libs/expat/lib/xmltok_ns.c
  26. 0 17
      libs/install/openssl/build_source.bat
  27. 0 234
      libs/install/openssl/cleanup.bat
  28. 0 14
      libs/install/openssl/fixasmalign.php
  29. 0 31
      libs/install/openssl/readme
  30. 0 6
      libs/install/openssl/readme_debug
  31. 1 1
      source/Console.cbproj
  32. 1 1
      source/DragExt.cbproj
  33. 2 2
      source/DragExt64.rc
  34. 8 0
      source/Putty.cbproj
  35. 9 3
      source/WinSCP.cbproj
  36. 10 5
      source/components/ThemePageControl.cpp
  37. 1 1
      source/components/ThemePageControl.h
  38. 6 1
      source/components/UnixDirView.cpp
  39. 36 30
      source/components/UnixDriveView.cpp
  40. 156 76
      source/core/Common.cpp
  41. 10 1
      source/core/Common.h
  42. 1 6
      source/core/Configuration.cpp
  43. 0 2
      source/core/Configuration.h
  44. 34 1
      source/core/CopyParam.cpp
  45. 6 0
      source/core/CopyParam.h
  46. 3 3
      source/core/Cryptography.cpp
  47. 22 5
      source/core/Exceptions.cpp
  48. 75 19
      source/core/Exceptions.h
  49. 12 8
      source/core/FileBuffer.cpp
  50. 12 10
      source/core/FileMasks.cpp
  51. 6 2
      source/core/FileMasks.h
  52. 1 0
      source/core/FileSystems.h
  53. 28 3
      source/core/FtpFileSystem.cpp
  54. 1 0
      source/core/FtpFileSystem.h
  55. 1 1
      source/core/Option.cpp
  56. 85 22
      source/core/PuttyIntf.cpp
  57. 4 1
      source/core/PuttyTools.h
  58. 2 3
      source/core/Queue.cpp
  59. 33 7
      source/core/RemoteFiles.cpp
  60. 4 1
      source/core/RemoteFiles.h
  61. 13 1
      source/core/ScpFileSystem.cpp
  62. 1 0
      source/core/ScpFileSystem.h
  63. 2 2
      source/core/Script.cpp
  64. 189 147
      source/core/SecureShell.cpp
  65. 4 6
      source/core/SecureShell.h
  66. 180 77
      source/core/SessionData.cpp
  67. 7 0
      source/core/SessionData.h
  68. 9 1
      source/core/SessionInfo.cpp
  69. 1 1
      source/core/SessionInfo.h
  70. 55 23
      source/core/SftpFileSystem.cpp
  71. 1 2
      source/core/SftpFileSystem.h
  72. 120 51
      source/core/Terminal.cpp
  73. 9 6
      source/core/Terminal.h
  74. 19 17
      source/core/WebDAVFileSystem.cpp
  75. 1 0
      source/core/WebDAVFileSystem.h
  76. 2 2
      source/dragext/DragExt.cpp
  77. 8 20
      source/filezilla/AsyncSocketEx.cpp
  78. 73 17
      source/filezilla/AsyncSslSocketLayer.cpp
  79. 2 0
      source/filezilla/AsyncSslSocketLayer.h
  80. 1 0
      source/filezilla/ControlSocket.h
  81. 10 0
      source/filezilla/FileZillaApi.cpp
  82. 1 0
      source/filezilla/FileZillaApi.h
  83. 14 11
      source/filezilla/FileZillaIntf.cpp
  84. 1 0
      source/filezilla/FileZillaIntf.h
  85. 8 4
      source/filezilla/FtpControlSocket.cpp
  86. 1 0
      source/filezilla/FtpControlSocket.h
  87. 1 1
      source/filezilla/FtpListResult.cpp
  88. 7 0
      source/filezilla/MainThread.cpp
  89. 1 0
      source/filezilla/MainThread.h
  90. 13 1
      source/filezilla/TransferSocket.cpp
  91. 2 0
      source/filezilla/stdafx.h
  92. 4 7
      source/forms/Authenticate.cpp
  93. 2 3
      source/forms/Authenticate.h
  94. 39 9
      source/forms/Console.dfm
  95. 2 0
      source/forms/Console.h
  96. 1 1
      source/forms/Copy.cpp
  97. 10 0
      source/forms/CopyParams.cpp
  98. 11 2
      source/forms/CopyParams.dfm
  99. 1 0
      source/forms/CopyParams.h
  100. 40 13
      source/forms/Custom.cpp

+ 1 - 1
dotnet/properties/AssemblyInfo.cs

@@ -21,7 +21,7 @@ using System.Runtime.InteropServices;
 
 [assembly: AssemblyVersion("1.1.4.0")]
 [assembly: AssemblyFileVersion("1.1.4.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.2.4.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.2.5.0")]
 
 [assembly: CLSCompliant(true)]
 

+ 0 - 2
libs/.gitignore

@@ -1,2 +0,0 @@
-lib
-openssl/openssl

+ 32 - 0
libs/expat/lib/amigaconfig.h

@@ -0,0 +1,32 @@
+#ifndef AMIGACONFIG_H
+#define AMIGACONFIG_H
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 4321
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+#undef HAVE_CHECK_H
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* whether byteorder is bigendian */
+#define WORDS_BIGENDIAN
+
+/* Define to specify how much context to retain around the current parse
+   point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS
+
+#endif  /* AMIGACONFIG_H */

+ 92 - 0
libs/expat/lib/ascii.h

@@ -0,0 +1,92 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#define ASCII_A 0x41
+#define ASCII_B 0x42
+#define ASCII_C 0x43
+#define ASCII_D 0x44
+#define ASCII_E 0x45
+#define ASCII_F 0x46
+#define ASCII_G 0x47
+#define ASCII_H 0x48
+#define ASCII_I 0x49
+#define ASCII_J 0x4A
+#define ASCII_K 0x4B
+#define ASCII_L 0x4C
+#define ASCII_M 0x4D
+#define ASCII_N 0x4E
+#define ASCII_O 0x4F
+#define ASCII_P 0x50
+#define ASCII_Q 0x51
+#define ASCII_R 0x52
+#define ASCII_S 0x53
+#define ASCII_T 0x54
+#define ASCII_U 0x55
+#define ASCII_V 0x56
+#define ASCII_W 0x57
+#define ASCII_X 0x58
+#define ASCII_Y 0x59
+#define ASCII_Z 0x5A
+
+#define ASCII_a 0x61
+#define ASCII_b 0x62
+#define ASCII_c 0x63
+#define ASCII_d 0x64
+#define ASCII_e 0x65
+#define ASCII_f 0x66
+#define ASCII_g 0x67
+#define ASCII_h 0x68
+#define ASCII_i 0x69
+#define ASCII_j 0x6A
+#define ASCII_k 0x6B
+#define ASCII_l 0x6C
+#define ASCII_m 0x6D
+#define ASCII_n 0x6E
+#define ASCII_o 0x6F
+#define ASCII_p 0x70
+#define ASCII_q 0x71
+#define ASCII_r 0x72
+#define ASCII_s 0x73
+#define ASCII_t 0x74
+#define ASCII_u 0x75
+#define ASCII_v 0x76
+#define ASCII_w 0x77
+#define ASCII_x 0x78
+#define ASCII_y 0x79
+#define ASCII_z 0x7A
+
+#define ASCII_0 0x30
+#define ASCII_1 0x31
+#define ASCII_2 0x32
+#define ASCII_3 0x33
+#define ASCII_4 0x34
+#define ASCII_5 0x35
+#define ASCII_6 0x36
+#define ASCII_7 0x37
+#define ASCII_8 0x38
+#define ASCII_9 0x39
+
+#define ASCII_TAB 0x09
+#define ASCII_SPACE 0x20
+#define ASCII_EXCL 0x21
+#define ASCII_QUOT 0x22
+#define ASCII_AMP 0x26
+#define ASCII_APOS 0x27
+#define ASCII_MINUS 0x2D
+#define ASCII_PERIOD 0x2E
+#define ASCII_COLON 0x3A
+#define ASCII_SEMI 0x3B
+#define ASCII_LT 0x3C
+#define ASCII_EQUALS 0x3D
+#define ASCII_GT 0x3E
+#define ASCII_LSQB 0x5B
+#define ASCII_RSQB 0x5D
+#define ASCII_UNDERSCORE 0x5F
+#define ASCII_LPAREN 0x28
+#define ASCII_RPAREN 0x29
+#define ASCII_FF 0x0C
+#define ASCII_SLASH 0x2F
+#define ASCII_HASH 0x23
+#define ASCII_PIPE 0x7C
+#define ASCII_COMMA 0x2C

+ 36 - 0
libs/expat/lib/asciitab.h

@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,

+ 1047 - 0
libs/expat/lib/expat.h

@@ -0,0 +1,1047 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_INCLUDED
+#define Expat_INCLUDED 1
+
+#ifdef __VMS
+/*      0        1         2         3      0        1         2         3
+        1234567890123456789012345678901     1234567890123456789012345678901 */
+#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
+#define XML_SetUnparsedEntityDeclHandler    XML_SetUnparsedEntDeclHandler
+#define XML_SetStartNamespaceDeclHandler    XML_SetStartNamespcDeclHandler
+#define XML_SetExternalEntityRefHandlerArg  XML_SetExternalEntRefHandlerArg
+#endif
+
+#include <stdlib.h>
+#include "expat_external.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct *XML_Parser;
+
+/* Should this be defined using stdbool.h when C99 is available? */
+typedef unsigned char XML_Bool;
+#define XML_TRUE   ((XML_Bool) 1)
+#define XML_FALSE  ((XML_Bool) 0)
+
+/* The XML_Status enum gives the possible return values for several
+   API functions.  The preprocessor #defines are included so this
+   stanza can be added to code that still needs to support older
+   versions of Expat 1.95.x:
+
+   #ifndef XML_STATUS_OK
+   #define XML_STATUS_OK    1
+   #define XML_STATUS_ERROR 0
+   #endif
+
+   Otherwise, the #define hackery is quite ugly and would have been
+   dropped.
+*/
+enum XML_Status {
+  XML_STATUS_ERROR = 0,
+#define XML_STATUS_ERROR XML_STATUS_ERROR
+  XML_STATUS_OK = 1,
+#define XML_STATUS_OK XML_STATUS_OK
+  XML_STATUS_SUSPENDED = 2
+#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
+};
+
+enum XML_Error {
+  XML_ERROR_NONE,
+  XML_ERROR_NO_MEMORY,
+  XML_ERROR_SYNTAX,
+  XML_ERROR_NO_ELEMENTS,
+  XML_ERROR_INVALID_TOKEN,
+  XML_ERROR_UNCLOSED_TOKEN,
+  XML_ERROR_PARTIAL_CHAR,
+  XML_ERROR_TAG_MISMATCH,
+  XML_ERROR_DUPLICATE_ATTRIBUTE,
+  XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
+  XML_ERROR_PARAM_ENTITY_REF,
+  XML_ERROR_UNDEFINED_ENTITY,
+  XML_ERROR_RECURSIVE_ENTITY_REF,
+  XML_ERROR_ASYNC_ENTITY,
+  XML_ERROR_BAD_CHAR_REF,
+  XML_ERROR_BINARY_ENTITY_REF,
+  XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
+  XML_ERROR_MISPLACED_XML_PI,
+  XML_ERROR_UNKNOWN_ENCODING,
+  XML_ERROR_INCORRECT_ENCODING,
+  XML_ERROR_UNCLOSED_CDATA_SECTION,
+  XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+  XML_ERROR_NOT_STANDALONE,
+  XML_ERROR_UNEXPECTED_STATE,
+  XML_ERROR_ENTITY_DECLARED_IN_PE,
+  XML_ERROR_FEATURE_REQUIRES_XML_DTD,
+  XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
+  /* Added in 1.95.7. */
+  XML_ERROR_UNBOUND_PREFIX,
+  /* Added in 1.95.8. */
+  XML_ERROR_UNDECLARING_PREFIX,
+  XML_ERROR_INCOMPLETE_PE,
+  XML_ERROR_XML_DECL,
+  XML_ERROR_TEXT_DECL,
+  XML_ERROR_PUBLICID,
+  XML_ERROR_SUSPENDED,
+  XML_ERROR_NOT_SUSPENDED,
+  XML_ERROR_ABORTED,
+  XML_ERROR_FINISHED,
+  XML_ERROR_SUSPEND_PE,
+  /* Added in 2.0. */
+  XML_ERROR_RESERVED_PREFIX_XML,
+  XML_ERROR_RESERVED_PREFIX_XMLNS,
+  XML_ERROR_RESERVED_NAMESPACE_URI
+};
+
+enum XML_Content_Type {
+  XML_CTYPE_EMPTY = 1,
+  XML_CTYPE_ANY,
+  XML_CTYPE_MIXED,
+  XML_CTYPE_NAME,
+  XML_CTYPE_CHOICE,
+  XML_CTYPE_SEQ
+};
+
+enum XML_Content_Quant {
+  XML_CQUANT_NONE,
+  XML_CQUANT_OPT,
+  XML_CQUANT_REP,
+  XML_CQUANT_PLUS
+};
+
+/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
+   XML_CQUANT_NONE, and the other fields will be zero or NULL.
+   If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
+   numchildren will contain number of elements that may be mixed in
+   and children point to an array of XML_Content cells that will be
+   all of XML_CTYPE_NAME type with no quantification.
+
+   If type == XML_CTYPE_NAME, then the name points to the name, and
+   the numchildren field will be zero and children will be NULL. The
+   quant fields indicates any quantifiers placed on the name.
+
+   CHOICE and SEQ will have name NULL, the number of children in
+   numchildren and children will point, recursively, to an array
+   of XML_Content cells.
+
+   The EMPTY, ANY, and MIXED types will only occur at top level.
+*/
+
+typedef struct XML_cp XML_Content;
+
+struct XML_cp {
+  enum XML_Content_Type         type;
+  enum XML_Content_Quant        quant;
+  XML_Char *                    name;
+  unsigned int                  numchildren;
+  XML_Content *                 children;
+};
+
+
+/* This is called for an element declaration. See above for
+   description of the model argument. It's the caller's responsibility
+   to free model when finished with it.
+*/
+typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
+                                                const XML_Char *name,
+                                                XML_Content *model);
+
+XMLPARSEAPI(void)
+XML_SetElementDeclHandler(XML_Parser parser,
+                          XML_ElementDeclHandler eldecl);
+
+/* The Attlist declaration handler is called for *each* attribute. So
+   a single Attlist declaration with multiple attributes declared will
+   generate multiple calls to this handler. The "default" parameter
+   may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
+   keyword. The "isrequired" parameter will be true and the default
+   value will be NULL in the case of "#REQUIRED". If "isrequired" is
+   true and default is non-NULL, then this is a "#FIXED" default.
+*/
+typedef void (XMLCALL *XML_AttlistDeclHandler) (
+                                    void            *userData,
+                                    const XML_Char  *elname,
+                                    const XML_Char  *attname,
+                                    const XML_Char  *att_type,
+                                    const XML_Char  *dflt,
+                                    int              isrequired);
+
+XMLPARSEAPI(void)
+XML_SetAttlistDeclHandler(XML_Parser parser,
+                          XML_AttlistDeclHandler attdecl);
+
+/* The XML declaration handler is called for *both* XML declarations
+   and text declarations. The way to distinguish is that the version
+   parameter will be NULL for text declarations. The encoding
+   parameter may be NULL for XML declarations. The standalone
+   parameter will be -1, 0, or 1 indicating respectively that there
+   was no standalone parameter in the declaration, that it was given
+   as no, or that it was given as yes.
+*/
+typedef void (XMLCALL *XML_XmlDeclHandler) (void           *userData,
+                                            const XML_Char *version,
+                                            const XML_Char *encoding,
+                                            int             standalone);
+
+XMLPARSEAPI(void)
+XML_SetXmlDeclHandler(XML_Parser parser,
+                      XML_XmlDeclHandler xmldecl);
+
+
+typedef struct {
+  void *(*malloc_fcn)(size_t size);
+  void *(*realloc_fcn)(void *ptr, size_t size);
+  void (*free_fcn)(void *ptr);
+} XML_Memory_Handling_Suite;
+
+/* Constructs a new parser; encoding is the encoding specified by the
+   external protocol or NULL if there is none specified.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate(const XML_Char *encoding);
+
+/* Constructs a new parser and namespace processor.  Element type
+   names and attribute names that belong to a namespace will be
+   expanded; unprefixed attribute names are never expanded; unprefixed
+   element type names are expanded only if there is a default
+   namespace. The expanded name is the concatenation of the namespace
+   URI, the namespace separator character, and the local part of the
+   name.  If the namespace separator is '\0' then the namespace URI
+   and the local part will be concatenated without any separator.
+   It is a programming error to use the separator '\0' with namespace
+   triplets (see XML_SetReturnNSTriplet).
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
+
+
+/* Constructs a new parser using the memory management suite referred to
+   by memsuite. If memsuite is NULL, then use the standard library memory
+   suite. If namespaceSeparator is non-NULL it creates a parser with
+   namespace processing as described above. The character pointed at
+   will serve as the namespace separator.
+
+   All further memory operations used for the created parser will come from
+   the given suite.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate_MM(const XML_Char *encoding,
+                    const XML_Memory_Handling_Suite *memsuite,
+                    const XML_Char *namespaceSeparator);
+
+/* Prepare a parser object to be re-used.  This is particularly
+   valuable when memory allocation overhead is disproportionatly high,
+   such as when a large number of small documnents need to be parsed.
+   All handlers are cleared from the parser, except for the
+   unknownEncodingHandler. The parser's external state is re-initialized
+   except for the values of ns and ns_triplets.
+
+   Added in Expat 1.95.3.
+*/
+XMLPARSEAPI(XML_Bool)
+XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
+
+/* atts is array of name/value pairs, terminated by 0;
+   names and values are 0 terminated.
+*/
+typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
+                                                 const XML_Char *name,
+                                                 const XML_Char **atts);
+
+typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
+                                               const XML_Char *name);
+
+
+/* s is not 0 terminated. */
+typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
+                                                  const XML_Char *s,
+                                                  int len);
+
+/* target and data are 0 terminated */
+typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
+                                                void *userData,
+                                                const XML_Char *target,
+                                                const XML_Char *data);
+
+/* data is 0 terminated */
+typedef void (XMLCALL *XML_CommentHandler) (void *userData,
+                                            const XML_Char *data);
+
+typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
+typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
+
+/* This is called for any characters in the XML document for which
+   there is no applicable handler.  This includes both characters that
+   are part of markup which is of a kind that is not reported
+   (comments, markup declarations), or characters that are part of a
+   construct which could be reported but for which no handler has been
+   supplied. The characters are passed exactly as they were in the XML
+   document except that they will be encoded in UTF-8 or UTF-16.
+   Line boundaries are not normalized. Note that a byte order mark
+   character is not passed to the default handler. There are no
+   guarantees about how characters are divided between calls to the
+   default handler: for example, a comment might be split between
+   multiple calls.
+*/
+typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
+                                            const XML_Char *s,
+                                            int len);
+
+/* This is called for the start of the DOCTYPE declaration, before
+   any DTD or internal subset is parsed.
+*/
+typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
+                                            void *userData,
+                                            const XML_Char *doctypeName,
+                                            const XML_Char *sysid,
+                                            const XML_Char *pubid,
+                                            int has_internal_subset);
+
+/* This is called for the start of the DOCTYPE declaration when the
+   closing > is encountered, but after processing any external
+   subset.
+*/
+typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+
+/* This is called for entity declarations. The is_parameter_entity
+   argument will be non-zero if the entity is a parameter entity, zero
+   otherwise.
+
+   For internal entities (<!ENTITY foo "bar">), value will
+   be non-NULL and systemId, publicID, and notationName will be NULL.
+   The value string is NOT nul-terminated; the length is provided in
+   the value_length argument. Since it is legal to have zero-length
+   values, do not use this argument to test for internal entities.
+
+   For external entities, value will be NULL and systemId will be
+   non-NULL. The publicId argument will be NULL unless a public
+   identifier was provided. The notationName argument will have a
+   non-NULL value only for unparsed entity declarations.
+
+   Note that is_parameter_entity can't be changed to XML_Bool, since
+   that would break binary compatibility.
+*/
+typedef void (XMLCALL *XML_EntityDeclHandler) (
+                              void *userData,
+                              const XML_Char *entityName,
+                              int is_parameter_entity,
+                              const XML_Char *value,
+                              int value_length,
+                              const XML_Char *base,
+                              const XML_Char *systemId,
+                              const XML_Char *publicId,
+                              const XML_Char *notationName);
+
+XMLPARSEAPI(void)
+XML_SetEntityDeclHandler(XML_Parser parser,
+                         XML_EntityDeclHandler handler);
+
+/* OBSOLETE -- OBSOLETE -- OBSOLETE
+   This handler has been superceded by the EntityDeclHandler above.
+   It is provided here for backward compatibility.
+
+   This is called for a declaration of an unparsed (NDATA) entity.
+   The base argument is whatever was set by XML_SetBase. The
+   entityName, systemId and notationName arguments will never be
+   NULL. The other arguments may be.
+*/
+typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
+                                    void *userData,
+                                    const XML_Char *entityName,
+                                    const XML_Char *base,
+                                    const XML_Char *systemId,
+                                    const XML_Char *publicId,
+                                    const XML_Char *notationName);
+
+/* This is called for a declaration of notation.  The base argument is
+   whatever was set by XML_SetBase. The notationName will never be
+   NULL.  The other arguments can be.
+*/
+typedef void (XMLCALL *XML_NotationDeclHandler) (
+                                    void *userData,
+                                    const XML_Char *notationName,
+                                    const XML_Char *base,
+                                    const XML_Char *systemId,
+                                    const XML_Char *publicId);
+
+/* When namespace processing is enabled, these are called once for
+   each namespace declaration. The call to the start and end element
+   handlers occur between the calls to the start and end namespace
+   declaration handlers. For an xmlns attribute, prefix will be
+   NULL.  For an xmlns="" attribute, uri will be NULL.
+*/
+typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
+                                    void *userData,
+                                    const XML_Char *prefix,
+                                    const XML_Char *uri);
+
+typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
+                                    void *userData,
+                                    const XML_Char *prefix);
+
+/* This is called if the document is not standalone, that is, it has an
+   external subset or a reference to a parameter entity, but does not
+   have standalone="yes". If this handler returns XML_STATUS_ERROR,
+   then processing will not continue, and the parser will return a
+   XML_ERROR_NOT_STANDALONE error.
+   If parameter entity parsing is enabled, then in addition to the
+   conditions above this handler will only be called if the referenced
+   entity was actually read.
+*/
+typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
+
+/* This is called for a reference to an external parsed general
+   entity.  The referenced entity is not automatically parsed.  The
+   application can parse it immediately or later using
+   XML_ExternalEntityParserCreate.
+
+   The parser argument is the parser parsing the entity containing the
+   reference; it can be passed as the parser argument to
+   XML_ExternalEntityParserCreate.  The systemId argument is the
+   system identifier as specified in the entity declaration; it will
+   not be NULL.
+
+   The base argument is the system identifier that should be used as
+   the base for resolving systemId if systemId was relative; this is
+   set by XML_SetBase; it may be NULL.
+
+   The publicId argument is the public identifier as specified in the
+   entity declaration, or NULL if none was specified; the whitespace
+   in the public identifier will have been normalized as required by
+   the XML spec.
+
+   The context argument specifies the parsing context in the format
+   expected by the context argument to XML_ExternalEntityParserCreate;
+   context is valid only until the handler returns, so if the
+   referenced entity is to be parsed later, it must be copied.
+   context is NULL only when the entity is a parameter entity.
+
+   The handler should return XML_STATUS_ERROR if processing should not
+   continue because of a fatal error in the handling of the external
+   entity.  In this case the calling parser will return an
+   XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
+
+   Note that unlike other handlers the first argument is the parser,
+   not userData.
+*/
+typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
+                                    XML_Parser parser,
+                                    const XML_Char *context,
+                                    const XML_Char *base,
+                                    const XML_Char *systemId,
+                                    const XML_Char *publicId);
+
+/* This is called in two situations:
+   1) An entity reference is encountered for which no declaration
+      has been read *and* this is not an error.
+   2) An internal entity reference is read, but not expanded, because
+      XML_SetDefaultHandler has been called.
+   Note: skipped parameter entities in declarations and skipped general
+         entities in attribute values cannot be reported, because
+         the event would be out of sync with the reporting of the
+         declarations or attribute values
+*/
+typedef void (XMLCALL *XML_SkippedEntityHandler) (
+                                    void *userData,
+                                    const XML_Char *entityName,
+                                    int is_parameter_entity);
+
+/* This structure is filled in by the XML_UnknownEncodingHandler to
+   provide information to the parser about encodings that are unknown
+   to the parser.
+
+   The map[b] member gives information about byte sequences whose
+   first byte is b.
+
+   If map[b] is c where c is >= 0, then b by itself encodes the
+   Unicode scalar value c.
+
+   If map[b] is -1, then the byte sequence is malformed.
+
+   If map[b] is -n, where n >= 2, then b is the first byte of an
+   n-byte sequence that encodes a single Unicode scalar value.
+
+   The data member will be passed as the first argument to the convert
+   function.
+
+   The convert function is used to convert multibyte sequences; s will
+   point to a n-byte sequence where map[(unsigned char)*s] == -n.  The
+   convert function must return the Unicode scalar value represented
+   by this byte sequence or -1 if the byte sequence is malformed.
+
+   The convert function may be NULL if the encoding is a single-byte
+   encoding, that is if map[b] >= -1 for all bytes b.
+
+   When the parser is finished with the encoding, then if release is
+   not NULL, it will call release passing it the data member; once
+   release has been called, the convert function will not be called
+   again.
+
+   Expat places certain restrictions on the encodings that are supported
+   using this mechanism.
+
+   1. Every ASCII character that can appear in a well-formed XML document,
+      other than the characters
+
+      $@\^`{}~
+
+      must be represented by a single byte, and that byte must be the
+      same byte that represents that character in ASCII.
+
+   2. No character may require more than 4 bytes to encode.
+
+   3. All characters encoded must have Unicode scalar values <=
+      0xFFFF, (i.e., characters that would be encoded by surrogates in
+      UTF-16 are  not allowed).  Note that this restriction doesn't
+      apply to the built-in support for UTF-8 and UTF-16.
+
+   4. No Unicode character may be encoded by more than one distinct
+      sequence of bytes.
+*/
+typedef struct {
+  int map[256];
+  void *data;
+  int (XMLCALL *convert)(void *data, const char *s);
+  void (XMLCALL *release)(void *data);
+} XML_Encoding;
+
+/* This is called for an encoding that is unknown to the parser.
+
+   The encodingHandlerData argument is that which was passed as the
+   second argument to XML_SetUnknownEncodingHandler.
+
+   The name argument gives the name of the encoding as specified in
+   the encoding declaration.
+
+   If the callback can provide information about the encoding, it must
+   fill in the XML_Encoding structure, and return XML_STATUS_OK.
+   Otherwise it must return XML_STATUS_ERROR.
+
+   If info does not describe a suitable encoding, then the parser will
+   return an XML_UNKNOWN_ENCODING error.
+*/
+typedef int (XMLCALL *XML_UnknownEncodingHandler) (
+                                    void *encodingHandlerData,
+                                    const XML_Char *name,
+                                    XML_Encoding *info);
+
+XMLPARSEAPI(void)
+XML_SetElementHandler(XML_Parser parser,
+                      XML_StartElementHandler start,
+                      XML_EndElementHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartElementHandler(XML_Parser parser,
+                           XML_StartElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetEndElementHandler(XML_Parser parser,
+                         XML_EndElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCharacterDataHandler(XML_Parser parser,
+                            XML_CharacterDataHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+                                    XML_ProcessingInstructionHandler handler);
+XMLPARSEAPI(void)
+XML_SetCommentHandler(XML_Parser parser,
+                      XML_CommentHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCdataSectionHandler(XML_Parser parser,
+                           XML_StartCdataSectionHandler start,
+                           XML_EndCdataSectionHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+                                XML_StartCdataSectionHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+                              XML_EndCdataSectionHandler end);
+
+/* This sets the default handler and also inhibits expansion of
+   internal entities. These entity references will be passed to the
+   default handler, or to the skipped entity handler, if one is set.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandler(XML_Parser parser,
+                      XML_DefaultHandler handler);
+
+/* This sets the default handler but does not inhibit expansion of
+   internal entities.  The entity reference will not be passed to the
+   default handler.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+                            XML_DefaultHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+                          XML_StartDoctypeDeclHandler start,
+                          XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+                               XML_StartDoctypeDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+                             XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+                                 XML_UnparsedEntityDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNotationDeclHandler(XML_Parser parser,
+                           XML_NotationDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+                            XML_StartNamespaceDeclHandler start,
+                            XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+                                 XML_StartNamespaceDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+                               XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetNotStandaloneHandler(XML_Parser parser,
+                            XML_NotStandaloneHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+                                XML_ExternalEntityRefHandler handler);
+
+/* If a non-NULL value for arg is specified here, then it will be
+   passed as the first argument to the external entity ref handler
+   instead of the parser object.
+*/
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
+                                   void *arg);
+
+XMLPARSEAPI(void)
+XML_SetSkippedEntityHandler(XML_Parser parser,
+                            XML_SkippedEntityHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+                              XML_UnknownEncodingHandler handler,
+                              void *encodingHandlerData);
+
+/* This can be called within a handler for a start element, end
+   element, processing instruction or character data.  It causes the
+   corresponding markup to be passed to the default handler.
+*/
+XMLPARSEAPI(void)
+XML_DefaultCurrent(XML_Parser parser);
+
+/* If do_nst is non-zero, and namespace processing is in effect, and
+   a name has a prefix (i.e. an explicit namespace qualifier) then
+   that name is returned as a triplet in a single string separated by
+   the separator character specified when the parser was created: URI
+   + sep + local_name + sep + prefix.
+
+   If do_nst is zero, then namespace information is returned in the
+   default manner (URI + sep + local_name) whether or not the name
+   has a prefix.
+
+   Note: Calling XML_SetReturnNSTriplet after XML_Parse or
+     XML_ParseBuffer has no effect.
+*/
+
+XMLPARSEAPI(void)
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
+
+/* This value is passed as the userData argument to callbacks. */
+XMLPARSEAPI(void)
+XML_SetUserData(XML_Parser parser, void *userData);
+
+/* Returns the last value set by XML_SetUserData or NULL. */
+#define XML_GetUserData(parser) (*(void **)(parser))
+
+/* This is equivalent to supplying an encoding argument to
+   XML_ParserCreate. On success XML_SetEncoding returns non-zero,
+   zero otherwise.
+   Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
+     has no effect and returns XML_STATUS_ERROR.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
+
+/* If this function is called, then the parser will be passed as the
+   first argument to callbacks instead of userData.  The userData will
+   still be accessible using XML_GetUserData.
+*/
+XMLPARSEAPI(void)
+XML_UseParserAsHandlerArg(XML_Parser parser);
+
+/* If useDTD == XML_TRUE is passed to this function, then the parser
+   will assume that there is an external subset, even if none is
+   specified in the document. In such a case the parser will call the
+   externalEntityRefHandler with a value of NULL for the systemId
+   argument (the publicId and context arguments will be NULL as well).
+   Note: For the purpose of checking WFC: Entity Declared, passing
+     useDTD == XML_TRUE will make the parser behave as if the document
+     had a DTD with an external subset.
+   Note: If this function is called, then this must be done before
+     the first call to XML_Parse or XML_ParseBuffer, since it will
+     have no effect after that.  Returns
+     XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
+   Note: If the document does not have a DOCTYPE declaration at all,
+     then startDoctypeDeclHandler and endDoctypeDeclHandler will not
+     be called, despite an external subset being parsed.
+   Note: If XML_DTD is not defined when Expat is compiled, returns
+     XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
+
+
+/* Sets the base to be used for resolving relative URIs in system
+   identifiers in declarations.  Resolving relative identifiers is
+   left to the application: this value will be passed through as the
+   base argument to the XML_ExternalEntityRefHandler,
+   XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
+   argument will be copied.  Returns XML_STATUS_ERROR if out of memory,
+   XML_STATUS_OK otherwise.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetBase(XML_Parser parser, const XML_Char *base);
+
+XMLPARSEAPI(const XML_Char *)
+XML_GetBase(XML_Parser parser);
+
+/* Returns the number of the attribute/value pairs passed in last call
+   to the XML_StartElementHandler that were specified in the start-tag
+   rather than defaulted. Each attribute/value pair counts as 2; thus
+   this correspondds to an index into the atts array passed to the
+   XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetSpecifiedAttributeCount(XML_Parser parser);
+
+/* Returns the index of the ID attribute passed in the last call to
+   XML_StartElementHandler, or -1 if there is no ID attribute.  Each
+   attribute/value pair counts as 2; thus this correspondds to an
+   index into the atts array passed to the XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetIdAttributeIndex(XML_Parser parser);
+
+#ifdef XML_ATTR_INFO
+/* Source file byte offsets for the start and end of attribute names and values.
+   The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
+   file an attribute value of "blah" will yield:
+   info->valueEnd - info->valueStart = 4 bytes.
+*/
+typedef struct {
+  XML_Index  nameStart;  /* Offset to beginning of the attribute name. */
+  XML_Index  nameEnd;    /* Offset after the attribute name's last byte. */
+  XML_Index  valueStart; /* Offset to beginning of the attribute value. */
+  XML_Index  valueEnd;   /* Offset after the attribute value's last byte. */
+} XML_AttrInfo;
+
+/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
+   passed in last call to the XML_StartElementHandler that were specified
+   in the start-tag rather than defaulted. Each attribute/value pair counts
+   as 1; thus the number of entries in the array is
+   XML_GetSpecifiedAttributeCount(parser) / 2.
+*/
+XMLPARSEAPI(const XML_AttrInfo *)
+XML_GetAttributeInfo(XML_Parser parser);
+#endif
+
+/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
+   detected.  The last call to XML_Parse must have isFinal true; len
+   may be zero for this call (or any other).
+
+   Though the return values for these functions has always been
+   described as a Boolean value, the implementation, at least for the
+   1.95.x series, has always returned exactly one of the XML_Status
+   values.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
+
+XMLPARSEAPI(void *)
+XML_GetBuffer(XML_Parser parser, int len);
+
+XMLPARSEAPI(enum XML_Status)
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
+
+/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
+   Must be called from within a call-back handler, except when aborting
+   (resumable = 0) an already suspended parser. Some call-backs may
+   still follow because they would otherwise get lost. Examples:
+   - endElementHandler() for empty elements when stopped in
+     startElementHandler(), 
+   - endNameSpaceDeclHandler() when stopped in endElementHandler(), 
+   and possibly others.
+
+   Can be called from most handlers, including DTD related call-backs,
+   except when parsing an external parameter entity and resumable != 0.
+   Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
+   Possible error codes: 
+   - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
+   - XML_ERROR_FINISHED: when the parser has already finished.
+   - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
+
+   When resumable != 0 (true) then parsing is suspended, that is, 
+   XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. 
+   Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
+   return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
+
+   *Note*:
+   This will be applied to the current parser instance only, that is, if
+   there is a parent parser then it will continue parsing when the
+   externalEntityRefHandler() returns. It is up to the implementation of
+   the externalEntityRefHandler() to call XML_StopParser() on the parent
+   parser (recursively), if one wants to stop parsing altogether.
+
+   When suspended, parsing can be resumed by calling XML_ResumeParser(). 
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_StopParser(XML_Parser parser, XML_Bool resumable);
+
+/* Resumes parsing after it has been suspended with XML_StopParser().
+   Must not be called from within a handler call-back. Returns same
+   status codes as XML_Parse() or XML_ParseBuffer().
+   Additional error code XML_ERROR_NOT_SUSPENDED possible.   
+
+   *Note*:
+   This must be called on the most deeply nested child parser instance
+   first, and on its parent parser only after the child parser has finished,
+   to be applied recursively until the document entity's parser is restarted.
+   That is, the parent parser will not resume by itself and it is up to the
+   application to call XML_ResumeParser() on it at the appropriate moment.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_ResumeParser(XML_Parser parser);
+
+enum XML_Parsing {
+  XML_INITIALIZED,
+  XML_PARSING,
+  XML_FINISHED,
+  XML_SUSPENDED
+};
+
+typedef struct {
+  enum XML_Parsing parsing;
+  XML_Bool finalBuffer;
+} XML_ParsingStatus;
+
+/* Returns status of parser with respect to being initialized, parsing,
+   finished, or suspended and processing the final buffer.
+   XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
+   XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
+*/
+XMLPARSEAPI(void)
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
+
+/* Creates an XML_Parser object that can parse an external general
+   entity; context is a '\0'-terminated string specifying the parse
+   context; encoding is a '\0'-terminated string giving the name of
+   the externally specified encoding, or NULL if there is no
+   externally specified encoding.  The context string consists of a
+   sequence of tokens separated by formfeeds (\f); a token consisting
+   of a name specifies that the general entity of the name is open; a
+   token of the form prefix=uri specifies the namespace for a
+   particular prefix; a token of the form =uri specifies the default
+   namespace.  This can be called at any point after the first call to
+   an ExternalEntityRefHandler so longer as the parser has not yet
+   been freed.  The new parser is completely independent and may
+   safely be used in a separate thread.  The handlers and userData are
+   initialized from the parser argument.  Returns NULL if out of memory.
+   Otherwise returns a new XML_Parser object.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ExternalEntityParserCreate(XML_Parser parser,
+                               const XML_Char *context,
+                               const XML_Char *encoding);
+
+enum XML_ParamEntityParsing {
+  XML_PARAM_ENTITY_PARSING_NEVER,
+  XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
+  XML_PARAM_ENTITY_PARSING_ALWAYS
+};
+
+/* Controls parsing of parameter entities (including the external DTD
+   subset). If parsing of parameter entities is enabled, then
+   references to external parameter entities (including the external
+   DTD subset) will be passed to the handler set with
+   XML_SetExternalEntityRefHandler.  The context passed will be 0.
+
+   Unlike external general entities, external parameter entities can
+   only be parsed synchronously.  If the external parameter entity is
+   to be parsed, it must be parsed during the call to the external
+   entity ref handler: the complete sequence of
+   XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
+   XML_ParserFree calls must be made during this call.  After
+   XML_ExternalEntityParserCreate has been called to create the parser
+   for the external parameter entity (context must be 0 for this
+   call), it is illegal to make any calls on the old parser until
+   XML_ParserFree has been called on the newly created parser.
+   If the library has been compiled without support for parameter
+   entity parsing (ie without XML_DTD being defined), then
+   XML_SetParamEntityParsing will return 0 if parsing of parameter
+   entities is requested; otherwise it will return non-zero.
+   Note: If XML_SetParamEntityParsing is called after XML_Parse or
+      XML_ParseBuffer, then it has no effect and will always return 0.
+*/
+XMLPARSEAPI(int)
+XML_SetParamEntityParsing(XML_Parser parser,
+                          enum XML_ParamEntityParsing parsing);
+
+/* Sets the hash salt to use for internal hash calculations.
+   Helps in preventing DoS attacks based on predicting hash
+   function behavior. This must be called before parsing is started.
+   Returns 1 if successful, 0 when called after parsing has started.
+*/
+XMLPARSEAPI(int)
+XML_SetHashSalt(XML_Parser parser,
+                unsigned long hash_salt);
+
+/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
+   XML_GetErrorCode returns information about the error.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_GetErrorCode(XML_Parser parser);
+
+/* These functions return information about the current parse
+   location.  They may be called from any callback called to report
+   some parse event; in this case the location is the location of the
+   first of the sequence of characters that generated the event.  When
+   called from callbacks generated by declarations in the document
+   prologue, the location identified isn't as neatly defined, but will
+   be within the relevant markup.  When called outside of the callback
+   functions, the position indicated will be just past the last parse
+   event (regardless of whether there was an associated callback).
+   
+   They may also be called after returning from a call to XML_Parse
+   or XML_ParseBuffer.  If the return value is XML_STATUS_ERROR then
+   the location is the location of the character at which the error
+   was detected; otherwise the location is the location of the last
+   parse event, as described above.
+*/
+XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
+
+/* Return the number of bytes in the current event.
+   Returns 0 if the event is in an internal entity.
+*/
+XMLPARSEAPI(int)
+XML_GetCurrentByteCount(XML_Parser parser);
+
+/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+   the integer pointed to by offset to the offset within this buffer
+   of the current parse position, and sets the integer pointed to by size
+   to the size of this buffer (the number of input bytes). Otherwise
+   returns a NULL pointer. Also returns a NULL pointer if a parse isn't
+   active.
+
+   NOTE: The character pointer returned should not be used outside
+   the handler that makes the call.
+*/
+XMLPARSEAPI(const char *)
+XML_GetInputContext(XML_Parser parser,
+                    int *offset,
+                    int *size);
+
+/* For backwards compatibility with previous versions. */
+#define XML_GetErrorLineNumber   XML_GetCurrentLineNumber
+#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+#define XML_GetErrorByteIndex    XML_GetCurrentByteIndex
+
+/* Frees the content model passed to the element declaration handler */
+XMLPARSEAPI(void)
+XML_FreeContentModel(XML_Parser parser, XML_Content *model);
+
+/* Exposing the memory handling functions used in Expat */
+XMLPARSEAPI(void *)
+XML_MemMalloc(XML_Parser parser, size_t size);
+
+XMLPARSEAPI(void *)
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
+
+XMLPARSEAPI(void)
+XML_MemFree(XML_Parser parser, void *ptr);
+
+/* Frees memory used by the parser. */
+XMLPARSEAPI(void)
+XML_ParserFree(XML_Parser parser);
+
+/* Returns a string describing the error. */
+XMLPARSEAPI(const XML_LChar *)
+XML_ErrorString(enum XML_Error code);
+
+/* Return a string containing the version number of this expat */
+XMLPARSEAPI(const XML_LChar *)
+XML_ExpatVersion(void);
+
+typedef struct {
+  int major;
+  int minor;
+  int micro;
+} XML_Expat_Version;
+
+/* Return an XML_Expat_Version structure containing numeric version
+   number information for this version of expat.
+*/
+XMLPARSEAPI(XML_Expat_Version)
+XML_ExpatVersionInfo(void);
+
+/* Added in Expat 1.95.5. */
+enum XML_FeatureEnum {
+  XML_FEATURE_END = 0,
+  XML_FEATURE_UNICODE,
+  XML_FEATURE_UNICODE_WCHAR_T,
+  XML_FEATURE_DTD,
+  XML_FEATURE_CONTEXT_BYTES,
+  XML_FEATURE_MIN_SIZE,
+  XML_FEATURE_SIZEOF_XML_CHAR,
+  XML_FEATURE_SIZEOF_XML_LCHAR,
+  XML_FEATURE_NS,
+  XML_FEATURE_LARGE_SIZE,
+  XML_FEATURE_ATTR_INFO
+  /* Additional features must be added to the end of this enum. */
+};
+
+typedef struct {
+  enum XML_FeatureEnum  feature;
+  const XML_LChar       *name;
+  long int              value;
+} XML_Feature;
+
+XMLPARSEAPI(const XML_Feature *)
+XML_GetFeatureList(void);
+
+
+/* Expat follows the GNU/Linux convention of odd number minor version for
+   beta/development releases and even number minor version for stable
+   releases. Micro is bumped with each release, and set to 0 with each
+   change to major or minor version.
+*/
+#define XML_MAJOR_VERSION 2
+#define XML_MINOR_VERSION 1
+#define XML_MICRO_VERSION 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_INCLUDED */

+ 115 - 0
libs/expat/lib/expat_external.h

@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_External_INCLUDED
+#define Expat_External_INCLUDED 1
+
+/* External API definitions */
+
+#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
+#define XML_USE_MSC_EXTENSIONS 1
+#endif
+
+/* Expat tries very hard to make the API boundary very specifically
+   defined.  There are two macros defined to control this boundary;
+   each of these can be defined before including this header to
+   achieve some different behavior, but doing so it not recommended or
+   tested frequently.
+
+   XMLCALL    - The calling convention to use for all calls across the
+                "library boundary."  This will default to cdecl, and
+                try really hard to tell the compiler that's what we
+                want.
+
+   XMLIMPORT  - Whatever magic is needed to note that a function is
+                to be imported from a dynamically loaded library
+                (.dll, .so, or .sl, depending on your platform).
+
+   The XMLCALL macro was added in Expat 1.95.7.  The only one which is
+   expected to be directly useful in client code is XMLCALL.
+
+   Note that on at least some Unix versions, the Expat library must be
+   compiled with the cdecl calling convention as the default since
+   system headers may assume the cdecl convention.
+*/
+#ifndef XMLCALL
+#if defined(_MSC_VER)
+#define XMLCALL __cdecl
+#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
+#define XMLCALL __attribute__((cdecl))
+#else
+/* For any platform which uses this definition and supports more than
+   one calling convention, we need to extend this definition to
+   declare the convention used on that platform, if it's possible to
+   do so.
+
+   If this is the case for your platform, please file a bug report
+   with information on how to identify your platform via the C
+   pre-processor and how to specify the same calling convention as the
+   platform's malloc() implementation.
+*/
+#define XMLCALL
+#endif
+#endif  /* not defined XMLCALL */
+
+
+#if !defined(XML_STATIC) && !defined(XMLIMPORT)
+#ifndef XML_BUILDING_EXPAT
+/* using Expat from an application */
+
+#ifdef XML_USE_MSC_EXTENSIONS
+#define XMLIMPORT __declspec(dllimport)
+#endif
+
+#endif
+#endif  /* not defined XML_STATIC */
+
+
+/* If we didn't define it above, define it away: */
+#ifndef XMLIMPORT
+#define XMLIMPORT
+#endif
+
+
+#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_UNICODE
+#endif
+
+#ifdef XML_UNICODE     /* Information is UTF-16 encoded. */
+#ifdef XML_UNICODE_WCHAR_T
+typedef wchar_t XML_Char;
+typedef wchar_t XML_LChar;
+#else
+typedef unsigned short XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE_WCHAR_T */
+#else                  /* Information is UTF-8 encoded. */
+typedef char XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE */
+
+#ifdef XML_LARGE_SIZE  /* Use large integers for file/stream positions. */
+#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+typedef __int64 XML_Index; 
+typedef unsigned __int64 XML_Size;
+#else
+typedef long long XML_Index;
+typedef unsigned long long XML_Size;
+#endif
+#else
+typedef long XML_Index;
+typedef unsigned long XML_Size;
+#endif /* XML_LARGE_SIZE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_External_INCLUDED */

+ 37 - 0
libs/expat/lib/iasciitab.h

@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,

+ 73 - 0
libs/expat/lib/internal.h

@@ -0,0 +1,73 @@
+/* internal.h
+
+   Internal definitions used by Expat.  This is not needed to compile
+   client code.
+
+   The following calling convention macros are defined for frequently
+   called functions:
+
+   FASTCALL    - Used for those internal functions that have a simple
+                 body and a low number of arguments and local variables.
+
+   PTRCALL     - Used for functions called though function pointers.
+
+   PTRFASTCALL - Like PTRCALL, but for low number of arguments.
+
+   inline      - Used for selected internal functions for which inlining
+                 may improve performance on some platforms.
+
+   Note: Use of these macros is based on judgement, not hard rules,
+         and therefore subject to change.
+*/
+
+#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
+/* We'll use this version by default only where we know it helps.
+
+   regparm() generates warnings on Solaris boxes.   See SF bug #692878.
+
+   Instability reported with egcs on a RedHat Linux 7.3.
+   Let's comment out:
+   #define FASTCALL __attribute__((stdcall, regparm(3)))
+   and let's try this:
+*/
+#define FASTCALL __attribute__((regparm(3)))
+#define PTRFASTCALL __attribute__((regparm(3)))
+#endif
+
+/* Using __fastcall seems to have an unexpected negative effect under
+   MS VC++, especially for function pointers, so we won't use it for
+   now on that platform. It may be reconsidered for a future release
+   if it can be made more effective.
+   Likely reason: __fastcall on Windows is like stdcall, therefore
+   the compiler cannot perform stack optimizations for call clusters.
+*/
+
+/* Make sure all of these are defined if they aren't already. */
+
+#ifndef FASTCALL
+#define FASTCALL
+#endif
+
+#ifndef PTRCALL
+#define PTRCALL
+#endif
+
+#ifndef PTRFASTCALL
+#define PTRFASTCALL
+#endif
+
+#ifndef XML_MIN_SIZE
+#if !defined(__cplusplus) && !defined(inline)
+#ifdef __GNUC__
+#define inline __inline
+#endif /* __GNUC__ */
+#endif
+#endif /* XML_MIN_SIZE */
+
+#ifdef __cplusplus
+#define inline inline
+#else
+#ifndef inline
+#define inline
+#endif
+#endif

+ 36 - 0
libs/expat/lib/latin1tab.h

@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,

+ 73 - 0
libs/expat/lib/libexpat.def

@@ -0,0 +1,73 @@
+; DEF file for MS VC++
+
+LIBRARY
+EXPORTS
+  XML_DefaultCurrent @1
+  XML_ErrorString @2
+  XML_ExpatVersion @3
+  XML_ExpatVersionInfo @4
+  XML_ExternalEntityParserCreate @5
+  XML_GetBase @6
+  XML_GetBuffer @7
+  XML_GetCurrentByteCount @8
+  XML_GetCurrentByteIndex @9
+  XML_GetCurrentColumnNumber @10
+  XML_GetCurrentLineNumber @11
+  XML_GetErrorCode @12
+  XML_GetIdAttributeIndex @13
+  XML_GetInputContext @14
+  XML_GetSpecifiedAttributeCount @15
+  XML_Parse @16
+  XML_ParseBuffer @17
+  XML_ParserCreate @18
+  XML_ParserCreateNS @19
+  XML_ParserCreate_MM @20
+  XML_ParserFree @21
+  XML_SetAttlistDeclHandler @22
+  XML_SetBase @23
+  XML_SetCdataSectionHandler @24
+  XML_SetCharacterDataHandler @25
+  XML_SetCommentHandler @26
+  XML_SetDefaultHandler @27
+  XML_SetDefaultHandlerExpand @28
+  XML_SetDoctypeDeclHandler @29
+  XML_SetElementDeclHandler @30
+  XML_SetElementHandler @31
+  XML_SetEncoding @32
+  XML_SetEndCdataSectionHandler @33
+  XML_SetEndDoctypeDeclHandler @34
+  XML_SetEndElementHandler @35
+  XML_SetEndNamespaceDeclHandler @36
+  XML_SetEntityDeclHandler @37
+  XML_SetExternalEntityRefHandler @38
+  XML_SetExternalEntityRefHandlerArg @39
+  XML_SetNamespaceDeclHandler @40
+  XML_SetNotStandaloneHandler @41
+  XML_SetNotationDeclHandler @42
+  XML_SetParamEntityParsing @43
+  XML_SetProcessingInstructionHandler @44
+  XML_SetReturnNSTriplet @45
+  XML_SetStartCdataSectionHandler @46
+  XML_SetStartDoctypeDeclHandler @47
+  XML_SetStartElementHandler @48
+  XML_SetStartNamespaceDeclHandler @49
+  XML_SetUnknownEncodingHandler @50
+  XML_SetUnparsedEntityDeclHandler @51
+  XML_SetUserData @52
+  XML_SetXmlDeclHandler @53
+  XML_UseParserAsHandlerArg @54
+; added with version 1.95.3
+  XML_ParserReset @55
+  XML_SetSkippedEntityHandler @56
+; added with version 1.95.5
+  XML_GetFeatureList @57
+  XML_UseForeignDTD @58
+; added with version 1.95.6
+  XML_FreeContentModel @59
+  XML_MemMalloc @60
+  XML_MemRealloc @61
+  XML_MemFree @62
+; added with version 1.95.8
+  XML_StopParser @63
+  XML_ResumeParser @64
+  XML_GetParsingStatus @65

+ 242 - 0
libs/expat/lib/libexpat.vcxproj

@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Template|Win32">
+      <Configuration>Template</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Template|x64">
+      <Configuration>Template</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="UnityDebug|Win32">
+      <Configuration>UnityDebug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="UnityDebug|x64">
+      <Configuration>UnityDebug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="UnityRelease|Win32">
+      <Configuration>UnityRelease</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="UnityRelease|x64">
+      <Configuration>UnityRelease</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{27250AA6-FED6-F96F-E32B-E8E9719F8FEB}</ProjectGuid>
+    <RootNamespace>libexpat</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|Win32'">
+    <OutDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</OutDir>
+    <IntDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|x64'">
+    <OutDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</OutDir>
+    <IntDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|Win32'">
+    <OutDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</OutDir>
+    <IntDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|x64'">
+    <OutDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</OutDir>
+    <IntDir>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|Win32'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+      <FunctionLevelLinking>false</FunctionLevelLinking>
+      <Optimization>Disabled</Optimization>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_LIB;COMPILED_FROM_DSP;XML_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AssemblerListingLocation>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</AssemblerListingLocation>
+      <BrowseInformation>true</BrowseInformation>
+      <PrecompiledHeaderOutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.pch</PrecompiledHeaderOutputFile>
+      <ObjectFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</ObjectFileName>
+      <ProgramDataBaseFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</ProgramDataBaseFileName>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+    </ClCompile>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+    <Bscmake>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.bsc</OutputFile>
+    </Bscmake>
+    <Lib>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='UnityDebug|x64'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+      <FunctionLevelLinking>false</FunctionLevelLinking>
+      <Optimization>Disabled</Optimization>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_LIB;COMPILED_FROM_DSP;XML_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AssemblerListingLocation>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</AssemblerListingLocation>
+      <BrowseInformation>true</BrowseInformation>
+      <PrecompiledHeaderOutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.pch</PrecompiledHeaderOutputFile>
+      <ObjectFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</ObjectFileName>
+      <ProgramDataBaseFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</ProgramDataBaseFileName>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+    </ClCompile>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+    <Bscmake>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.bsc</OutputFile>
+    </Bscmake>
+    <Lib>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|Win32'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+      <StringPooling>true</StringPooling>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <Optimization>MaxSpeed</Optimization>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AssemblerListingLocation>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</AssemblerListingLocation>
+      <PrecompiledHeaderOutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.pch</PrecompiledHeaderOutputFile>
+      <ObjectFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</ObjectFileName>
+      <ProgramDataBaseFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\</ProgramDataBaseFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+    <Bscmake>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.bsc</OutputFile>
+    </Bscmake>
+    <Lib>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x86\$(ProjectName)\libexpat.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='UnityRelease|x64'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+      <StringPooling>true</StringPooling>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <Optimization>MaxSpeed</Optimization>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN64;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AssemblerListingLocation>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</AssemblerListingLocation>
+      <PrecompiledHeaderOutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.pch</PrecompiledHeaderOutputFile>
+      <ObjectFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</ObjectFileName>
+      <ProgramDataBaseFileName>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\</ProgramDataBaseFileName>
+    </ClCompile>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+    <Bscmake>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.bsc</OutputFile>
+    </Bscmake>
+    <Lib>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <OutputFile>.\..\..\..\Temp\$(SolutionName)\$(Configuration)\x64\$(ProjectName)\libexpat.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="xmlparse.c" />
+    <ClCompile Include="xmlrole.c" />
+    <ClCompile Include="xmltok.c" />
+    <ClCompile Include="xmltok_impl.c" />
+    <ClCompile Include="xmltok_ns.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ascii.h" />
+    <ClInclude Include="asciitab.h" />
+    <ClInclude Include="expat.h" />
+    <ClInclude Include="expat_external.h" />
+    <ClInclude Include="iasciitab.h" />
+    <ClInclude Include="internal.h" />
+    <ClInclude Include="latin1tab.h" />
+    <ClInclude Include="nametab.h" />
+    <ClInclude Include="utf8tab.h" />
+    <ClInclude Include="xmlrole.h" />
+    <ClInclude Include="xmltok.h" />
+    <ClInclude Include="xmltok_impl.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 73 - 0
libs/expat/lib/libexpatw.def

@@ -0,0 +1,73 @@
+; DEF file for MS VC++
+
+LIBRARY
+EXPORTS
+  XML_DefaultCurrent @1
+  XML_ErrorString @2
+  XML_ExpatVersion @3
+  XML_ExpatVersionInfo @4
+  XML_ExternalEntityParserCreate @5
+  XML_GetBase @6
+  XML_GetBuffer @7
+  XML_GetCurrentByteCount @8
+  XML_GetCurrentByteIndex @9
+  XML_GetCurrentColumnNumber @10
+  XML_GetCurrentLineNumber @11
+  XML_GetErrorCode @12
+  XML_GetIdAttributeIndex @13
+  XML_GetInputContext @14
+  XML_GetSpecifiedAttributeCount @15
+  XML_Parse @16
+  XML_ParseBuffer @17
+  XML_ParserCreate @18
+  XML_ParserCreateNS @19
+  XML_ParserCreate_MM @20
+  XML_ParserFree @21
+  XML_SetAttlistDeclHandler @22
+  XML_SetBase @23
+  XML_SetCdataSectionHandler @24
+  XML_SetCharacterDataHandler @25
+  XML_SetCommentHandler @26
+  XML_SetDefaultHandler @27
+  XML_SetDefaultHandlerExpand @28
+  XML_SetDoctypeDeclHandler @29
+  XML_SetElementDeclHandler @30
+  XML_SetElementHandler @31
+  XML_SetEncoding @32
+  XML_SetEndCdataSectionHandler @33
+  XML_SetEndDoctypeDeclHandler @34
+  XML_SetEndElementHandler @35
+  XML_SetEndNamespaceDeclHandler @36
+  XML_SetEntityDeclHandler @37
+  XML_SetExternalEntityRefHandler @38
+  XML_SetExternalEntityRefHandlerArg @39
+  XML_SetNamespaceDeclHandler @40
+  XML_SetNotStandaloneHandler @41
+  XML_SetNotationDeclHandler @42
+  XML_SetParamEntityParsing @43
+  XML_SetProcessingInstructionHandler @44
+  XML_SetReturnNSTriplet @45
+  XML_SetStartCdataSectionHandler @46
+  XML_SetStartDoctypeDeclHandler @47
+  XML_SetStartElementHandler @48
+  XML_SetStartNamespaceDeclHandler @49
+  XML_SetUnknownEncodingHandler @50
+  XML_SetUnparsedEntityDeclHandler @51
+  XML_SetUserData @52
+  XML_SetXmlDeclHandler @53
+  XML_UseParserAsHandlerArg @54
+; added with version 1.95.3
+  XML_ParserReset @55
+  XML_SetSkippedEntityHandler @56
+; added with version 1.95.5
+  XML_GetFeatureList @57
+  XML_UseForeignDTD @58
+; added with version 1.95.6
+  XML_FreeContentModel @59
+  XML_MemMalloc @60
+  XML_MemRealloc @61
+  XML_MemFree @62
+; added with version 1.95.8
+  XML_StopParser @63
+  XML_ResumeParser @64
+  XML_GetParsingStatus @65

+ 53 - 0
libs/expat/lib/macconfig.h

@@ -0,0 +1,53 @@
+/*================================================================
+** Copyright 2000, Clark Cooper
+** All rights reserved.
+**
+** This is free software. You are permitted to copy, distribute, or modify
+** it under the terms of the MIT/X license (contained in the COPYING file
+** with this distribution.)
+**
+*/
+
+#ifndef MACCONFIG_H
+#define MACCONFIG_H
+
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER  4321
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* whether byteorder is bigendian */
+#define WORDS_BIGENDIAN
+
+/* Define to specify how much context to retain around the current parse
+   point. */
+#undef XML_CONTEXT_BYTES
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `long' if <sys/types.h> does not define. */
+#define off_t  long
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+
+#endif /* ifndef MACCONFIG_H */

+ 150 - 0
libs/expat/lib/nametab.h

@@ -0,0 +1,150 @@
+static const unsigned namingBitmap[] = {
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
+0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
+0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
+0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
+0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
+0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
+0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
+0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
+0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
+0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
+0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
+0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
+0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
+0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
+0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
+0x40000000, 0xF580C900, 0x00000007, 0x02010800,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
+0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
+0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
+0x00000000, 0x00004C40, 0x00000000, 0x00000000,
+0x00000007, 0x00000000, 0x00000000, 0x00000000,
+0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
+0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
+0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
+0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
+0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
+0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
+0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
+0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
+0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
+0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
+0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
+0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
+0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
+0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
+0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
+0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
+};
+static const unsigned char nmstrtPages[] = {
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
+0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+static const unsigned char namePages[] = {
+0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
+0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};

+ 37 - 0
libs/expat/lib/utf8tab.h

@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+
+/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,

+ 32 - 0
libs/expat/lib/winconfig.h

@@ -0,0 +1,32 @@
+/*================================================================
+** Copyright 2000, Clark Cooper
+** All rights reserved.
+**
+** This is free software. You are permitted to copy, distribute, or modify
+** it under the terms of the MIT/X license (contained in the COPYING file
+** with this distribution.)
+*/
+
+#ifndef WINCONFIG_H
+#define WINCONFIG_H
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <memory.h>
+#include <string.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
+
+/* Windows has memmove() available. */
+#define HAVE_MEMMOVE
+
+#endif /* ndef WINCONFIG_H */

+ 6403 - 0
libs/expat/lib/xmlparse.c

@@ -0,0 +1,6403 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+#include <string.h>                     /* memset(), memcpy() */
+#include <assert.h>
+#include <limits.h>                     /* UINT_MAX */
+#include <time.h>                       /* time() */
+
+#define XML_BUILDING_EXPAT 1
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#elif defined(HAVE_EXPAT_CONFIG_H)
+#include <expat_config.h>
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "ascii.h"
+#include "expat.h"
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+/* Using pointer subtraction to convert to integer type. */
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) (const wchar_t)x
+#define XML_L(x) L ## x
+#else
+#define XML_T(x) (const unsigned short)x
+#define XML_L(x) x
+#endif
+
+#else
+
+#define XML_T(x) x
+#define XML_L(x) x
+
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+/* Handle the case where memmove() doesn't exist. */
+#ifndef HAVE_MEMMOVE
+#ifdef HAVE_BCOPY
+#define memmove(d,s,l) bcopy((s),(d),(l))
+#else
+#error memmove does not exist on this platform, nor is a substitute available
+#endif /* HAVE_BCOPY */
+#endif /* HAVE_MEMMOVE */
+
+#include "internal.h"
+#include "xmltok.h"
+#include "xmlrole.h"
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+  KEY name;
+} NAMED;
+
+typedef struct {
+  NAMED **v;
+  unsigned char power;
+  size_t size;
+  size_t used;
+  const XML_Memory_Handling_Suite *mem;
+} HASH_TABLE;
+
+/* Basic character hash algorithm, taken from Python's string hash:
+   h = h * 1000003 ^ character, the constant being a prime number.
+
+*/
+#ifdef XML_UNICODE
+#define CHAR_HASH(h, c) \
+  (((h) * 0xF4243) ^ (unsigned short)(c))
+#else
+#define CHAR_HASH(h, c) \
+  (((h) * 0xF4243) ^ (unsigned char)(c))
+#endif
+
+/* For probing (after a collision) we need a step size relative prime
+   to the hash table size, which is a power of 2. We use double-hashing,
+   since we can calculate a second hash value cheaply by taking those bits
+   of the first hash value that were discarded (masked out) when the table
+   index was calculated: index = hash & mask, where mask = table->size - 1.
+   We limit the maximum step size to table->size / 4 (mask >> 2) and make
+   it odd, since odd numbers are always relative prime to a power of 2.
+*/
+#define SECOND_HASH(hash, mask, power) \
+  ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
+  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
+
+typedef struct {
+  NAMED **p;
+  NAMED **end;
+} HASH_TABLE_ITER;
+
+#define INIT_TAG_BUF_SIZE 32  /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_ATTS_VERSION 0xFFFFFFFF
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+  struct prefix *prefix;
+  struct binding *nextTagBinding;
+  struct binding *prevPrefixBinding;
+  const struct attribute_id *attId;
+  XML_Char *uri;
+  int uriLen;
+  int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+  const XML_Char *name;
+  BINDING *binding;
+} PREFIX;
+
+typedef struct {
+  const XML_Char *str;
+  const XML_Char *localPart;
+  const XML_Char *prefix;
+  int strLen;
+  int uriLen;
+  int prefixLen;
+} TAG_NAME;
+
+/* TAG represents an open element.
+   The name of the element is stored in both the document and API
+   encodings.  The memory buffer 'buf' is a separately-allocated
+   memory area which stores the name.  During the XML_Parse()/
+   XMLParseBuffer() when the element is open, the memory for the 'raw'
+   version of the name (in the document encoding) is shared with the
+   document buffer.  If the element is open across calls to
+   XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
+   contain the 'raw' name as well.
+
+   A parser re-uses these structures, maintaining a list of allocated
+   TAG objects in a free list.
+*/
+typedef struct tag {
+  struct tag *parent;           /* parent of this element */
+  const char *rawName;          /* tagName in the original encoding */
+  int rawNameLength;
+  TAG_NAME name;                /* tagName in the API encoding */
+  char *buf;                    /* buffer for name components */
+  char *bufEnd;                 /* end of the buffer */
+  BINDING *bindings;
+} TAG;
+
+typedef struct {
+  const XML_Char *name;
+  const XML_Char *textPtr;
+  int textLen;                  /* length in XML_Chars */
+  int processed;                /* # of processed bytes - when suspended */
+  const XML_Char *systemId;
+  const XML_Char *base;
+  const XML_Char *publicId;
+  const XML_Char *notation;
+  XML_Bool open;
+  XML_Bool is_param;
+  XML_Bool is_internal; /* true if declared in internal subset outside PE */
+} ENTITY;
+
+typedef struct {
+  enum XML_Content_Type         type;
+  enum XML_Content_Quant        quant;
+  const XML_Char *              name;
+  int                           firstchild;
+  int                           lastchild;
+  int                           childcnt;
+  int                           nextsib;
+} CONTENT_SCAFFOLD;
+
+#define INIT_SCAFFOLD_ELEMENTS 32
+
+typedef struct block {
+  struct block *next;
+  int size;
+  XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+  BLOCK *blocks;
+  BLOCK *freeBlocks;
+  const XML_Char *end;
+  XML_Char *ptr;
+  XML_Char *start;
+  const XML_Memory_Handling_Suite *mem;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+   an attribute has been specified. */
+typedef struct attribute_id {
+  XML_Char *name;
+  PREFIX *prefix;
+  XML_Bool maybeTokenized;
+  XML_Bool xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+  const ATTRIBUTE_ID *id;
+  XML_Bool isCdata;
+  const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+  unsigned long version;
+  unsigned long hash;
+  const XML_Char *uriName;
+} NS_ATT;
+
+typedef struct {
+  const XML_Char *name;
+  PREFIX *prefix;
+  const ATTRIBUTE_ID *idAtt;
+  int nDefaultAtts;
+  int allocDefaultAtts;
+  DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+  HASH_TABLE generalEntities;
+  HASH_TABLE elementTypes;
+  HASH_TABLE attributeIds;
+  HASH_TABLE prefixes;
+  STRING_POOL pool;
+  STRING_POOL entityValuePool;
+  /* false once a parameter entity reference has been skipped */
+  XML_Bool keepProcessing;
+  /* true once an internal or external PE reference has been encountered;
+     this includes the reference to an external subset */
+  XML_Bool hasParamEntityRefs;
+  XML_Bool standalone;
+#ifdef XML_DTD
+  /* indicates if external PE has been read */
+  XML_Bool paramEntityRead;
+  HASH_TABLE paramEntities;
+#endif /* XML_DTD */
+  PREFIX defaultPrefix;
+  /* === scaffolding for building content model === */
+  XML_Bool in_eldecl;
+  CONTENT_SCAFFOLD *scaffold;
+  unsigned contentStringLen;
+  unsigned scaffSize;
+  unsigned scaffCount;
+  int scaffLevel;
+  int *scaffIndex;
+} DTD;
+
+typedef struct open_internal_entity {
+  const char *internalEventPtr;
+  const char *internalEventEndPtr;
+  struct open_internal_entity *next;
+  ENTITY *entity;
+  int startTagLevel;
+  XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
+                                         const char *start,
+                                         const char *end,
+                                         const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+#ifdef XML_DTD
+static Processor ignoreSectionProcessor;
+static Processor externalParEntProcessor;
+static Processor externalParEntInitProcessor;
+static Processor entityValueProcessor;
+static Processor entityValueInitProcessor;
+#endif /* XML_DTD */
+static Processor epilogProcessor;
+static Processor errorProcessor;
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+static Processor internalEntityProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+               const char *s, const char *next);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
+         const char *end, int tok, const char *next, const char **nextPtr,
+         XML_Bool haveMore);
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+                      XML_Bool betweenDecl);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+          const char *start, const char *end, const char **endPtr,
+          XML_Bool haveMore);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+               const char *end, const char **nextPtr, XML_Bool haveMore);
+#ifdef XML_DTD
+static enum XML_Error
+doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+                const char *end, const char **nextPtr, XML_Bool haveMore);
+#endif /* XML_DTD */
+
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+           const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+                    const char *, const char *, STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+                     const char *, const char *, STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+               const char *end);
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
+                 const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                            const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+              const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
+              const char *end);
+
+static const XML_Char * getContext(XML_Parser parser);
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context);
+
+static void FASTCALL normalizePublicId(XML_Char *s);
+
+static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if parentParser != NULL */
+static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
+static int
+dtdCopy(XML_Parser oldParser,
+        DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
+static int
+copyEntityTable(XML_Parser oldParser,
+                HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
+static void FASTCALL
+hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL hashTableClear(HASH_TABLE *);
+static void FASTCALL hashTableDestroy(HASH_TABLE *);
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+
+static void FASTCALL
+poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolClear(STRING_POOL *);
+static void FASTCALL poolDestroy(STRING_POOL *);
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+           const char *ptr, const char *end);
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+                const char *ptr, const char *end);
+static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s);
+
+static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static XML_Content * build_model(XML_Parser parser);
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser, const ENCODING *enc,
+               const char *ptr, const char *end);
+
+static unsigned long generate_hash_secret_salt(void);
+static XML_Bool startParsing(XML_Parser parser);
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+             const XML_Memory_Handling_Suite *memsuite,
+             const XML_Char *nameSep,
+             DTD *dtd);
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+  (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+   ? 0 \
+   : ((*((pool)->ptr)++ = c), 1))
+
+struct XML_ParserStruct {
+  /* The first member must be userData so that the XML_GetUserData
+     macro works. */
+  void *m_userData;
+  void *m_handlerArg;
+  char *m_buffer;
+  const XML_Memory_Handling_Suite m_mem;
+  /* first character to be parsed */
+  const char *m_bufferPtr;
+  /* past last character to be parsed */
+  char *m_bufferEnd;
+  /* allocated end of buffer */
+  const char *m_bufferLim;
+  XML_Index m_parseEndByteIndex;
+  const char *m_parseEndPtr;
+  XML_Char *m_dataBuf;
+  XML_Char *m_dataBufEnd;
+  XML_StartElementHandler m_startElementHandler;
+  XML_EndElementHandler m_endElementHandler;
+  XML_CharacterDataHandler m_characterDataHandler;
+  XML_ProcessingInstructionHandler m_processingInstructionHandler;
+  XML_CommentHandler m_commentHandler;
+  XML_StartCdataSectionHandler m_startCdataSectionHandler;
+  XML_EndCdataSectionHandler m_endCdataSectionHandler;
+  XML_DefaultHandler m_defaultHandler;
+  XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
+  XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
+  XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+  XML_NotationDeclHandler m_notationDeclHandler;
+  XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+  XML_NotStandaloneHandler m_notStandaloneHandler;
+  XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+  XML_Parser m_externalEntityRefHandlerArg;
+  XML_SkippedEntityHandler m_skippedEntityHandler;
+  XML_UnknownEncodingHandler m_unknownEncodingHandler;
+  XML_ElementDeclHandler m_elementDeclHandler;
+  XML_AttlistDeclHandler m_attlistDeclHandler;
+  XML_EntityDeclHandler m_entityDeclHandler;
+  XML_XmlDeclHandler m_xmlDeclHandler;
+  const ENCODING *m_encoding;
+  INIT_ENCODING m_initEncoding;
+  const ENCODING *m_internalEncoding;
+  const XML_Char *m_protocolEncodingName;
+  XML_Bool m_ns;
+  XML_Bool m_ns_triplets;
+  void *m_unknownEncodingMem;
+  void *m_unknownEncodingData;
+  void *m_unknownEncodingHandlerData;
+  void (XMLCALL *m_unknownEncodingRelease)(void *);
+  PROLOG_STATE m_prologState;
+  Processor *m_processor;
+  enum XML_Error m_errorCode;
+  const char *m_eventPtr;
+  const char *m_eventEndPtr;
+  const char *m_positionPtr;
+  OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+  OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+  XML_Bool m_defaultExpandInternalEntities;
+  int m_tagLevel;
+  ENTITY *m_declEntity;
+  const XML_Char *m_doctypeName;
+  const XML_Char *m_doctypeSysid;
+  const XML_Char *m_doctypePubid;
+  const XML_Char *m_declAttributeType;
+  const XML_Char *m_declNotationName;
+  const XML_Char *m_declNotationPublicId;
+  ELEMENT_TYPE *m_declElementType;
+  ATTRIBUTE_ID *m_declAttributeId;
+  XML_Bool m_declAttributeIsCdata;
+  XML_Bool m_declAttributeIsId;
+  DTD *m_dtd;
+  const XML_Char *m_curBase;
+  TAG *m_tagStack;
+  TAG *m_freeTagList;
+  BINDING *m_inheritedBindings;
+  BINDING *m_freeBindingList;
+  int m_attsSize;
+  int m_nSpecifiedAtts;
+  int m_idAttIndex;
+  ATTRIBUTE *m_atts;
+  NS_ATT *m_nsAtts;
+  unsigned long m_nsAttsVersion;
+  unsigned char m_nsAttsPower;
+#ifdef XML_ATTR_INFO
+  XML_AttrInfo *m_attInfo;
+#endif
+  POSITION m_position;
+  STRING_POOL m_tempPool;
+  STRING_POOL m_temp2Pool;
+  char *m_groupConnector;
+  unsigned int m_groupSize;
+  XML_Char m_namespaceSeparator;
+  XML_Parser m_parentParser;
+  XML_ParsingStatus m_parsingStatus;
+#ifdef XML_DTD
+  XML_Bool m_isParamEntity;
+  XML_Bool m_useForeignDTD;
+  enum XML_ParamEntityParsing m_paramEntityParsing;
+#endif
+  unsigned long m_hash_secret_salt;
+};
+
+#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(p) (parser->m_mem.free_fcn((p)))
+
+#define userData (parser->m_userData)
+#define handlerArg (parser->m_handlerArg)
+#define startElementHandler (parser->m_startElementHandler)
+#define endElementHandler (parser->m_endElementHandler)
+#define characterDataHandler (parser->m_characterDataHandler)
+#define processingInstructionHandler \
+        (parser->m_processingInstructionHandler)
+#define commentHandler (parser->m_commentHandler)
+#define startCdataSectionHandler \
+        (parser->m_startCdataSectionHandler)
+#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
+#define defaultHandler (parser->m_defaultHandler)
+#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
+#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
+#define unparsedEntityDeclHandler \
+        (parser->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (parser->m_notationDeclHandler)
+#define startNamespaceDeclHandler \
+        (parser->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (parser->m_notStandaloneHandler)
+#define externalEntityRefHandler \
+        (parser->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg \
+        (parser->m_externalEntityRefHandlerArg)
+#define internalEntityRefHandler \
+        (parser->m_internalEntityRefHandler)
+#define skippedEntityHandler (parser->m_skippedEntityHandler)
+#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
+#define elementDeclHandler (parser->m_elementDeclHandler)
+#define attlistDeclHandler (parser->m_attlistDeclHandler)
+#define entityDeclHandler (parser->m_entityDeclHandler)
+#define xmlDeclHandler (parser->m_xmlDeclHandler)
+#define encoding (parser->m_encoding)
+#define initEncoding (parser->m_initEncoding)
+#define internalEncoding (parser->m_internalEncoding)
+#define unknownEncodingMem (parser->m_unknownEncodingMem)
+#define unknownEncodingData (parser->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+  (parser->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
+#define protocolEncodingName (parser->m_protocolEncodingName)
+#define ns (parser->m_ns)
+#define ns_triplets (parser->m_ns_triplets)
+#define prologState (parser->m_prologState)
+#define processor (parser->m_processor)
+#define errorCode (parser->m_errorCode)
+#define eventPtr (parser->m_eventPtr)
+#define eventEndPtr (parser->m_eventEndPtr)
+#define positionPtr (parser->m_positionPtr)
+#define position (parser->m_position)
+#define openInternalEntities (parser->m_openInternalEntities)
+#define freeInternalEntities (parser->m_freeInternalEntities)
+#define defaultExpandInternalEntities \
+        (parser->m_defaultExpandInternalEntities)
+#define tagLevel (parser->m_tagLevel)
+#define buffer (parser->m_buffer)
+#define bufferPtr (parser->m_bufferPtr)
+#define bufferEnd (parser->m_bufferEnd)
+#define parseEndByteIndex (parser->m_parseEndByteIndex)
+#define parseEndPtr (parser->m_parseEndPtr)
+#define bufferLim (parser->m_bufferLim)
+#define dataBuf (parser->m_dataBuf)
+#define dataBufEnd (parser->m_dataBufEnd)
+#define _dtd (parser->m_dtd)
+#define curBase (parser->m_curBase)
+#define declEntity (parser->m_declEntity)
+#define doctypeName (parser->m_doctypeName)
+#define doctypeSysid (parser->m_doctypeSysid)
+#define doctypePubid (parser->m_doctypePubid)
+#define declAttributeType (parser->m_declAttributeType)
+#define declNotationName (parser->m_declNotationName)
+#define declNotationPublicId (parser->m_declNotationPublicId)
+#define declElementType (parser->m_declElementType)
+#define declAttributeId (parser->m_declAttributeId)
+#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
+#define declAttributeIsId (parser->m_declAttributeIsId)
+#define freeTagList (parser->m_freeTagList)
+#define freeBindingList (parser->m_freeBindingList)
+#define inheritedBindings (parser->m_inheritedBindings)
+#define tagStack (parser->m_tagStack)
+#define atts (parser->m_atts)
+#define attsSize (parser->m_attsSize)
+#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
+#define idAttIndex (parser->m_idAttIndex)
+#define nsAtts (parser->m_nsAtts)
+#define nsAttsVersion (parser->m_nsAttsVersion)
+#define nsAttsPower (parser->m_nsAttsPower)
+#define attInfo (parser->m_attInfo)
+#define tempPool (parser->m_tempPool)
+#define temp2Pool (parser->m_temp2Pool)
+#define groupConnector (parser->m_groupConnector)
+#define groupSize (parser->m_groupSize)
+#define namespaceSeparator (parser->m_namespaceSeparator)
+#define parentParser (parser->m_parentParser)
+#define ps_parsing (parser->m_parsingStatus.parsing)
+#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
+#ifdef XML_DTD
+#define isParamEntity (parser->m_isParamEntity)
+#define useForeignDTD (parser->m_useForeignDTD)
+#define paramEntityParsing (parser->m_paramEntityParsing)
+#endif /* XML_DTD */
+#define hash_secret_salt (parser->m_hash_secret_salt)
+
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encodingName)
+{
+  return XML_ParserCreate_MM(encodingName, NULL, NULL);
+}
+
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+  XML_Char tmp[2];
+  *tmp = nsSep;
+  return XML_ParserCreate_MM(encodingName, NULL, tmp);
+}
+
+static const XML_Char implicitContext[] = {
+  ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
+  ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
+  ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
+  ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
+  ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
+  ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
+};
+
+static unsigned long
+generate_hash_secret_salt(void)
+{
+  unsigned int seed = time(NULL) % UINT_MAX;
+  srand(seed);
+  return rand();
+}
+
+static XML_Bool  /* only valid for root parser */
+startParsing(XML_Parser parser)
+{
+    /* hash functions must be initialized before setContext() is called */
+    if (hash_secret_salt == 0)
+      hash_secret_salt = generate_hash_secret_salt();
+    if (ns) {
+      /* implicit context only set for root parser, since child
+         parsers (i.e. external entity parsers) will inherit it
+      */
+      return setContext(parser, implicitContext);
+    }
+    return XML_TRUE;
+}
+
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encodingName,
+                    const XML_Memory_Handling_Suite *memsuite,
+                    const XML_Char *nameSep)
+{
+  return parserCreate(encodingName, memsuite, nameSep, NULL);
+}
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+             const XML_Memory_Handling_Suite *memsuite,
+             const XML_Char *nameSep,
+             DTD *dtd)
+{
+  XML_Parser parser;
+
+  if (memsuite) {
+    XML_Memory_Handling_Suite *mtemp;
+    parser = (XML_Parser)
+      memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+    if (parser != NULL) {
+      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+      mtemp->malloc_fcn = memsuite->malloc_fcn;
+      mtemp->realloc_fcn = memsuite->realloc_fcn;
+      mtemp->free_fcn = memsuite->free_fcn;
+    }
+  }
+  else {
+    XML_Memory_Handling_Suite *mtemp;
+    parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
+    if (parser != NULL) {
+      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+      mtemp->malloc_fcn = malloc;
+      mtemp->realloc_fcn = realloc;
+      mtemp->free_fcn = free;
+    }
+  }
+
+  if (!parser)
+    return parser;
+
+  buffer = NULL;
+  bufferLim = NULL;
+
+  attsSize = INIT_ATTS_SIZE;
+  atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
+  if (atts == NULL) {
+    FREE(parser);
+    return NULL;
+  }
+#ifdef XML_ATTR_INFO
+  attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
+  if (attInfo == NULL) {
+    FREE(atts);
+    FREE(parser);
+    return NULL;
+  }
+#endif
+  dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+  if (dataBuf == NULL) {
+    FREE(atts);
+#ifdef XML_ATTR_INFO
+    FREE(attInfo);
+#endif
+    FREE(parser);
+    return NULL;
+  }
+  dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+
+  if (dtd)
+    _dtd = dtd;
+  else {
+    _dtd = dtdCreate(&parser->m_mem);
+    if (_dtd == NULL) {
+      FREE(dataBuf);
+      FREE(atts);
+#ifdef XML_ATTR_INFO
+      FREE(attInfo);
+#endif
+      FREE(parser);
+      return NULL;
+    }
+  }
+
+  freeBindingList = NULL;
+  freeTagList = NULL;
+  freeInternalEntities = NULL;
+
+  groupSize = 0;
+  groupConnector = NULL;
+
+  unknownEncodingHandler = NULL;
+  unknownEncodingHandlerData = NULL;
+
+  namespaceSeparator = ASCII_EXCL;
+  ns = XML_FALSE;
+  ns_triplets = XML_FALSE;
+
+  nsAtts = NULL;
+  nsAttsVersion = 0;
+  nsAttsPower = 0;
+
+  poolInit(&tempPool, &(parser->m_mem));
+  poolInit(&temp2Pool, &(parser->m_mem));
+  parserInit(parser, encodingName);
+
+  if (encodingName && !protocolEncodingName) {
+    XML_ParserFree(parser);
+    return NULL;
+  }
+
+  if (nameSep) {
+    ns = XML_TRUE;
+    internalEncoding = XmlGetInternalEncodingNS();
+    namespaceSeparator = *nameSep;
+  }
+  else {
+    internalEncoding = XmlGetInternalEncoding();
+  }
+
+  return parser;
+}
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName)
+{
+  processor = prologInitProcessor;
+  XmlPrologStateInit(&prologState);
+  protocolEncodingName = (encodingName != NULL
+                          ? poolCopyString(&tempPool, encodingName)
+                          : NULL);
+  curBase = NULL;
+  XmlInitEncoding(&initEncoding, &encoding, 0);
+  userData = NULL;
+  handlerArg = NULL;
+  startElementHandler = NULL;
+  endElementHandler = NULL;
+  characterDataHandler = NULL;
+  processingInstructionHandler = NULL;
+  commentHandler = NULL;
+  startCdataSectionHandler = NULL;
+  endCdataSectionHandler = NULL;
+  defaultHandler = NULL;
+  startDoctypeDeclHandler = NULL;
+  endDoctypeDeclHandler = NULL;
+  unparsedEntityDeclHandler = NULL;
+  notationDeclHandler = NULL;
+  startNamespaceDeclHandler = NULL;
+  endNamespaceDeclHandler = NULL;
+  notStandaloneHandler = NULL;
+  externalEntityRefHandler = NULL;
+  externalEntityRefHandlerArg = parser;
+  skippedEntityHandler = NULL;
+  elementDeclHandler = NULL;
+  attlistDeclHandler = NULL;
+  entityDeclHandler = NULL;
+  xmlDeclHandler = NULL;
+  bufferPtr = buffer;
+  bufferEnd = buffer;
+  parseEndByteIndex = 0;
+  parseEndPtr = NULL;
+  declElementType = NULL;
+  declAttributeId = NULL;
+  declEntity = NULL;
+  doctypeName = NULL;
+  doctypeSysid = NULL;
+  doctypePubid = NULL;
+  declAttributeType = NULL;
+  declNotationName = NULL;
+  declNotationPublicId = NULL;
+  declAttributeIsCdata = XML_FALSE;
+  declAttributeIsId = XML_FALSE;
+  memset(&position, 0, sizeof(POSITION));
+  errorCode = XML_ERROR_NONE;
+  eventPtr = NULL;
+  eventEndPtr = NULL;
+  positionPtr = NULL;
+  openInternalEntities = NULL;
+  defaultExpandInternalEntities = XML_TRUE;
+  tagLevel = 0;
+  tagStack = NULL;
+  inheritedBindings = NULL;
+  nSpecifiedAtts = 0;
+  unknownEncodingMem = NULL;
+  unknownEncodingRelease = NULL;
+  unknownEncodingData = NULL;
+  parentParser = NULL;
+  ps_parsing = XML_INITIALIZED;
+#ifdef XML_DTD
+  isParamEntity = XML_FALSE;
+  useForeignDTD = XML_FALSE;
+  paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+  hash_secret_salt = 0;
+}
+
+/* moves list of bindings to freeBindingList */
+static void FASTCALL
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
+{
+  while (bindings) {
+    BINDING *b = bindings;
+    bindings = bindings->nextTagBinding;
+    b->nextTagBinding = freeBindingList;
+    freeBindingList = b;
+  }
+}
+
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
+{
+  TAG *tStk;
+  OPEN_INTERNAL_ENTITY *openEntityList;
+  if (parentParser)
+    return XML_FALSE;
+  /* move tagStack to freeTagList */
+  tStk = tagStack;
+  while (tStk) {
+    TAG *tag = tStk;
+    tStk = tStk->parent;
+    tag->parent = freeTagList;
+    moveToFreeBindingList(parser, tag->bindings);
+    tag->bindings = NULL;
+    freeTagList = tag;
+  }
+  /* move openInternalEntities to freeInternalEntities */
+  openEntityList = openInternalEntities;
+  while (openEntityList) {
+    OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+    openEntityList = openEntity->next;
+    openEntity->next = freeInternalEntities;
+    freeInternalEntities = openEntity;
+  }
+  moveToFreeBindingList(parser, inheritedBindings);
+  FREE(unknownEncodingMem);
+  if (unknownEncodingRelease)
+    unknownEncodingRelease(unknownEncodingData);
+  poolClear(&tempPool);
+  poolClear(&temp2Pool);
+  parserInit(parser, encodingName);
+  dtdReset(_dtd, &parser->m_mem);
+  return XML_TRUE;
+}
+
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+  /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+     XXX There's no way for the caller to determine which of the
+     XXX possible error cases caused the XML_STATUS_ERROR return.
+  */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return XML_STATUS_ERROR;
+  if (encodingName == NULL)
+    protocolEncodingName = NULL;
+  else {
+    protocolEncodingName = poolCopyString(&tempPool, encodingName);
+    if (!protocolEncodingName)
+      return XML_STATUS_ERROR;
+  }
+  return XML_STATUS_OK;
+}
+
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser oldParser,
+                               const XML_Char *context,
+                               const XML_Char *encodingName)
+{
+  XML_Parser parser = oldParser;
+  DTD *newDtd = NULL;
+  DTD *oldDtd = _dtd;
+  XML_StartElementHandler oldStartElementHandler = startElementHandler;
+  XML_EndElementHandler oldEndElementHandler = endElementHandler;
+  XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
+  XML_ProcessingInstructionHandler oldProcessingInstructionHandler
+      = processingInstructionHandler;
+  XML_CommentHandler oldCommentHandler = commentHandler;
+  XML_StartCdataSectionHandler oldStartCdataSectionHandler
+      = startCdataSectionHandler;
+  XML_EndCdataSectionHandler oldEndCdataSectionHandler
+      = endCdataSectionHandler;
+  XML_DefaultHandler oldDefaultHandler = defaultHandler;
+  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
+      = unparsedEntityDeclHandler;
+  XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
+  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
+      = startNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
+      = endNamespaceDeclHandler;
+  XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
+  XML_ExternalEntityRefHandler oldExternalEntityRefHandler
+      = externalEntityRefHandler;
+  XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
+  XML_UnknownEncodingHandler oldUnknownEncodingHandler
+      = unknownEncodingHandler;
+  XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
+  XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
+  XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
+  XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
+  ELEMENT_TYPE * oldDeclElementType = declElementType;
+
+  void *oldUserData = userData;
+  void *oldHandlerArg = handlerArg;
+  XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+  XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+  enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
+  int oldInEntityValue = prologState.inEntityValue;
+#endif
+  XML_Bool oldns_triplets = ns_triplets;
+  /* Note that the new parser shares the same hash secret as the old
+     parser, so that dtdCopy and copyEntityTable can lookup values
+     from hash tables associated with either parser without us having
+     to worry which hash secrets each table has.
+  */
+  unsigned long oldhash_secret_salt = hash_secret_salt;
+
+#ifdef XML_DTD
+  if (!context)
+    newDtd = oldDtd;
+#endif /* XML_DTD */
+
+  /* Note that the magical uses of the pre-processor to make field
+     access look more like C++ require that `parser' be overwritten
+     here.  This makes this function more painful to follow than it
+     would be otherwise.
+  */
+  if (ns) {
+    XML_Char tmp[2];
+    *tmp = namespaceSeparator;
+    parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+  }
+  else {
+    parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+  }
+
+  if (!parser)
+    return NULL;
+
+  startElementHandler = oldStartElementHandler;
+  endElementHandler = oldEndElementHandler;
+  characterDataHandler = oldCharacterDataHandler;
+  processingInstructionHandler = oldProcessingInstructionHandler;
+  commentHandler = oldCommentHandler;
+  startCdataSectionHandler = oldStartCdataSectionHandler;
+  endCdataSectionHandler = oldEndCdataSectionHandler;
+  defaultHandler = oldDefaultHandler;
+  unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+  notationDeclHandler = oldNotationDeclHandler;
+  startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+  endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+  notStandaloneHandler = oldNotStandaloneHandler;
+  externalEntityRefHandler = oldExternalEntityRefHandler;
+  skippedEntityHandler = oldSkippedEntityHandler;
+  unknownEncodingHandler = oldUnknownEncodingHandler;
+  elementDeclHandler = oldElementDeclHandler;
+  attlistDeclHandler = oldAttlistDeclHandler;
+  entityDeclHandler = oldEntityDeclHandler;
+  xmlDeclHandler = oldXmlDeclHandler;
+  declElementType = oldDeclElementType;
+  userData = oldUserData;
+  if (oldUserData == oldHandlerArg)
+    handlerArg = userData;
+  else
+    handlerArg = parser;
+  if (oldExternalEntityRefHandlerArg != oldParser)
+    externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+  defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+  ns_triplets = oldns_triplets;
+  hash_secret_salt = oldhash_secret_salt;
+  parentParser = oldParser;
+#ifdef XML_DTD
+  paramEntityParsing = oldParamEntityParsing;
+  prologState.inEntityValue = oldInEntityValue;
+  if (context) {
+#endif /* XML_DTD */
+    if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+      || !setContext(parser, context)) {
+      XML_ParserFree(parser);
+      return NULL;
+    }
+    processor = externalEntityInitProcessor;
+#ifdef XML_DTD
+  }
+  else {
+    /* The DTD instance referenced by _dtd is shared between the document's
+       root parser and external PE parsers, therefore one does not need to
+       call setContext. In addition, one also *must* not call setContext,
+       because this would overwrite existing prefix->binding pointers in
+       _dtd with ones that get destroyed with the external PE parser.
+       This would leave those prefixes with dangling pointers.
+    */
+    isParamEntity = XML_TRUE;
+    XmlPrologStateInitExternalEntity(&prologState);
+    processor = externalParEntInitProcessor;
+  }
+#endif /* XML_DTD */
+  return parser;
+}
+
+static void FASTCALL
+destroyBindings(BINDING *bindings, XML_Parser parser)
+{
+  for (;;) {
+    BINDING *b = bindings;
+    if (!b)
+      break;
+    bindings = b->nextTagBinding;
+    FREE(b->uri);
+    FREE(b);
+  }
+}
+
+void XMLCALL
+XML_ParserFree(XML_Parser parser)
+{
+  TAG *tagList;
+  OPEN_INTERNAL_ENTITY *entityList;
+  if (parser == NULL)
+    return;
+  /* free tagStack and freeTagList */
+  tagList = tagStack;
+  for (;;) {
+    TAG *p;
+    if (tagList == NULL) {
+      if (freeTagList == NULL)
+        break;
+      tagList = freeTagList;
+      freeTagList = NULL;
+    }
+    p = tagList;
+    tagList = tagList->parent;
+    FREE(p->buf);
+    destroyBindings(p->bindings, parser);
+    FREE(p);
+  }
+  /* free openInternalEntities and freeInternalEntities */
+  entityList = openInternalEntities;
+  for (;;) {
+    OPEN_INTERNAL_ENTITY *openEntity;
+    if (entityList == NULL) {
+      if (freeInternalEntities == NULL)
+        break;
+      entityList = freeInternalEntities;
+      freeInternalEntities = NULL;
+    }
+    openEntity = entityList;
+    entityList = entityList->next;
+    FREE(openEntity);
+  }
+
+  destroyBindings(freeBindingList, parser);
+  destroyBindings(inheritedBindings, parser);
+  poolDestroy(&tempPool);
+  poolDestroy(&temp2Pool);
+#ifdef XML_DTD
+  /* external parameter entity parsers share the DTD structure
+     parser->m_dtd with the root parser, so we must not destroy it
+  */
+  if (!isParamEntity && _dtd)
+#else
+  if (_dtd)
+#endif /* XML_DTD */
+    dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
+  FREE((void *)atts);
+#ifdef XML_ATTR_INFO
+  FREE((void *)attInfo);
+#endif
+  FREE(groupConnector);
+  FREE(buffer);
+  FREE(dataBuf);
+  FREE(nsAtts);
+  FREE(unknownEncodingMem);
+  if (unknownEncodingRelease)
+    unknownEncodingRelease(unknownEncodingData);
+  FREE(parser);
+}
+
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+  handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+#ifdef XML_DTD
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
+  useForeignDTD = useDTD;
+  return XML_ERROR_NONE;
+#else
+  return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
+#endif
+}
+
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return;
+  ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+}
+
+void XMLCALL
+XML_SetUserData(XML_Parser parser, void *p)
+{
+  if (handlerArg == userData)
+    handlerArg = userData = p;
+  else
+    userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+  if (p) {
+    p = poolCopyString(&_dtd->pool, p);
+    if (!p)
+      return XML_STATUS_ERROR;
+    curBase = p;
+  }
+  else
+    curBase = NULL;
+  return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+  return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+  return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+  return idAttIndex;
+}
+
+#ifdef XML_ATTR_INFO
+const XML_AttrInfo * XMLCALL
+XML_GetAttributeInfo(XML_Parser parser)
+{
+  return attInfo;
+}
+#endif
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+                      XML_StartElementHandler start,
+                      XML_EndElementHandler end)
+{
+  startElementHandler = start;
+  endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+                           XML_StartElementHandler start) {
+  startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+                         XML_EndElementHandler end) {
+  endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+                            XML_CharacterDataHandler handler)
+{
+  characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+                                    XML_ProcessingInstructionHandler handler)
+{
+  processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+                      XML_CommentHandler handler)
+{
+  commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+                           XML_StartCdataSectionHandler start,
+                           XML_EndCdataSectionHandler end)
+{
+  startCdataSectionHandler = start;
+  endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+                                XML_StartCdataSectionHandler start) {
+  startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+                              XML_EndCdataSectionHandler end) {
+  endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+                      XML_DefaultHandler handler)
+{
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+                            XML_DefaultHandler handler)
+{
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+                          XML_StartDoctypeDeclHandler start,
+                          XML_EndDoctypeDeclHandler end)
+{
+  startDoctypeDeclHandler = start;
+  endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+                               XML_StartDoctypeDeclHandler start) {
+  startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+                             XML_EndDoctypeDeclHandler end) {
+  endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+                                 XML_UnparsedEntityDeclHandler handler)
+{
+  unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+                           XML_NotationDeclHandler handler)
+{
+  notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+                            XML_StartNamespaceDeclHandler start,
+                            XML_EndNamespaceDeclHandler end)
+{
+  startNamespaceDeclHandler = start;
+  endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+                                 XML_StartNamespaceDeclHandler start) {
+  startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+                               XML_EndNamespaceDeclHandler end) {
+  endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+                            XML_NotStandaloneHandler handler)
+{
+  notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+                                XML_ExternalEntityRefHandler handler)
+{
+  externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+  if (arg)
+    externalEntityRefHandlerArg = (XML_Parser)arg;
+  else
+    externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+                            XML_SkippedEntityHandler handler)
+{
+  skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+                              XML_UnknownEncodingHandler handler,
+                              void *data)
+{
+  unknownEncodingHandler = handler;
+  unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+                          XML_ElementDeclHandler eldecl)
+{
+  elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+                          XML_AttlistDeclHandler attdecl)
+{
+  attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+                         XML_EntityDeclHandler handler)
+{
+  entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+                      XML_XmlDeclHandler handler) {
+  xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+                          enum XML_ParamEntityParsing peParsing)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+#ifdef XML_DTD
+  paramEntityParsing = peParsing;
+  return 1;
+#else
+  return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+int XMLCALL
+XML_SetHashSalt(XML_Parser parser,
+                unsigned long hash_salt)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+  hash_secret_salt = hash_salt;
+  return 1;
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return XML_STATUS_ERROR;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  case XML_INITIALIZED:
+    if (parentParser == NULL && !startParsing(parser)) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return XML_STATUS_ERROR;
+    }
+  default:
+    ps_parsing = XML_PARSING;
+  }
+
+  if (len == 0) {
+    ps_finalBuffer = (XML_Bool)isFinal;
+    if (!isFinal)
+      return XML_STATUS_OK;
+    positionPtr = bufferPtr;
+    parseEndPtr = bufferEnd;
+
+    /* If data are left over from last buffer, and we now know that these
+       data are the final chunk of input, then we have to check them again
+       to detect errors based on that fact.
+    */
+    errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+    if (errorCode == XML_ERROR_NONE) {
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+        positionPtr = bufferPtr;
+        return XML_STATUS_SUSPENDED;
+      case XML_INITIALIZED:
+      case XML_PARSING:
+        ps_parsing = XML_FINISHED;
+        /* fall through */
+      default:
+        return XML_STATUS_OK;
+      }
+    }
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+#ifndef XML_CONTEXT_BYTES
+  else if (bufferPtr == bufferEnd) {
+    const char *end;
+    int nLeftOver;
+    enum XML_Error result;
+    parseEndByteIndex += len;
+    positionPtr = s;
+    ps_finalBuffer = (XML_Bool)isFinal;
+
+    errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+
+    if (errorCode != XML_ERROR_NONE) {
+      eventEndPtr = eventPtr;
+      processor = errorProcessor;
+      return XML_STATUS_ERROR;
+    }
+    else {
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        result = XML_STATUS_SUSPENDED;
+        break;
+      case XML_INITIALIZED:
+      case XML_PARSING:
+        if (isFinal) {
+          ps_parsing = XML_FINISHED;
+          return XML_STATUS_OK;
+        }
+      /* fall through */
+      default:
+        result = XML_STATUS_OK;
+      }
+    }
+
+    XmlUpdatePosition(encoding, positionPtr, end, &position);
+    nLeftOver = s + len - end;
+    if (nLeftOver) {
+      if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+        /* FIXME avoid integer overflow */
+        char *temp;
+        temp = (buffer == NULL
+                ? (char *)MALLOC(len * 2)
+                : (char *)REALLOC(buffer, len * 2));
+        if (temp == NULL) {
+          errorCode = XML_ERROR_NO_MEMORY;
+          eventPtr = eventEndPtr = NULL;
+          processor = errorProcessor;
+          return XML_STATUS_ERROR;
+        }
+        buffer = temp;
+        bufferLim = buffer + len * 2;
+      }
+      memcpy(buffer, end, nLeftOver);
+    }
+    bufferPtr = buffer;
+    bufferEnd = buffer + nLeftOver;
+    positionPtr = bufferPtr;
+    parseEndPtr = bufferEnd;
+    eventPtr = bufferPtr;
+    eventEndPtr = bufferPtr;
+    return result;
+  }
+#endif  /* not defined XML_CONTEXT_BYTES */
+  else {
+    void *buff = XML_GetBuffer(parser, len);
+    if (buff == NULL)
+      return XML_STATUS_ERROR;
+    else {
+      memcpy(buff, s, len);
+      return XML_ParseBuffer(parser, len, isFinal);
+    }
+  }
+}
+
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+  const char *start;
+  enum XML_Status result = XML_STATUS_OK;
+
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return XML_STATUS_ERROR;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  case XML_INITIALIZED:
+    if (parentParser == NULL && !startParsing(parser)) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return XML_STATUS_ERROR;
+    }
+  default:
+    ps_parsing = XML_PARSING;
+  }
+
+  start = bufferPtr;
+  positionPtr = start;
+  bufferEnd += len;
+  parseEndPtr = bufferEnd;
+  parseEndByteIndex += len;
+  ps_finalBuffer = (XML_Bool)isFinal;
+
+  errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+
+  if (errorCode != XML_ERROR_NONE) {
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+  else {
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      result = XML_STATUS_SUSPENDED;
+      break;
+    case XML_INITIALIZED:
+    case XML_PARSING:
+      if (isFinal) {
+        ps_parsing = XML_FINISHED;
+        return result;
+      }
+    default: ;  /* should not happen */
+    }
+  }
+
+  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+  positionPtr = bufferPtr;
+  return result;
+}
+
+void * XMLCALL
+XML_GetBuffer(XML_Parser parser, int len)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return NULL;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return NULL;
+  default: ;
+  }
+
+  if (len > bufferLim - bufferEnd) {
+    /* FIXME avoid integer overflow */
+    int neededSize = len + (int)(bufferEnd - bufferPtr);
+#ifdef XML_CONTEXT_BYTES
+    int keep = (int)(bufferPtr - buffer);
+
+    if (keep > XML_CONTEXT_BYTES)
+      keep = XML_CONTEXT_BYTES;
+    neededSize += keep;
+#endif  /* defined XML_CONTEXT_BYTES */
+    if (neededSize  <= bufferLim - buffer) {
+#ifdef XML_CONTEXT_BYTES
+      if (keep < bufferPtr - buffer) {
+        int offset = (int)(bufferPtr - buffer) - keep;
+        memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
+        bufferEnd -= offset;
+        bufferPtr -= offset;
+      }
+#else
+      memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+      bufferEnd = buffer + (bufferEnd - bufferPtr);
+      bufferPtr = buffer;
+#endif  /* not defined XML_CONTEXT_BYTES */
+    }
+    else {
+      char *newBuf;
+      int bufferSize = (int)(bufferLim - bufferPtr);
+      if (bufferSize == 0)
+        bufferSize = INIT_BUFFER_SIZE;
+      do {
+        bufferSize *= 2;
+      } while (bufferSize < neededSize);
+      newBuf = (char *)MALLOC(bufferSize);
+      if (newBuf == 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        return NULL;
+      }
+      bufferLim = newBuf + bufferSize;
+#ifdef XML_CONTEXT_BYTES
+      if (bufferPtr) {
+        int keep = (int)(bufferPtr - buffer);
+        if (keep > XML_CONTEXT_BYTES)
+          keep = XML_CONTEXT_BYTES;
+        memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
+        FREE(buffer);
+        buffer = newBuf;
+        bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
+        bufferPtr = buffer + keep;
+      }
+      else {
+        bufferEnd = newBuf + (bufferEnd - bufferPtr);
+        bufferPtr = buffer = newBuf;
+      }
+#else
+      if (bufferPtr) {
+        memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+        FREE(buffer);
+      }
+      bufferEnd = newBuf + (bufferEnd - bufferPtr);
+      bufferPtr = buffer = newBuf;
+#endif  /* not defined XML_CONTEXT_BYTES */
+    }
+    eventPtr = eventEndPtr = NULL;
+    positionPtr = NULL;
+  }
+  return bufferEnd;
+}
+
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser parser, XML_Bool resumable)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    if (resumable) {
+      errorCode = XML_ERROR_SUSPENDED;
+      return XML_STATUS_ERROR;
+    }
+    ps_parsing = XML_FINISHED;
+    break;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  default:
+    if (resumable) {
+#ifdef XML_DTD
+      if (isParamEntity) {
+        errorCode = XML_ERROR_SUSPEND_PE;
+        return XML_STATUS_ERROR;
+      }
+#endif
+      ps_parsing = XML_SUSPENDED;
+    }
+    else
+      ps_parsing = XML_FINISHED;
+  }
+  return XML_STATUS_OK;
+}
+
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser parser)
+{
+  enum XML_Status result = XML_STATUS_OK;
+
+  if (ps_parsing != XML_SUSPENDED) {
+    errorCode = XML_ERROR_NOT_SUSPENDED;
+    return XML_STATUS_ERROR;
+  }
+  ps_parsing = XML_PARSING;
+
+  errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+  if (errorCode != XML_ERROR_NONE) {
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+  else {
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      result = XML_STATUS_SUSPENDED;
+      break;
+    case XML_INITIALIZED:
+    case XML_PARSING:
+      if (ps_finalBuffer) {
+        ps_parsing = XML_FINISHED;
+        return result;
+      }
+    default: ;
+    }
+  }
+
+  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+  positionPtr = bufferPtr;
+  return result;
+}
+
+void XMLCALL
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
+{
+  assert(status != NULL);
+  *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+  return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+  if (eventPtr)
+    return parseEndByteIndex - (parseEndPtr - eventPtr);
+  return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+  if (eventEndPtr && eventPtr)
+    return (int)(eventEndPtr - eventPtr);
+  return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+  if (eventPtr && buffer) {
+    *offset = (int)(eventPtr - buffer);
+    *size   = (int)(bufferEnd - buffer);
+    return buffer;
+  }
+#endif /* defined XML_CONTEXT_BYTES */
+  return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+  FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+  return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+  return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+  FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+  if (defaultHandler) {
+    if (openInternalEntities)
+      reportDefault(parser,
+                    internalEncoding,
+                    openInternalEntities->internalEventPtr,
+                    openInternalEntities->internalEventEndPtr);
+    else
+      reportDefault(parser, encoding, eventPtr, eventEndPtr);
+  }
+}
+
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code)
+{
+  static const XML_LChar* const message[] = {
+    0,
+    XML_L("out of memory"),
+    XML_L("syntax error"),
+    XML_L("no element found"),
+    XML_L("not well-formed (invalid token)"),
+    XML_L("unclosed token"),
+    XML_L("partial character"),
+    XML_L("mismatched tag"),
+    XML_L("duplicate attribute"),
+    XML_L("junk after document element"),
+    XML_L("illegal parameter entity reference"),
+    XML_L("undefined entity"),
+    XML_L("recursive entity reference"),
+    XML_L("asynchronous entity"),
+    XML_L("reference to invalid character number"),
+    XML_L("reference to binary entity"),
+    XML_L("reference to external entity in attribute"),
+    XML_L("XML or text declaration not at start of entity"),
+    XML_L("unknown encoding"),
+    XML_L("encoding specified in XML declaration is incorrect"),
+    XML_L("unclosed CDATA section"),
+    XML_L("error in processing external entity reference"),
+    XML_L("document is not standalone"),
+    XML_L("unexpected parser state - please send a bug report"),
+    XML_L("entity declared in parameter entity"),
+    XML_L("requested feature requires XML_DTD support in Expat"),
+    XML_L("cannot change setting once parsing has begun"),
+    XML_L("unbound prefix"),
+    XML_L("must not undeclare prefix"),
+    XML_L("incomplete markup in parameter entity"),
+    XML_L("XML declaration not well-formed"),
+    XML_L("text declaration not well-formed"),
+    XML_L("illegal character(s) in public id"),
+    XML_L("parser suspended"),
+    XML_L("parser not suspended"),
+    XML_L("parsing aborted"),
+    XML_L("parsing finished"),
+    XML_L("cannot suspend in external parameter entity"),
+    XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
+    XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
+    XML_L("prefix must not be bound to one of the reserved namespace names")
+  };
+  if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+    return message[code];
+  return NULL;
+}
+
+const XML_LChar * XMLCALL
+XML_ExpatVersion(void) {
+
+  /* V1 is used to string-ize the version number. However, it would
+     string-ize the actual version macro *names* unless we get them
+     substituted before being passed to V1. CPP is defined to expand
+     a macro, then rescan for more expansions. Thus, we use V2 to expand
+     the version macros, then CPP will expand the resulting V1() macro
+     with the correct numerals. */
+  /* ### I'm assuming cpp is portable in this respect... */
+
+#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
+#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+
+  return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
+
+#undef V1
+#undef V2
+}
+
+XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo(void)
+{
+  XML_Expat_Version version;
+
+  version.major = XML_MAJOR_VERSION;
+  version.minor = XML_MINOR_VERSION;
+  version.micro = XML_MICRO_VERSION;
+
+  return version;
+}
+
+const XML_Feature * XMLCALL
+XML_GetFeatureList(void)
+{
+  static const XML_Feature features[] = {
+    {XML_FEATURE_SIZEOF_XML_CHAR,  XML_L("sizeof(XML_Char)"),
+     sizeof(XML_Char)},
+    {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+     sizeof(XML_LChar)},
+#ifdef XML_UNICODE
+    {XML_FEATURE_UNICODE,          XML_L("XML_UNICODE"), 0},
+#endif
+#ifdef XML_UNICODE_WCHAR_T
+    {XML_FEATURE_UNICODE_WCHAR_T,  XML_L("XML_UNICODE_WCHAR_T"), 0},
+#endif
+#ifdef XML_DTD
+    {XML_FEATURE_DTD,              XML_L("XML_DTD"), 0},
+#endif
+#ifdef XML_CONTEXT_BYTES
+    {XML_FEATURE_CONTEXT_BYTES,    XML_L("XML_CONTEXT_BYTES"),
+     XML_CONTEXT_BYTES},
+#endif
+#ifdef XML_MIN_SIZE
+    {XML_FEATURE_MIN_SIZE,         XML_L("XML_MIN_SIZE"), 0},
+#endif
+#ifdef XML_NS
+    {XML_FEATURE_NS,               XML_L("XML_NS"), 0},
+#endif
+#ifdef XML_LARGE_SIZE
+    {XML_FEATURE_LARGE_SIZE,       XML_L("XML_LARGE_SIZE"), 0},
+#endif
+#ifdef XML_ATTR_INFO
+    {XML_FEATURE_ATTR_INFO,        XML_L("XML_ATTR_INFO"), 0},
+#endif
+    {XML_FEATURE_END,              NULL, 0}
+  };
+
+  return features;
+}
+
+/* Initially tag->rawName always points into the parse buffer;
+   for those TAG instances opened while the current parse buffer was
+   processed, and not yet closed, we need to store tag->rawName in a more
+   permanent location, since the parse buffer is about to be discarded.
+*/
+static XML_Bool
+storeRawNames(XML_Parser parser)
+{
+  TAG *tag = tagStack;
+  while (tag) {
+    int bufSize;
+    int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+    char *rawNameBuf = tag->buf + nameLen;
+    /* Stop if already stored.  Since tagStack is a stack, we can stop
+       at the first entry that has already been copied; everything
+       below it in the stack is already been accounted for in a
+       previous call to this function.
+    */
+    if (tag->rawName == rawNameBuf)
+      break;
+    /* For re-use purposes we need to ensure that the
+       size of tag->buf is a multiple of sizeof(XML_Char).
+    */
+    bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+    if (bufSize > tag->bufEnd - tag->buf) {
+      char *temp = (char *)REALLOC(tag->buf, bufSize);
+      if (temp == NULL)
+        return XML_FALSE;
+      /* if tag->name.str points to tag->buf (only when namespace
+         processing is off) then we have to update it
+      */
+      if (tag->name.str == (XML_Char *)tag->buf)
+        tag->name.str = (XML_Char *)temp;
+      /* if tag->name.localPart is set (when namespace processing is on)
+         then update it as well, since it will always point into tag->buf
+      */
+      if (tag->name.localPart)
+        tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
+                                                  (XML_Char *)tag->buf);
+      tag->buf = temp;
+      tag->bufEnd = temp + bufSize;
+      rawNameBuf = temp + nameLen;
+    }
+    memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
+    tag->rawName = rawNameBuf;
+    tag = tag->parent;
+  }
+  return XML_TRUE;
+}
+
+static enum XML_Error PTRCALL
+contentProcessor(XML_Parser parser,
+                 const char *start,
+                 const char *end,
+                 const char **endPtr)
+{
+  enum XML_Error result = doContent(parser, 0, encoding, start, end,
+                                    endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result == XML_ERROR_NONE) {
+    if (!storeRawNames(parser))
+      return XML_ERROR_NO_MEMORY;
+  }
+  return result;
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor(XML_Parser parser,
+                            const char *start,
+                            const char *end,
+                            const char **endPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+  processor = externalEntityInitProcessor2;
+  return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor2(XML_Parser parser,
+                             const char *start,
+                             const char *end,
+                             const char **endPtr)
+{
+  const char *next = start; /* XmlContentTok doesn't always set the last arg */
+  int tok = XmlContentTok(encoding, start, end, &next);
+  switch (tok) {
+  case XML_TOK_BOM:
+    /* If we are at the end of the buffer, this would cause the next stage,
+       i.e. externalEntityInitProcessor3, to pass control directly to
+       doContent (by detecting XML_TOK_NONE) without processing any xml text
+       declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
+    */
+    if (next == end && !ps_finalBuffer) {
+      *endPtr = next;
+      return XML_ERROR_NONE;
+    }
+    start = next;
+    break;
+  case XML_TOK_PARTIAL:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    eventPtr = start;
+    return XML_ERROR_UNCLOSED_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    eventPtr = start;
+    return XML_ERROR_PARTIAL_CHAR;
+  }
+  processor = externalEntityInitProcessor3;
+  return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor3(XML_Parser parser,
+                             const char *start,
+                             const char *end,
+                             const char **endPtr)
+{
+  int tok;
+  const char *next = start; /* XmlContentTok doesn't always set the last arg */
+  eventPtr = start;
+  tok = XmlContentTok(encoding, start, end, &next);
+  eventEndPtr = next;
+
+  switch (tok) {
+  case XML_TOK_XML_DECL:
+    {
+      enum XML_Error result;
+      result = processXmlDecl(parser, 1, start, next);
+      if (result != XML_ERROR_NONE)
+        return result;
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        *endPtr = next;
+        return XML_ERROR_NONE;
+      case XML_FINISHED:
+        return XML_ERROR_ABORTED;
+      default:
+        start = next;
+      }
+    }
+    break;
+  case XML_TOK_PARTIAL:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_UNCLOSED_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_PARTIAL_CHAR;
+  }
+  processor = externalEntityContentProcessor;
+  tagLevel = 1;
+  return externalEntityContentProcessor(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityContentProcessor(XML_Parser parser,
+                               const char *start,
+                               const char *end,
+                               const char **endPtr)
+{
+  enum XML_Error result = doContent(parser, 1, encoding, start, end,
+                                    endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result == XML_ERROR_NONE) {
+    if (!storeRawNames(parser))
+      return XML_ERROR_NO_MEMORY;
+  }
+  return result;
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+          int startTagLevel,
+          const ENCODING *enc,
+          const char *s,
+          const char *end,
+          const char **nextPtr,
+          XML_Bool haveMore)
+{
+  /* save one level of indirection */
+  DTD * const dtd = _dtd;
+
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+
+  for (;;) {
+    const char *next = s; /* XmlContentTok doesn't always set the last arg */
+    int tok = XmlContentTok(enc, s, end, &next);
+    *eventEndPP = next;
+    switch (tok) {
+    case XML_TOK_TRAILING_CR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      *eventEndPP = end;
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, end);
+      /* We are at the end of the final buffer, should we check for
+         XML_SUSPENDED, XML_FINISHED?
+      */
+      if (startTagLevel == 0)
+        return XML_ERROR_NO_ELEMENTS;
+      if (tagLevel != startTagLevel)
+        return XML_ERROR_ASYNC_ENTITY;
+      *nextPtr = end;
+      return XML_ERROR_NONE;
+    case XML_TOK_NONE:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      if (startTagLevel > 0) {
+        if (tagLevel != startTagLevel)
+          return XML_ERROR_ASYNC_ENTITY;
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_NO_ELEMENTS;
+    case XML_TOK_INVALID:
+      *eventPP = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_ENTITY_REF:
+      {
+        const XML_Char *name;
+        ENTITY *entity;
+        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+                                              s + enc->minBytesPerChar,
+                                              next - enc->minBytesPerChar);
+        if (ch) {
+          if (characterDataHandler)
+            characterDataHandler(handlerArg, &ch, 1);
+          else if (defaultHandler)
+            reportDefault(parser, enc, s, next);
+          break;
+        }
+        name = poolStoreString(&dtd->pool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+        poolDiscard(&dtd->pool);
+        /* First, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal,
+           otherwise call the skipped entity or default handler.
+        */
+        if (!dtd->hasParamEntityRefs || dtd->standalone) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          else if (defaultHandler)
+            reportDefault(parser, enc, s, next);
+          break;
+        }
+        if (entity->open)
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        if (entity->notation)
+          return XML_ERROR_BINARY_ENTITY_REF;
+        if (entity->textPtr) {
+          enum XML_Error result;
+          if (!defaultExpandInternalEntities) {
+            if (skippedEntityHandler)
+              skippedEntityHandler(handlerArg, entity->name, 0);
+            else if (defaultHandler)
+              reportDefault(parser, enc, s, next);
+            break;
+          }
+          result = processInternalEntity(parser, entity, XML_FALSE);
+          if (result != XML_ERROR_NONE)
+            return result;
+        }
+        else if (externalEntityRefHandler) {
+          const XML_Char *context;
+          entity->open = XML_TRUE;
+          context = getContext(parser);
+          entity->open = XML_FALSE;
+          if (!context)
+            return XML_ERROR_NO_MEMORY;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        context,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          poolDiscard(&tempPool);
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        break;
+      }
+    case XML_TOK_START_TAG_NO_ATTS:
+      /* fall through */
+    case XML_TOK_START_TAG_WITH_ATTS:
+      {
+        TAG *tag;
+        enum XML_Error result;
+        XML_Char *toPtr;
+        if (freeTagList) {
+          tag = freeTagList;
+          freeTagList = freeTagList->parent;
+        }
+        else {
+          tag = (TAG *)MALLOC(sizeof(TAG));
+          if (!tag)
+            return XML_ERROR_NO_MEMORY;
+          tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+          if (!tag->buf) {
+            FREE(tag);
+            return XML_ERROR_NO_MEMORY;
+          }
+          tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+        }
+        tag->bindings = NULL;
+        tag->parent = tagStack;
+        tagStack = tag;
+        tag->name.localPart = NULL;
+        tag->name.prefix = NULL;
+        tag->rawName = s + enc->minBytesPerChar;
+        tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+        ++tagLevel;
+        {
+          const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+          const char *fromPtr = tag->rawName;
+          toPtr = (XML_Char *)tag->buf;
+          for (;;) {
+            int bufSize;
+            int convLen;
+            XmlConvert(enc,
+                       &fromPtr, rawNameEnd,
+                       (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+            convLen = (int)(toPtr - (XML_Char *)tag->buf);
+            if (fromPtr == rawNameEnd) {
+              tag->name.strLen = convLen;
+              break;
+            }
+            bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+            {
+              char *temp = (char *)REALLOC(tag->buf, bufSize);
+              if (temp == NULL)
+                return XML_ERROR_NO_MEMORY;
+              tag->buf = temp;
+              tag->bufEnd = temp + bufSize;
+              toPtr = (XML_Char *)temp + convLen;
+            }
+          }
+        }
+        tag->name.str = (XML_Char *)tag->buf;
+        *toPtr = XML_T('\0');
+        result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+        if (result)
+          return result;
+        if (startElementHandler)
+          startElementHandler(handlerArg, tag->name.str,
+                              (const XML_Char **)atts);
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        poolClear(&tempPool);
+        break;
+      }
+    case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+      /* fall through */
+    case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+      {
+        const char *rawName = s + enc->minBytesPerChar;
+        enum XML_Error result;
+        BINDING *bindings = NULL;
+        XML_Bool noElmHandlers = XML_TRUE;
+        TAG_NAME name;
+        name.str = poolStoreString(&tempPool, enc, rawName,
+                                   rawName + XmlNameLength(enc, rawName));
+        if (!name.str)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        result = storeAtts(parser, enc, s, &name, &bindings);
+        if (result)
+          return result;
+        poolFinish(&tempPool);
+        if (startElementHandler) {
+          startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+          noElmHandlers = XML_FALSE;
+        }
+        if (endElementHandler) {
+          if (startElementHandler)
+            *eventPP = *eventEndPP;
+          endElementHandler(handlerArg, name.str);
+          noElmHandlers = XML_FALSE;
+        }
+        if (noElmHandlers && defaultHandler)
+          reportDefault(parser, enc, s, next);
+        poolClear(&tempPool);
+        while (bindings) {
+          BINDING *b = bindings;
+          if (endNamespaceDeclHandler)
+            endNamespaceDeclHandler(handlerArg, b->prefix->name);
+          bindings = bindings->nextTagBinding;
+          b->nextTagBinding = freeBindingList;
+          freeBindingList = b;
+          b->prefix->binding = b->prevPrefixBinding;
+        }
+      }
+      if (tagLevel == 0)
+        return epilogProcessor(parser, next, end, nextPtr);
+      break;
+    case XML_TOK_END_TAG:
+      if (tagLevel == startTagLevel)
+        return XML_ERROR_ASYNC_ENTITY;
+      else {
+        int len;
+        const char *rawName;
+        TAG *tag = tagStack;
+        tagStack = tag->parent;
+        tag->parent = freeTagList;
+        freeTagList = tag;
+        rawName = s + enc->minBytesPerChar*2;
+        len = XmlNameLength(enc, rawName);
+        if (len != tag->rawNameLength
+            || memcmp(tag->rawName, rawName, len) != 0) {
+          *eventPP = rawName;
+          return XML_ERROR_TAG_MISMATCH;
+        }
+        --tagLevel;
+        if (endElementHandler) {
+          const XML_Char *localPart;
+          const XML_Char *prefix;
+          XML_Char *uri;
+          localPart = tag->name.localPart;
+          if (ns && localPart) {
+            /* localPart and prefix may have been overwritten in
+               tag->name.str, since this points to the binding->uri
+               buffer which gets re-used; so we have to add them again
+            */
+            uri = (XML_Char *)tag->name.str + tag->name.uriLen;
+            /* don't need to check for space - already done in storeAtts() */
+            while (*localPart) *uri++ = *localPart++;
+            prefix = (XML_Char *)tag->name.prefix;
+            if (ns_triplets && prefix) {
+              *uri++ = namespaceSeparator;
+              while (*prefix) *uri++ = *prefix++;
+             }
+            *uri = XML_T('\0');
+          }
+          endElementHandler(handlerArg, tag->name.str);
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        while (tag->bindings) {
+          BINDING *b = tag->bindings;
+          if (endNamespaceDeclHandler)
+            endNamespaceDeclHandler(handlerArg, b->prefix->name);
+          tag->bindings = tag->bindings->nextTagBinding;
+          b->nextTagBinding = freeBindingList;
+          freeBindingList = b;
+          b->prefix->binding = b->prevPrefixBinding;
+        }
+        if (tagLevel == 0)
+          return epilogProcessor(parser, next, end, nextPtr);
+      }
+      break;
+    case XML_TOK_CHAR_REF:
+      {
+        int n = XmlCharRefNumber(enc, s);
+        if (n < 0)
+          return XML_ERROR_BAD_CHAR_REF;
+        if (characterDataHandler) {
+          XML_Char buf[XML_ENCODE_MAX];
+          characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_XML_DECL:
+      return XML_ERROR_MISPLACED_XML_PI;
+    case XML_TOK_DATA_NEWLINE:
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    case XML_TOK_CDATA_SECT_OPEN:
+      {
+        enum XML_Error result;
+        if (startCdataSectionHandler)
+          startCdataSectionHandler(handlerArg);
+#if 0
+        /* Suppose you doing a transformation on a document that involves
+           changing only the character data.  You set up a defaultHandler
+           and a characterDataHandler.  The defaultHandler simply copies
+           characters through.  The characterDataHandler does the
+           transformation and writes the characters out escaping them as
+           necessary.  This case will fail to work if we leave out the
+           following two lines (because & and < inside CDATA sections will
+           be incorrectly escaped).
+
+           However, now we have a start/endCdataSectionHandler, so it seems
+           easier to let the user deal with this.
+        */
+        else if (characterDataHandler)
+          characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+        if (result != XML_ERROR_NONE)
+          return result;
+        else if (!next) {
+          processor = cdataSectionProcessor;
+          return result;
+        }
+      }
+      break;
+    case XML_TOK_TRAILING_RSQB:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      if (characterDataHandler) {
+        if (MUST_CONVERT(enc, s)) {
+          ICHAR *dataPtr = (ICHAR *)dataBuf;
+          XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+          characterDataHandler(handlerArg, dataBuf,
+                               (int)(dataPtr - (ICHAR *)dataBuf));
+        }
+        else
+          characterDataHandler(handlerArg,
+                               (XML_Char *)s,
+                               (int)((XML_Char *)end - (XML_Char *)s));
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, end);
+      /* We are at the end of the final buffer, should we check for
+         XML_SUSPENDED, XML_FINISHED?
+      */
+      if (startTagLevel == 0) {
+        *eventPP = end;
+        return XML_ERROR_NO_ELEMENTS;
+      }
+      if (tagLevel != startTagLevel) {
+        *eventPP = end;
+        return XML_ERROR_ASYNC_ENTITY;
+      }
+      *nextPtr = end;
+      return XML_ERROR_NONE;
+    case XML_TOK_DATA_CHARS:
+      {
+        XML_CharacterDataHandler charDataHandler = characterDataHandler;
+        if (charDataHandler) {
+          if (MUST_CONVERT(enc, s)) {
+            for (;;) {
+              ICHAR *dataPtr = (ICHAR *)dataBuf;
+              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = s;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if (s == next)
+                break;
+              *eventPP = s;
+            }
+          }
+          else
+            charDataHandler(handlerArg,
+                            (XML_Char *)s,
+                            (int)((XML_Char *)next - (XML_Char *)s));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_PI:
+      if (!reportProcessingInstruction(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_COMMENT:
+      if (!reportComment(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    default:
+      if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    }
+    *eventPP = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+  /* not reached */
+}
+
+/* Precondition: all arguments must be non-NULL;
+   Purpose:
+   - normalize attributes
+   - check attributes for well-formedness
+   - generate namespace aware attribute names (URI, prefix)
+   - build list of attributes for startElementHandler
+   - default attributes
+   - process namespace declarations (check and report them)
+   - generate namespace aware element name (URI, prefix)
+*/
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *enc,
+          const char *attStr, TAG_NAME *tagNamePtr,
+          BINDING **bindingsPtr)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  ELEMENT_TYPE *elementType;
+  int nDefaultAtts;
+  const XML_Char **appAtts;   /* the attribute list for the application */
+  int attIndex = 0;
+  int prefixLen;
+  int i;
+  int n;
+  XML_Char *uri;
+  int nPrefixes = 0;
+  BINDING *binding;
+  const XML_Char *localPart;
+
+  /* lookup the element type name */
+  elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
+  if (!elementType) {
+    const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
+    if (!name)
+      return XML_ERROR_NO_MEMORY;
+    elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
+                                         sizeof(ELEMENT_TYPE));
+    if (!elementType)
+      return XML_ERROR_NO_MEMORY;
+    if (ns && !setElementTypePrefix(parser, elementType))
+      return XML_ERROR_NO_MEMORY;
+  }
+  nDefaultAtts = elementType->nDefaultAtts;
+
+  /* get the attributes from the tokenizer */
+  n = XmlGetAttributes(enc, attStr, attsSize, atts);
+  if (n + nDefaultAtts > attsSize) {
+    int oldAttsSize = attsSize;
+    ATTRIBUTE *temp;
+#ifdef XML_ATTR_INFO
+    XML_AttrInfo *temp2;
+#endif
+    attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+    temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+    if (temp == NULL)
+      return XML_ERROR_NO_MEMORY;
+    atts = temp;
+#ifdef XML_ATTR_INFO
+    temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+    if (temp2 == NULL)
+      return XML_ERROR_NO_MEMORY;
+    attInfo = temp2;
+#endif
+    if (n > oldAttsSize)
+      XmlGetAttributes(enc, attStr, n, atts);
+  }
+
+  appAtts = (const XML_Char **)atts;
+  for (i = 0; i < n; i++) {
+    ATTRIBUTE *currAtt = &atts[i];
+#ifdef XML_ATTR_INFO
+    XML_AttrInfo *currAttInfo = &attInfo[i];
+#endif
+    /* add the name and value to the attribute list */
+    ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
+                                         currAtt->name
+                                         + XmlNameLength(enc, currAtt->name));
+    if (!attId)
+      return XML_ERROR_NO_MEMORY;
+#ifdef XML_ATTR_INFO
+    currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+    currAttInfo->nameEnd = currAttInfo->nameStart +
+                           XmlNameLength(enc, currAtt->name);
+    currAttInfo->valueStart = parseEndByteIndex -
+                            (parseEndPtr - currAtt->valuePtr);
+    currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+#endif
+    /* Detect duplicate attributes by their QNames. This does not work when
+       namespace processing is turned on and different prefixes for the same
+       namespace are used. For this case we have a check further down.
+    */
+    if ((attId->name)[-1]) {
+      if (enc == encoding)
+        eventPtr = atts[i].name;
+      return XML_ERROR_DUPLICATE_ATTRIBUTE;
+    }
+    (attId->name)[-1] = 1;
+    appAtts[attIndex++] = attId->name;
+    if (!atts[i].normalized) {
+      enum XML_Error result;
+      XML_Bool isCdata = XML_TRUE;
+
+      /* figure out whether declared as other than CDATA */
+      if (attId->maybeTokenized) {
+        int j;
+        for (j = 0; j < nDefaultAtts; j++) {
+          if (attId == elementType->defaultAtts[j].id) {
+            isCdata = elementType->defaultAtts[j].isCdata;
+            break;
+          }
+        }
+      }
+
+      /* normalize the attribute value */
+      result = storeAttributeValue(parser, enc, isCdata,
+                                   atts[i].valuePtr, atts[i].valueEnd,
+                                   &tempPool);
+      if (result)
+        return result;
+      appAtts[attIndex] = poolStart(&tempPool);
+      poolFinish(&tempPool);
+    }
+    else {
+      /* the value did not need normalizing */
+      appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
+                                          atts[i].valueEnd);
+      if (appAtts[attIndex] == 0)
+        return XML_ERROR_NO_MEMORY;
+      poolFinish(&tempPool);
+    }
+    /* handle prefixed attribute names */
+    if (attId->prefix) {
+      if (attId->xmlns) {
+        /* deal with namespace declarations here */
+        enum XML_Error result = addBinding(parser, attId->prefix, attId,
+                                           appAtts[attIndex], bindingsPtr);
+        if (result)
+          return result;
+        --attIndex;
+      }
+      else {
+        /* deal with other prefixed names later */
+        attIndex++;
+        nPrefixes++;
+        (attId->name)[-1] = 2;
+      }
+    }
+    else
+      attIndex++;
+  }
+
+  /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+  nSpecifiedAtts = attIndex;
+  if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+    for (i = 0; i < attIndex; i += 2)
+      if (appAtts[i] == elementType->idAtt->name) {
+        idAttIndex = i;
+        break;
+      }
+  }
+  else
+    idAttIndex = -1;
+
+  /* do attribute defaulting */
+  for (i = 0; i < nDefaultAtts; i++) {
+    const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
+    if (!(da->id->name)[-1] && da->value) {
+      if (da->id->prefix) {
+        if (da->id->xmlns) {
+          enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
+                                             da->value, bindingsPtr);
+          if (result)
+            return result;
+        }
+        else {
+          (da->id->name)[-1] = 2;
+          nPrefixes++;
+          appAtts[attIndex++] = da->id->name;
+          appAtts[attIndex++] = da->value;
+        }
+      }
+      else {
+        (da->id->name)[-1] = 1;
+        appAtts[attIndex++] = da->id->name;
+        appAtts[attIndex++] = da->value;
+      }
+    }
+  }
+  appAtts[attIndex] = 0;
+
+  /* expand prefixed attribute names, check for duplicates,
+     and clear flags that say whether attributes were specified */
+  i = 0;
+  if (nPrefixes) {
+    int j;  /* hash table index */
+    unsigned long version = nsAttsVersion;
+    int nsAttsSize = (int)1 << nsAttsPower;
+    /* size of hash table must be at least 2 * (# of prefixed attributes) */
+    if ((nPrefixes << 1) >> nsAttsPower) {  /* true for nsAttsPower = 0 */
+      NS_ATT *temp;
+      /* hash table size must also be a power of 2 and >= 8 */
+      while (nPrefixes >> nsAttsPower++);
+      if (nsAttsPower < 3)
+        nsAttsPower = 3;
+      nsAttsSize = (int)1 << nsAttsPower;
+      temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+      if (!temp)
+        return XML_ERROR_NO_MEMORY;
+      nsAtts = temp;
+      version = 0;  /* force re-initialization of nsAtts hash table */
+    }
+    /* using a version flag saves us from initializing nsAtts every time */
+    if (!version) {  /* initialize version flags when version wraps around */
+      version = INIT_ATTS_VERSION;
+      for (j = nsAttsSize; j != 0; )
+        nsAtts[--j].version = version;
+    }
+    nsAttsVersion = --version;
+
+    /* expand prefixed names and check for duplicates */
+    for (; i < attIndex; i += 2) {
+      const XML_Char *s = appAtts[i];
+      if (s[-1] == 2) {  /* prefixed */
+        ATTRIBUTE_ID *id;
+        const BINDING *b;
+        unsigned long uriHash = hash_secret_salt;
+        ((XML_Char *)s)[-1] = 0;  /* clear flag */
+        id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+        b = id->prefix->binding;
+        if (!b)
+          return XML_ERROR_UNBOUND_PREFIX;
+
+        /* as we expand the name we also calculate its hash value */
+        for (j = 0; j < b->uriLen; j++) {
+          const XML_Char c = b->uri[j];
+          if (!poolAppendChar(&tempPool, c))
+            return XML_ERROR_NO_MEMORY;
+          uriHash = CHAR_HASH(uriHash, c);
+        }
+        while (*s++ != XML_T(ASCII_COLON))
+          ;
+        do {  /* copies null terminator */
+          const XML_Char c = *s;
+          if (!poolAppendChar(&tempPool, *s))
+            return XML_ERROR_NO_MEMORY;
+          uriHash = CHAR_HASH(uriHash, c);
+        } while (*s++);
+
+        { /* Check hash table for duplicate of expanded name (uriName).
+             Derived from code in lookup(parser, HASH_TABLE *table, ...).
+          */
+          unsigned char step = 0;
+          unsigned long mask = nsAttsSize - 1;
+          j = uriHash & mask;  /* index into hash table */
+          while (nsAtts[j].version == version) {
+            /* for speed we compare stored hash values first */
+            if (uriHash == nsAtts[j].hash) {
+              const XML_Char *s1 = poolStart(&tempPool);
+              const XML_Char *s2 = nsAtts[j].uriName;
+              /* s1 is null terminated, but not s2 */
+              for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+              if (*s1 == 0)
+                return XML_ERROR_DUPLICATE_ATTRIBUTE;
+            }
+            if (!step)
+              step = PROBE_STEP(uriHash, mask, nsAttsPower);
+            j < step ? (j += nsAttsSize - step) : (j -= step);
+          }
+        }
+
+        if (ns_triplets) {  /* append namespace separator and prefix */
+          tempPool.ptr[-1] = namespaceSeparator;
+          s = b->prefix->name;
+          do {
+            if (!poolAppendChar(&tempPool, *s))
+              return XML_ERROR_NO_MEMORY;
+          } while (*s++);
+        }
+
+        /* store expanded name in attribute list */
+        s = poolStart(&tempPool);
+        poolFinish(&tempPool);
+        appAtts[i] = s;
+
+        /* fill empty slot with new version, uriName and hash value */
+        nsAtts[j].version = version;
+        nsAtts[j].hash = uriHash;
+        nsAtts[j].uriName = s;
+
+        if (!--nPrefixes) {
+          i += 2;
+          break;
+        }
+      }
+      else  /* not prefixed */
+        ((XML_Char *)s)[-1] = 0;  /* clear flag */
+    }
+  }
+  /* clear flags for the remaining attributes */
+  for (; i < attIndex; i += 2)
+    ((XML_Char *)(appAtts[i]))[-1] = 0;
+  for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+    binding->attId->name[-1] = 0;
+
+  if (!ns)
+    return XML_ERROR_NONE;
+
+  /* expand the element type name */
+  if (elementType->prefix) {
+    binding = elementType->prefix->binding;
+    if (!binding)
+      return XML_ERROR_UNBOUND_PREFIX;
+    localPart = tagNamePtr->str;
+    while (*localPart++ != XML_T(ASCII_COLON))
+      ;
+  }
+  else if (dtd->defaultPrefix.binding) {
+    binding = dtd->defaultPrefix.binding;
+    localPart = tagNamePtr->str;
+  }
+  else
+    return XML_ERROR_NONE;
+  prefixLen = 0;
+  if (ns_triplets && binding->prefix->name) {
+    for (; binding->prefix->name[prefixLen++];)
+      ;  /* prefixLen includes null terminator */
+  }
+  tagNamePtr->localPart = localPart;
+  tagNamePtr->uriLen = binding->uriLen;
+  tagNamePtr->prefix = binding->prefix->name;
+  tagNamePtr->prefixLen = prefixLen;
+  for (i = 0; localPart[i++];)
+    ;  /* i includes null terminator */
+  n = i + binding->uriLen + prefixLen;
+  if (n > binding->uriAlloc) {
+    TAG *p;
+    uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+    if (!uri)
+      return XML_ERROR_NO_MEMORY;
+    binding->uriAlloc = n + EXPAND_SPARE;
+    memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
+    for (p = tagStack; p; p = p->parent)
+      if (p->name.str == binding->uri)
+        p->name.str = uri;
+    FREE(binding->uri);
+    binding->uri = uri;
+  }
+  /* if namespaceSeparator != '\0' then uri includes it already */
+  uri = binding->uri + binding->uriLen;
+  memcpy(uri, localPart, i * sizeof(XML_Char));
+  /* we always have a namespace separator between localPart and prefix */
+  if (prefixLen) {
+    uri += i - 1;
+    *uri = namespaceSeparator;  /* replace null terminator */
+    memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
+  }
+  tagNamePtr->str = binding->uri;
+  return XML_ERROR_NONE;
+}
+
+/* addBinding() overwrites the value of prefix->binding without checking.
+   Therefore one must keep track of the old value outside of addBinding().
+*/
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+           const XML_Char *uri, BINDING **bindingsPtr)
+{
+  static const XML_Char xmlNamespace[] = {
+    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
+    ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
+    ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
+    ASCII_e, '\0'
+  };
+  static const int xmlLen =
+    (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
+  static const XML_Char xmlnsNamespace[] = {
+    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
+    ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
+    ASCII_SLASH, '\0'
+  };
+  static const int xmlnsLen =
+    (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+
+  XML_Bool mustBeXML = XML_FALSE;
+  XML_Bool isXML = XML_TRUE;
+  XML_Bool isXMLNS = XML_TRUE;
+
+  BINDING *b;
+  int len;
+
+  /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
+  if (*uri == XML_T('\0') && prefix->name)
+    return XML_ERROR_UNDECLARING_PREFIX;
+
+  if (prefix->name
+      && prefix->name[0] == XML_T(ASCII_x)
+      && prefix->name[1] == XML_T(ASCII_m)
+      && prefix->name[2] == XML_T(ASCII_l)) {
+
+    /* Not allowed to bind xmlns */
+    if (prefix->name[3] == XML_T(ASCII_n)
+        && prefix->name[4] == XML_T(ASCII_s)
+        && prefix->name[5] == XML_T('\0'))
+      return XML_ERROR_RESERVED_PREFIX_XMLNS;
+
+    if (prefix->name[3] == XML_T('\0'))
+      mustBeXML = XML_TRUE;
+  }
+
+  for (len = 0; uri[len]; len++) {
+    if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
+      isXML = XML_FALSE;
+
+    if (!mustBeXML && isXMLNS
+        && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
+      isXMLNS = XML_FALSE;
+  }
+  isXML = isXML && len == xmlLen;
+  isXMLNS = isXMLNS && len == xmlnsLen;
+
+  if (mustBeXML != isXML)
+    return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+                     : XML_ERROR_RESERVED_NAMESPACE_URI;
+
+  if (isXMLNS)
+    return XML_ERROR_RESERVED_NAMESPACE_URI;
+
+  if (namespaceSeparator)
+    len++;
+  if (freeBindingList) {
+    b = freeBindingList;
+    if (len > b->uriAlloc) {
+      XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+                          sizeof(XML_Char) * (len + EXPAND_SPARE));
+      if (temp == NULL)
+        return XML_ERROR_NO_MEMORY;
+      b->uri = temp;
+      b->uriAlloc = len + EXPAND_SPARE;
+    }
+    freeBindingList = b->nextTagBinding;
+  }
+  else {
+    b = (BINDING *)MALLOC(sizeof(BINDING));
+    if (!b)
+      return XML_ERROR_NO_MEMORY;
+    b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+    if (!b->uri) {
+      FREE(b);
+      return XML_ERROR_NO_MEMORY;
+    }
+    b->uriAlloc = len + EXPAND_SPARE;
+  }
+  b->uriLen = len;
+  memcpy(b->uri, uri, len * sizeof(XML_Char));
+  if (namespaceSeparator)
+    b->uri[len - 1] = namespaceSeparator;
+  b->prefix = prefix;
+  b->attId = attId;
+  b->prevPrefixBinding = prefix->binding;
+  /* NULL binding when default namespace undeclared */
+  if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+    prefix->binding = NULL;
+  else
+    prefix->binding = b;
+  b->nextTagBinding = *bindingsPtr;
+  *bindingsPtr = b;
+  /* if attId == NULL then we are not starting a namespace scope */
+  if (attId && startNamespaceDeclHandler)
+    startNamespaceDeclHandler(handlerArg, prefix->name,
+                              prefix->binding ? uri : 0);
+  return XML_ERROR_NONE;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+   the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+cdataSectionProcessor(XML_Parser parser,
+                      const char *start,
+                      const char *end,
+                      const char **endPtr)
+{
+  enum XML_Error result = doCdataSection(parser, encoding, &start, end,
+                                         endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result != XML_ERROR_NONE)
+    return result;
+  if (start) {
+    if (parentParser) {  /* we are parsing an external entity */
+      processor = externalEntityContentProcessor;
+      return externalEntityContentProcessor(parser, start, end, endPtr);
+    }
+    else {
+      processor = contentProcessor;
+      return contentProcessor(parser, start, end, endPtr);
+    }
+  }
+  return result;
+}
+
+/* startPtr gets set to non-null if the section is closed, and to null if
+   the section is not yet closed.
+*/
+static enum XML_Error
+doCdataSection(XML_Parser parser,
+               const ENCODING *enc,
+               const char **startPtr,
+               const char *end,
+               const char **nextPtr,
+               XML_Bool haveMore)
+{
+  const char *s = *startPtr;
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    *eventPP = s;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+  *startPtr = NULL;
+
+  for (;;) {
+    const char *next;
+    int tok = XmlCdataSectionTok(enc, s, end, &next);
+    *eventEndPP = next;
+    switch (tok) {
+    case XML_TOK_CDATA_SECT_CLOSE:
+      if (endCdataSectionHandler)
+        endCdataSectionHandler(handlerArg);
+#if 0
+      /* see comment under XML_TOK_CDATA_SECT_OPEN */
+      else if (characterDataHandler)
+        characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      *startPtr = next;
+      *nextPtr = next;
+      if (ps_parsing == XML_FINISHED)
+        return XML_ERROR_ABORTED;
+      else
+        return XML_ERROR_NONE;
+    case XML_TOK_DATA_NEWLINE:
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    case XML_TOK_DATA_CHARS:
+      {
+        XML_CharacterDataHandler charDataHandler = characterDataHandler;
+        if (charDataHandler) {
+          if (MUST_CONVERT(enc, s)) {
+            for (;;) {
+              ICHAR *dataPtr = (ICHAR *)dataBuf;
+              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = next;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if (s == next)
+                break;
+              *eventPP = s;
+            }
+          }
+          else
+            charDataHandler(handlerArg,
+                            (XML_Char *)s,
+                            (int)((XML_Char *)next - (XML_Char *)s));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_INVALID:
+      *eventPP = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_PARTIAL:
+    case XML_TOK_NONE:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_CDATA_SECTION;
+    default:
+      *eventPP = next;
+      return XML_ERROR_UNEXPECTED_STATE;
+    }
+
+    *eventPP = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+  /* not reached */
+}
+
+#ifdef XML_DTD
+
+/* The idea here is to avoid using stack for each IGNORE section when
+   the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+ignoreSectionProcessor(XML_Parser parser,
+                       const char *start,
+                       const char *end,
+                       const char **endPtr)
+{
+  enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
+                                          endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result != XML_ERROR_NONE)
+    return result;
+  if (start) {
+    processor = prologProcessor;
+    return prologProcessor(parser, start, end, endPtr);
+  }
+  return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null
+   if the section is not yet closed.
+*/
+static enum XML_Error
+doIgnoreSection(XML_Parser parser,
+                const ENCODING *enc,
+                const char **startPtr,
+                const char *end,
+                const char **nextPtr,
+                XML_Bool haveMore)
+{
+  const char *next;
+  int tok;
+  const char *s = *startPtr;
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    *eventPP = s;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+  *startPtr = NULL;
+  tok = XmlIgnoreSectionTok(enc, s, end, &next);
+  *eventEndPP = next;
+  switch (tok) {
+  case XML_TOK_IGNORE_SECT:
+    if (defaultHandler)
+      reportDefault(parser, enc, s, next);
+    *startPtr = next;
+    *nextPtr = next;
+    if (ps_parsing == XML_FINISHED)
+      return XML_ERROR_ABORTED;
+    else
+      return XML_ERROR_NONE;
+  case XML_TOK_INVALID:
+    *eventPP = next;
+    return XML_ERROR_INVALID_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (haveMore) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_PARTIAL_CHAR;
+  case XML_TOK_PARTIAL:
+  case XML_TOK_NONE:
+    if (haveMore) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
+  default:
+    *eventPP = next;
+    return XML_ERROR_UNEXPECTED_STATE;
+  }
+  /* not reached */
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+  const char *s;
+#ifdef XML_UNICODE
+  char encodingBuf[128];
+  if (!protocolEncodingName)
+    s = NULL;
+  else {
+    int i;
+    for (i = 0; protocolEncodingName[i]; i++) {
+      if (i == sizeof(encodingBuf) - 1
+          || (protocolEncodingName[i] & ~0x7f) != 0) {
+        encodingBuf[0] = '\0';
+        break;
+      }
+      encodingBuf[i] = (char)protocolEncodingName[i];
+    }
+    encodingBuf[i] = '\0';
+    s = encodingBuf;
+  }
+#else
+  s = protocolEncodingName;
+#endif
+  if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+    return XML_ERROR_NONE;
+  return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+               const char *s, const char *next)
+{
+  const char *encodingName = NULL;
+  const XML_Char *storedEncName = NULL;
+  const ENCODING *newEncoding = NULL;
+  const char *version = NULL;
+  const char *versionend;
+  const XML_Char *storedversion = NULL;
+  int standalone = -1;
+  if (!(ns
+        ? XmlParseXmlDeclNS
+        : XmlParseXmlDecl)(isGeneralTextEntity,
+                           encoding,
+                           s,
+                           next,
+                           &eventPtr,
+                           &version,
+                           &versionend,
+                           &encodingName,
+                           &newEncoding,
+                           &standalone)) {
+    if (isGeneralTextEntity)
+      return XML_ERROR_TEXT_DECL;
+    else
+      return XML_ERROR_XML_DECL;
+  }
+  if (!isGeneralTextEntity && standalone == 1) {
+    _dtd->standalone = XML_TRUE;
+#ifdef XML_DTD
+    if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+      paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif /* XML_DTD */
+  }
+  if (xmlDeclHandler) {
+    if (encodingName != NULL) {
+      storedEncName = poolStoreString(&temp2Pool,
+                                      encoding,
+                                      encodingName,
+                                      encodingName
+                                      + XmlNameLength(encoding, encodingName));
+      if (!storedEncName)
+              return XML_ERROR_NO_MEMORY;
+      poolFinish(&temp2Pool);
+    }
+    if (version) {
+      storedversion = poolStoreString(&temp2Pool,
+                                      encoding,
+                                      version,
+                                      versionend - encoding->minBytesPerChar);
+      if (!storedversion)
+        return XML_ERROR_NO_MEMORY;
+    }
+    xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+  }
+  else if (defaultHandler)
+    reportDefault(parser, encoding, s, next);
+  if (protocolEncodingName == NULL) {
+    if (newEncoding) {
+      if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
+        eventPtr = encodingName;
+        return XML_ERROR_INCORRECT_ENCODING;
+      }
+      encoding = newEncoding;
+    }
+    else if (encodingName) {
+      enum XML_Error result;
+      if (!storedEncName) {
+        storedEncName = poolStoreString(
+          &temp2Pool, encoding, encodingName,
+          encodingName + XmlNameLength(encoding, encodingName));
+        if (!storedEncName)
+          return XML_ERROR_NO_MEMORY;
+      }
+      result = handleUnknownEncoding(parser, storedEncName);
+      poolClear(&temp2Pool);
+      if (result == XML_ERROR_UNKNOWN_ENCODING)
+        eventPtr = encodingName;
+      return result;
+    }
+  }
+
+  if (storedEncName || storedversion)
+    poolClear(&temp2Pool);
+
+  return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+  if (unknownEncodingHandler) {
+    XML_Encoding info;
+    int i;
+    for (i = 0; i < 256; i++)
+      info.map[i] = -1;
+    info.convert = NULL;
+    info.data = NULL;
+    info.release = NULL;
+    if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+                               &info)) {
+      ENCODING *enc;
+      unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
+      if (!unknownEncodingMem) {
+        if (info.release)
+          info.release(info.data);
+        return XML_ERROR_NO_MEMORY;
+      }
+      enc = (ns
+             ? XmlInitUnknownEncodingNS
+             : XmlInitUnknownEncoding)(unknownEncodingMem,
+                                       info.map,
+                                       info.convert,
+                                       info.data);
+      if (enc) {
+        unknownEncodingData = info.data;
+        unknownEncodingRelease = info.release;
+        encoding = enc;
+        return XML_ERROR_NONE;
+      }
+    }
+    if (info.release != NULL)
+      info.release(info.data);
+  }
+  return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error PTRCALL
+prologInitProcessor(XML_Parser parser,
+                    const char *s,
+                    const char *end,
+                    const char **nextPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+  processor = prologProcessor;
+  return prologProcessor(parser, s, end, nextPtr);
+}
+
+#ifdef XML_DTD
+
+static enum XML_Error PTRCALL
+externalParEntInitProcessor(XML_Parser parser,
+                            const char *s,
+                            const char *end,
+                            const char **nextPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+
+  /* we know now that XML_Parse(Buffer) has been called,
+     so we consider the external parameter entity read */
+  _dtd->paramEntityRead = XML_TRUE;
+
+  if (prologState.inEntityValue) {
+    processor = entityValueInitProcessor;
+    return entityValueInitProcessor(parser, s, end, nextPtr);
+  }
+  else {
+    processor = externalParEntProcessor;
+    return externalParEntProcessor(parser, s, end, nextPtr);
+  }
+}
+
+static enum XML_Error PTRCALL
+entityValueInitProcessor(XML_Parser parser,
+                         const char *s,
+                         const char *end,
+                         const char **nextPtr)
+{
+  int tok;
+  const char *start = s;
+  const char *next = start;
+  eventPtr = start;
+
+  for (;;) {
+    tok = XmlPrologTok(encoding, start, end, &next);
+    eventEndPtr = next;
+    if (tok <= 0) {
+      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case XML_TOK_NONE:   /* start == end */
+      default:
+        break;
+      }
+      /* found end of entity value - can store it now */
+      return storeEntityValue(parser, encoding, s, end);
+    }
+    else if (tok == XML_TOK_XML_DECL) {
+      enum XML_Error result;
+      result = processXmlDecl(parser, 0, start, next);
+      if (result != XML_ERROR_NONE)
+        return result;
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        *nextPtr = next;
+        return XML_ERROR_NONE;
+      case XML_FINISHED:
+        return XML_ERROR_ABORTED;
+      default:
+        *nextPtr = next;
+      }
+      /* stop scanning for text declaration - we found one */
+      processor = entityValueProcessor;
+      return entityValueProcessor(parser, next, end, nextPtr);
+    }
+    /* If we are at the end of the buffer, this would cause XmlPrologTok to
+       return XML_TOK_NONE on the next call, which would then cause the
+       function to exit with *nextPtr set to s - that is what we want for other
+       tokens, but not for the BOM - we would rather like to skip it;
+       then, when this routine is entered the next time, XmlPrologTok will
+       return XML_TOK_INVALID, since the BOM is still in the buffer
+    */
+    else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    }
+    start = next;
+    eventPtr = start;
+  }
+}
+
+static enum XML_Error PTRCALL
+externalParEntProcessor(XML_Parser parser,
+                        const char *s,
+                        const char *end,
+                        const char **nextPtr)
+{
+  const char *next = s;
+  int tok;
+
+  tok = XmlPrologTok(encoding, s, end, &next);
+  if (tok <= 0) {
+    if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    switch (tok) {
+    case XML_TOK_INVALID:
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_NONE:   /* start == end */
+    default:
+      break;
+    }
+  }
+  /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+     However, when parsing an external subset, doProlog will not accept a BOM
+     as valid, and report a syntax error, so we have to skip the BOM
+  */
+  else if (tok == XML_TOK_BOM) {
+    s = next;
+    tok = XmlPrologTok(encoding, s, end, &next);
+  }
+
+  processor = prologProcessor;
+  return doProlog(parser, encoding, s, end, tok, next,
+                  nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error PTRCALL
+entityValueProcessor(XML_Parser parser,
+                     const char *s,
+                     const char *end,
+                     const char **nextPtr)
+{
+  const char *start = s;
+  const char *next = s;
+  const ENCODING *enc = encoding;
+  int tok;
+
+  for (;;) {
+    tok = XmlPrologTok(enc, start, end, &next);
+    if (tok <= 0) {
+      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case XML_TOK_NONE:   /* start == end */
+      default:
+        break;
+      }
+      /* found end of entity value - can store it now */
+      return storeEntityValue(parser, enc, s, end);
+    }
+    start = next;
+  }
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error PTRCALL
+prologProcessor(XML_Parser parser,
+                const char *s,
+                const char *end,
+                const char **nextPtr)
+{
+  const char *next = s;
+  int tok = XmlPrologTok(encoding, s, end, &next);
+  return doProlog(parser, encoding, s, end, tok, next,
+                  nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error
+doProlog(XML_Parser parser,
+         const ENCODING *enc,
+         const char *s,
+         const char *end,
+         int tok,
+         const char *next,
+         const char **nextPtr,
+         XML_Bool haveMore)
+{
+#ifdef XML_DTD
+  static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
+#endif /* XML_DTD */
+  static const XML_Char atypeCDATA[] =
+      { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+  static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
+  static const XML_Char atypeIDREF[] =
+      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+  static const XML_Char atypeIDREFS[] =
+      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+  static const XML_Char atypeENTITY[] =
+      { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+  static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
+      ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
+  static const XML_Char atypeNMTOKEN[] = {
+      ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+  static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
+      ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
+  static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
+      ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
+  static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
+  static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
+
+  /* save one level of indirection */
+  DTD * const dtd = _dtd;
+
+  const char **eventPP;
+  const char **eventEndPP;
+  enum XML_Content_Quant quant;
+
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+
+  for (;;) {
+    int role;
+    XML_Bool handleDefault = XML_TRUE;
+    *eventPP = s;
+    *eventEndPP = next;
+    if (tok <= 0) {
+      if (haveMore && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        *eventPP = next;
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case -XML_TOK_PROLOG_S:
+        tok = -tok;
+        break;
+      case XML_TOK_NONE:
+#ifdef XML_DTD
+        /* for internal PE NOT referenced between declarations */
+        if (enc != encoding && !openInternalEntities->betweenDecl) {
+          *nextPtr = s;
+          return XML_ERROR_NONE;
+        }
+        /* WFC: PE Between Declarations - must check that PE contains
+           complete markup, not only for external PEs, but also for
+           internal PEs if the reference occurs between declarations.
+        */
+        if (isParamEntity || enc != encoding) {
+          if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+              == XML_ROLE_ERROR)
+            return XML_ERROR_INCOMPLETE_PE;
+          *nextPtr = s;
+          return XML_ERROR_NONE;
+        }
+#endif /* XML_DTD */
+        return XML_ERROR_NO_ELEMENTS;
+      default:
+        tok = -tok;
+        next = end;
+        break;
+      }
+    }
+    role = XmlTokenRole(&prologState, tok, s, next, enc);
+    switch (role) {
+    case XML_ROLE_XML_DECL:
+      {
+        enum XML_Error result = processXmlDecl(parser, 0, s, next);
+        if (result != XML_ERROR_NONE)
+          return result;
+        enc = encoding;
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_NAME:
+      if (startDoctypeDeclHandler) {
+        doctypeName = poolStoreString(&tempPool, enc, s, next);
+        if (!doctypeName)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        doctypePubid = NULL;
+        handleDefault = XML_FALSE;
+      }
+      doctypeSysid = NULL; /* always initialize to NULL */
+      break;
+    case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
+      if (startDoctypeDeclHandler) {
+        startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
+                                doctypePubid, 1);
+        doctypeName = NULL;
+        poolClear(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+#ifdef XML_DTD
+    case XML_ROLE_TEXT_DECL:
+      {
+        enum XML_Error result = processXmlDecl(parser, 1, s, next);
+        if (result != XML_ERROR_NONE)
+          return result;
+        enc = encoding;
+        handleDefault = XML_FALSE;
+      }
+      break;
+#endif /* XML_DTD */
+    case XML_ROLE_DOCTYPE_PUBLIC_ID:
+#ifdef XML_DTD
+      useForeignDTD = XML_FALSE;
+      declEntity = (ENTITY *)lookup(parser,
+                                    &dtd->paramEntities,
+                                    externalSubsetName,
+                                    sizeof(ENTITY));
+      if (!declEntity)
+        return XML_ERROR_NO_MEMORY;
+#endif /* XML_DTD */
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (startDoctypeDeclHandler) {
+        XML_Char *pubId;
+        if (!XmlIsPublicId(enc, s, next, eventPP))
+          return XML_ERROR_PUBLICID;
+        pubId = poolStoreString(&tempPool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!pubId)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(pubId);
+        poolFinish(&tempPool);
+        doctypePubid = pubId;
+        handleDefault = XML_FALSE;
+        goto alreadyChecked;
+      }
+      /* fall through */
+    case XML_ROLE_ENTITY_PUBLIC_ID:
+      if (!XmlIsPublicId(enc, s, next, eventPP))
+        return XML_ERROR_PUBLICID;
+    alreadyChecked:
+      if (dtd->keepProcessing && declEntity) {
+        XML_Char *tem = poolStoreString(&dtd->pool,
+                                        enc,
+                                        s + enc->minBytesPerChar,
+                                        next - enc->minBytesPerChar);
+        if (!tem)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(tem);
+        declEntity->publicId = tem;
+        poolFinish(&dtd->pool);
+        if (entityDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_CLOSE:
+      if (doctypeName) {
+        startDoctypeDeclHandler(handlerArg, doctypeName,
+                                doctypeSysid, doctypePubid, 0);
+        poolClear(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      /* doctypeSysid will be non-NULL in the case of a previous
+         XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+         was not set, indicating an external subset
+      */
+#ifdef XML_DTD
+      if (doctypeSysid || useForeignDTD) {
+        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+        dtd->hasParamEntityRefs = XML_TRUE;
+        if (paramEntityParsing && externalEntityRefHandler) {
+          ENTITY *entity = (ENTITY *)lookup(parser,
+                                            &dtd->paramEntities,
+                                            externalSubsetName,
+                                            sizeof(ENTITY));
+          if (!entity)
+            return XML_ERROR_NO_MEMORY;
+          if (useForeignDTD)
+            entity->base = curBase;
+          dtd->paramEntityRead = XML_FALSE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          if (dtd->paramEntityRead) {
+            if (!dtd->standalone &&
+                notStandaloneHandler &&
+                !notStandaloneHandler(handlerArg))
+              return XML_ERROR_NOT_STANDALONE;
+          }
+          /* if we didn't read the foreign DTD then this means that there
+             is no external subset and we must reset dtd->hasParamEntityRefs
+          */
+          else if (!doctypeSysid)
+            dtd->hasParamEntityRefs = hadParamEntityRefs;
+          /* end of DTD - no need to update dtd->keepProcessing */
+        }
+        useForeignDTD = XML_FALSE;
+      }
+#endif /* XML_DTD */
+      if (endDoctypeDeclHandler) {
+        endDoctypeDeclHandler(handlerArg);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_INSTANCE_START:
+#ifdef XML_DTD
+      /* if there is no DOCTYPE declaration then now is the
+         last chance to read the foreign DTD
+      */
+      if (useForeignDTD) {
+        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+        dtd->hasParamEntityRefs = XML_TRUE;
+        if (paramEntityParsing && externalEntityRefHandler) {
+          ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+                                            externalSubsetName,
+                                            sizeof(ENTITY));
+          if (!entity)
+            return XML_ERROR_NO_MEMORY;
+          entity->base = curBase;
+          dtd->paramEntityRead = XML_FALSE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          if (dtd->paramEntityRead) {
+            if (!dtd->standalone &&
+                notStandaloneHandler &&
+                !notStandaloneHandler(handlerArg))
+              return XML_ERROR_NOT_STANDALONE;
+          }
+          /* if we didn't read the foreign DTD then this means that there
+             is no external subset and we must reset dtd->hasParamEntityRefs
+          */
+          else
+            dtd->hasParamEntityRefs = hadParamEntityRefs;
+          /* end of DTD - no need to update dtd->keepProcessing */
+        }
+      }
+#endif /* XML_DTD */
+      processor = contentProcessor;
+      return contentProcessor(parser, s, end, nextPtr);
+    case XML_ROLE_ATTLIST_ELEMENT_NAME:
+      declElementType = getElementType(parser, enc, s, next);
+      if (!declElementType)
+        return XML_ERROR_NO_MEMORY;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_NAME:
+      declAttributeId = getAttributeId(parser, enc, s, next);
+      if (!declAttributeId)
+        return XML_ERROR_NO_MEMORY;
+      declAttributeIsCdata = XML_FALSE;
+      declAttributeType = NULL;
+      declAttributeIsId = XML_FALSE;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+      declAttributeIsCdata = XML_TRUE;
+      declAttributeType = atypeCDATA;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ID:
+      declAttributeIsId = XML_TRUE;
+      declAttributeType = atypeID;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
+      declAttributeType = atypeIDREF;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
+      declAttributeType = atypeIDREFS;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
+      declAttributeType = atypeENTITY;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
+      declAttributeType = atypeENTITIES;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
+      declAttributeType = atypeNMTOKEN;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
+      declAttributeType = atypeNMTOKENS;
+    checkAttListDeclHandler:
+      if (dtd->keepProcessing && attlistDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
+    case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
+      if (dtd->keepProcessing && attlistDeclHandler) {
+        const XML_Char *prefix;
+        if (declAttributeType) {
+          prefix = enumValueSep;
+        }
+        else {
+          prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
+                    ? notationPrefix
+                    : enumValueStart);
+        }
+        if (!poolAppendString(&tempPool, prefix))
+          return XML_ERROR_NO_MEMORY;
+        if (!poolAppend(&tempPool, enc, s, next))
+          return XML_ERROR_NO_MEMORY;
+        declAttributeType = tempPool.start;
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+    case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+      if (dtd->keepProcessing) {
+        if (!defineAttribute(declElementType, declAttributeId,
+                             declAttributeIsCdata, declAttributeIsId,
+                             0, parser))
+          return XML_ERROR_NO_MEMORY;
+        if (attlistDeclHandler && declAttributeType) {
+          if (*declAttributeType == XML_T(ASCII_LPAREN)
+              || (*declAttributeType == XML_T(ASCII_N)
+                  && declAttributeType[1] == XML_T(ASCII_O))) {
+            /* Enumerated or Notation type */
+            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+                || !poolAppendChar(&tempPool, XML_T('\0')))
+              return XML_ERROR_NO_MEMORY;
+            declAttributeType = tempPool.start;
+            poolFinish(&tempPool);
+          }
+          *eventEndPP = s;
+          attlistDeclHandler(handlerArg, declElementType->name,
+                             declAttributeId->name, declAttributeType,
+                             0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+          poolClear(&tempPool);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+    case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+      if (dtd->keepProcessing) {
+        const XML_Char *attVal;
+        enum XML_Error result =
+          storeAttributeValue(parser, enc, declAttributeIsCdata,
+                              s + enc->minBytesPerChar,
+                              next - enc->minBytesPerChar,
+                              &dtd->pool);
+        if (result)
+          return result;
+        attVal = poolStart(&dtd->pool);
+        poolFinish(&dtd->pool);
+        /* ID attributes aren't allowed to have a default */
+        if (!defineAttribute(declElementType, declAttributeId,
+                             declAttributeIsCdata, XML_FALSE, attVal, parser))
+          return XML_ERROR_NO_MEMORY;
+        if (attlistDeclHandler && declAttributeType) {
+          if (*declAttributeType == XML_T(ASCII_LPAREN)
+              || (*declAttributeType == XML_T(ASCII_N)
+                  && declAttributeType[1] == XML_T(ASCII_O))) {
+            /* Enumerated or Notation type */
+            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+                || !poolAppendChar(&tempPool, XML_T('\0')))
+              return XML_ERROR_NO_MEMORY;
+            declAttributeType = tempPool.start;
+            poolFinish(&tempPool);
+          }
+          *eventEndPP = s;
+          attlistDeclHandler(handlerArg, declElementType->name,
+                             declAttributeId->name, declAttributeType,
+                             attVal,
+                             role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+          poolClear(&tempPool);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_ENTITY_VALUE:
+      if (dtd->keepProcessing) {
+        enum XML_Error result = storeEntityValue(parser, enc,
+                                            s + enc->minBytesPerChar,
+                                            next - enc->minBytesPerChar);
+        if (declEntity) {
+          declEntity->textPtr = poolStart(&dtd->entityValuePool);
+          declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+          poolFinish(&dtd->entityValuePool);
+          if (entityDeclHandler) {
+            *eventEndPP = s;
+            entityDeclHandler(handlerArg,
+                              declEntity->name,
+                              declEntity->is_param,
+                              declEntity->textPtr,
+                              declEntity->textLen,
+                              curBase, 0, 0, 0);
+            handleDefault = XML_FALSE;
+          }
+        }
+        else
+          poolDiscard(&dtd->entityValuePool);
+        if (result != XML_ERROR_NONE)
+          return result;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_SYSTEM_ID:
+#ifdef XML_DTD
+      useForeignDTD = XML_FALSE;
+#endif /* XML_DTD */
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (startDoctypeDeclHandler) {
+        doctypeSysid = poolStoreString(&tempPool, enc,
+                                       s + enc->minBytesPerChar,
+                                       next - enc->minBytesPerChar);
+        if (doctypeSysid == NULL)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+#ifdef XML_DTD
+      else
+        /* use externalSubsetName to make doctypeSysid non-NULL
+           for the case where no startDoctypeDeclHandler is set */
+        doctypeSysid = externalSubsetName;
+#endif /* XML_DTD */
+      if (!dtd->standalone
+#ifdef XML_DTD
+          && !paramEntityParsing
+#endif /* XML_DTD */
+          && notStandaloneHandler
+          && !notStandaloneHandler(handlerArg))
+        return XML_ERROR_NOT_STANDALONE;
+#ifndef XML_DTD
+      break;
+#else /* XML_DTD */
+      if (!declEntity) {
+        declEntity = (ENTITY *)lookup(parser,
+                                      &dtd->paramEntities,
+                                      externalSubsetName,
+                                      sizeof(ENTITY));
+        if (!declEntity)
+          return XML_ERROR_NO_MEMORY;
+        declEntity->publicId = NULL;
+      }
+      /* fall through */
+#endif /* XML_DTD */
+    case XML_ROLE_ENTITY_SYSTEM_ID:
+      if (dtd->keepProcessing && declEntity) {
+        declEntity->systemId = poolStoreString(&dtd->pool, enc,
+                                               s + enc->minBytesPerChar,
+                                               next - enc->minBytesPerChar);
+        if (!declEntity->systemId)
+          return XML_ERROR_NO_MEMORY;
+        declEntity->base = curBase;
+        poolFinish(&dtd->pool);
+        if (entityDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_ENTITY_COMPLETE:
+      if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+        *eventEndPP = s;
+        entityDeclHandler(handlerArg,
+                          declEntity->name,
+                          declEntity->is_param,
+                          0,0,
+                          declEntity->base,
+                          declEntity->systemId,
+                          declEntity->publicId,
+                          0);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_ENTITY_NOTATION_NAME:
+      if (dtd->keepProcessing && declEntity) {
+        declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+        if (!declEntity->notation)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&dtd->pool);
+        if (unparsedEntityDeclHandler) {
+          *eventEndPP = s;
+          unparsedEntityDeclHandler(handlerArg,
+                                    declEntity->name,
+                                    declEntity->base,
+                                    declEntity->systemId,
+                                    declEntity->publicId,
+                                    declEntity->notation);
+          handleDefault = XML_FALSE;
+        }
+        else if (entityDeclHandler) {
+          *eventEndPP = s;
+          entityDeclHandler(handlerArg,
+                            declEntity->name,
+                            0,0,0,
+                            declEntity->base,
+                            declEntity->systemId,
+                            declEntity->publicId,
+                            declEntity->notation);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_GENERAL_ENTITY_NAME:
+      {
+        if (XmlPredefinedEntityName(enc, s, next)) {
+          declEntity = NULL;
+          break;
+        }
+        if (dtd->keepProcessing) {
+          const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+          if (!name)
+            return XML_ERROR_NO_MEMORY;
+          declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+                                        sizeof(ENTITY));
+          if (!declEntity)
+            return XML_ERROR_NO_MEMORY;
+          if (declEntity->name != name) {
+            poolDiscard(&dtd->pool);
+            declEntity = NULL;
+          }
+          else {
+            poolFinish(&dtd->pool);
+            declEntity->publicId = NULL;
+            declEntity->is_param = XML_FALSE;
+            /* if we have a parent parser or are reading an internal parameter
+               entity, then the entity declaration is not considered "internal"
+            */
+            declEntity->is_internal = !(parentParser || openInternalEntities);
+            if (entityDeclHandler)
+              handleDefault = XML_FALSE;
+          }
+        }
+        else {
+          poolDiscard(&dtd->pool);
+          declEntity = NULL;
+        }
+      }
+      break;
+    case XML_ROLE_PARAM_ENTITY_NAME:
+#ifdef XML_DTD
+      if (dtd->keepProcessing) {
+        const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+                                           name, sizeof(ENTITY));
+        if (!declEntity)
+          return XML_ERROR_NO_MEMORY;
+        if (declEntity->name != name) {
+          poolDiscard(&dtd->pool);
+          declEntity = NULL;
+        }
+        else {
+          poolFinish(&dtd->pool);
+          declEntity->publicId = NULL;
+          declEntity->is_param = XML_TRUE;
+          /* if we have a parent parser or are reading an internal parameter
+             entity, then the entity declaration is not considered "internal"
+          */
+          declEntity->is_internal = !(parentParser || openInternalEntities);
+          if (entityDeclHandler)
+            handleDefault = XML_FALSE;
+        }
+      }
+      else {
+        poolDiscard(&dtd->pool);
+        declEntity = NULL;
+      }
+#else /* not XML_DTD */
+      declEntity = NULL;
+#endif /* XML_DTD */
+      break;
+    case XML_ROLE_NOTATION_NAME:
+      declNotationPublicId = NULL;
+      declNotationName = NULL;
+      if (notationDeclHandler) {
+        declNotationName = poolStoreString(&tempPool, enc, s, next);
+        if (!declNotationName)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_NOTATION_PUBLIC_ID:
+      if (!XmlIsPublicId(enc, s, next, eventPP))
+        return XML_ERROR_PUBLICID;
+      if (declNotationName) {  /* means notationDeclHandler != NULL */
+        XML_Char *tem = poolStoreString(&tempPool,
+                                        enc,
+                                        s + enc->minBytesPerChar,
+                                        next - enc->minBytesPerChar);
+        if (!tem)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(tem);
+        declNotationPublicId = tem;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_NOTATION_SYSTEM_ID:
+      if (declNotationName && notationDeclHandler) {
+        const XML_Char *systemId
+          = poolStoreString(&tempPool, enc,
+                            s + enc->minBytesPerChar,
+                            next - enc->minBytesPerChar);
+        if (!systemId)
+          return XML_ERROR_NO_MEMORY;
+        *eventEndPP = s;
+        notationDeclHandler(handlerArg,
+                            declNotationName,
+                            curBase,
+                            systemId,
+                            declNotationPublicId);
+        handleDefault = XML_FALSE;
+      }
+      poolClear(&tempPool);
+      break;
+    case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+      if (declNotationPublicId && notationDeclHandler) {
+        *eventEndPP = s;
+        notationDeclHandler(handlerArg,
+                            declNotationName,
+                            curBase,
+                            0,
+                            declNotationPublicId);
+        handleDefault = XML_FALSE;
+      }
+      poolClear(&tempPool);
+      break;
+    case XML_ROLE_ERROR:
+      switch (tok) {
+      case XML_TOK_PARAM_ENTITY_REF:
+        /* PE references in internal subset are
+           not allowed within declarations. */
+        return XML_ERROR_PARAM_ENTITY_REF;
+      case XML_TOK_XML_DECL:
+        return XML_ERROR_MISPLACED_XML_PI;
+      default:
+        return XML_ERROR_SYNTAX;
+      }
+#ifdef XML_DTD
+    case XML_ROLE_IGNORE_SECT:
+      {
+        enum XML_Error result;
+        if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        handleDefault = XML_FALSE;
+        result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+        if (result != XML_ERROR_NONE)
+          return result;
+        else if (!next) {
+          processor = ignoreSectionProcessor;
+          return result;
+        }
+      }
+      break;
+#endif /* XML_DTD */
+    case XML_ROLE_GROUP_OPEN:
+      if (prologState.level >= groupSize) {
+        if (groupSize) {
+          char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+          if (temp == NULL)
+            return XML_ERROR_NO_MEMORY;
+          groupConnector = temp;
+          if (dtd->scaffIndex) {
+            int *temp = (int *)REALLOC(dtd->scaffIndex,
+                          groupSize * sizeof(int));
+            if (temp == NULL)
+              return XML_ERROR_NO_MEMORY;
+            dtd->scaffIndex = temp;
+          }
+        }
+        else {
+          groupConnector = (char *)MALLOC(groupSize = 32);
+          if (!groupConnector)
+            return XML_ERROR_NO_MEMORY;
+        }
+      }
+      groupConnector[prologState.level] = 0;
+      if (dtd->in_eldecl) {
+        int myindex = nextScaffoldPart(parser);
+        if (myindex < 0)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffIndex[dtd->scaffLevel] = myindex;
+        dtd->scaffLevel++;
+        dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_GROUP_SEQUENCE:
+      if (groupConnector[prologState.level] == ASCII_PIPE)
+        return XML_ERROR_SYNTAX;
+      groupConnector[prologState.level] = ASCII_COMMA;
+      if (dtd->in_eldecl && elementDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_GROUP_CHOICE:
+      if (groupConnector[prologState.level] == ASCII_COMMA)
+        return XML_ERROR_SYNTAX;
+      if (dtd->in_eldecl
+          && !groupConnector[prologState.level]
+          && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+              != XML_CTYPE_MIXED)
+          ) {
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+            = XML_CTYPE_CHOICE;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      groupConnector[prologState.level] = ASCII_PIPE;
+      break;
+    case XML_ROLE_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+    case XML_ROLE_INNER_PARAM_ENTITY_REF:
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (!paramEntityParsing)
+        dtd->keepProcessing = dtd->standalone;
+      else {
+        const XML_Char *name;
+        ENTITY *entity;
+        name = poolStoreString(&dtd->pool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+        poolDiscard(&dtd->pool);
+        /* first, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal,
+           otherwise call the skipped entity handler
+        */
+        if (prologState.documentEntity &&
+            (dtd->standalone
+             ? !openInternalEntities
+             : !dtd->hasParamEntityRefs)) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          dtd->keepProcessing = dtd->standalone;
+          /* cannot report skipped entities in declarations */
+          if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
+            skippedEntityHandler(handlerArg, name, 1);
+            handleDefault = XML_FALSE;
+          }
+          break;
+        }
+        if (entity->open)
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        if (entity->textPtr) {
+          enum XML_Error result;
+          XML_Bool betweenDecl =
+            (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+          result = processInternalEntity(parser, entity, betweenDecl);
+          if (result != XML_ERROR_NONE)
+            return result;
+          handleDefault = XML_FALSE;
+          break;
+        }
+        if (externalEntityRefHandler) {
+          dtd->paramEntityRead = XML_FALSE;
+          entity->open = XML_TRUE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId)) {
+            entity->open = XML_FALSE;
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          }
+          entity->open = XML_FALSE;
+          handleDefault = XML_FALSE;
+          if (!dtd->paramEntityRead) {
+            dtd->keepProcessing = dtd->standalone;
+            break;
+          }
+        }
+        else {
+          dtd->keepProcessing = dtd->standalone;
+          break;
+        }
+      }
+#endif /* XML_DTD */
+      if (!dtd->standalone &&
+          notStandaloneHandler &&
+          !notStandaloneHandler(handlerArg))
+        return XML_ERROR_NOT_STANDALONE;
+      break;
+
+    /* Element declaration stuff */
+
+    case XML_ROLE_ELEMENT_NAME:
+      if (elementDeclHandler) {
+        declElementType = getElementType(parser, enc, s, next);
+        if (!declElementType)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffLevel = 0;
+        dtd->scaffCount = 0;
+        dtd->in_eldecl = XML_TRUE;
+        handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_ANY:
+    case XML_ROLE_CONTENT_EMPTY:
+      if (dtd->in_eldecl) {
+        if (elementDeclHandler) {
+          XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+          if (!content)
+            return XML_ERROR_NO_MEMORY;
+          content->quant = XML_CQUANT_NONE;
+          content->name = NULL;
+          content->numchildren = 0;
+          content->children = NULL;
+          content->type = ((role == XML_ROLE_CONTENT_ANY) ?
+                           XML_CTYPE_ANY :
+                           XML_CTYPE_EMPTY);
+          *eventEndPP = s;
+          elementDeclHandler(handlerArg, declElementType->name, content);
+          handleDefault = XML_FALSE;
+        }
+        dtd->in_eldecl = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_PCDATA:
+      if (dtd->in_eldecl) {
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+            = XML_CTYPE_MIXED;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_ELEMENT:
+      quant = XML_CQUANT_NONE;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_OPT:
+      quant = XML_CQUANT_OPT;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_REP:
+      quant = XML_CQUANT_REP;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_PLUS:
+      quant = XML_CQUANT_PLUS;
+    elementContent:
+      if (dtd->in_eldecl) {
+        ELEMENT_TYPE *el;
+        const XML_Char *name;
+        int nameLen;
+        const char *nxt = (quant == XML_CQUANT_NONE
+                           ? next
+                           : next - enc->minBytesPerChar);
+        int myindex = nextScaffoldPart(parser);
+        if (myindex < 0)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffold[myindex].type = XML_CTYPE_NAME;
+        dtd->scaffold[myindex].quant = quant;
+        el = getElementType(parser, enc, s, nxt);
+        if (!el)
+          return XML_ERROR_NO_MEMORY;
+        name = el->name;
+        dtd->scaffold[myindex].name = name;
+        nameLen = 0;
+        for (; name[nameLen++]; );
+        dtd->contentStringLen +=  nameLen;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_GROUP_CLOSE:
+      quant = XML_CQUANT_NONE;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_OPT:
+      quant = XML_CQUANT_OPT;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_REP:
+      quant = XML_CQUANT_REP;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_PLUS:
+      quant = XML_CQUANT_PLUS;
+    closeGroup:
+      if (dtd->in_eldecl) {
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+        dtd->scaffLevel--;
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
+        if (dtd->scaffLevel == 0) {
+          if (!handleDefault) {
+            XML_Content *model = build_model(parser);
+            if (!model)
+              return XML_ERROR_NO_MEMORY;
+            *eventEndPP = s;
+            elementDeclHandler(handlerArg, declElementType->name, model);
+          }
+          dtd->in_eldecl = XML_FALSE;
+          dtd->contentStringLen = 0;
+        }
+      }
+      break;
+      /* End element declaration stuff */
+
+    case XML_ROLE_PI:
+      if (!reportProcessingInstruction(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_COMMENT:
+      if (!reportComment(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_NONE:
+      switch (tok) {
+      case XML_TOK_BOM:
+        handleDefault = XML_FALSE;
+        break;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_NONE:
+      if (startDoctypeDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ENTITY_NONE:
+      if (dtd->keepProcessing && entityDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_NOTATION_NONE:
+      if (notationDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ATTLIST_NONE:
+      if (dtd->keepProcessing && attlistDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ELEMENT_NONE:
+      if (elementDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    } /* end of big switch */
+
+    if (handleDefault && defaultHandler)
+      reportDefault(parser, enc, s, next);
+
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default:
+      s = next;
+      tok = XmlPrologTok(enc, s, end, &next);
+    }
+  }
+  /* not reached */
+}
+
+static enum XML_Error PTRCALL
+epilogProcessor(XML_Parser parser,
+                const char *s,
+                const char *end,
+                const char **nextPtr)
+{
+  processor = epilogProcessor;
+  eventPtr = s;
+  for (;;) {
+    const char *next = NULL;
+    int tok = XmlPrologTok(encoding, s, end, &next);
+    eventEndPtr = next;
+    switch (tok) {
+    /* report partial linebreak - it might be the last token */
+    case -XML_TOK_PROLOG_S:
+      if (defaultHandler) {
+        reportDefault(parser, encoding, s, next);
+        if (ps_parsing == XML_FINISHED)
+          return XML_ERROR_ABORTED;
+      }
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_TOK_NONE:
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    case XML_TOK_PROLOG_S:
+      if (defaultHandler)
+        reportDefault(parser, encoding, s, next);
+      break;
+    case XML_TOK_PI:
+      if (!reportProcessingInstruction(parser, encoding, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_COMMENT:
+      if (!reportComment(parser, encoding, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_INVALID:
+      eventPtr = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (!ps_finalBuffer) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (!ps_finalBuffer) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    default:
+      return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+    }
+    eventPtr = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+}
+
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+                      XML_Bool betweenDecl)
+{
+  const char *textStart, *textEnd;
+  const char *next;
+  enum XML_Error result;
+  OPEN_INTERNAL_ENTITY *openEntity;
+
+  if (freeInternalEntities) {
+    openEntity = freeInternalEntities;
+    freeInternalEntities = openEntity->next;
+  }
+  else {
+    openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+    if (!openEntity)
+      return XML_ERROR_NO_MEMORY;
+  }
+  entity->open = XML_TRUE;
+  entity->processed = 0;
+  openEntity->next = openInternalEntities;
+  openInternalEntities = openEntity;
+  openEntity->entity = entity;
+  openEntity->startTagLevel = tagLevel;
+  openEntity->betweenDecl = betweenDecl;
+  openEntity->internalEventPtr = NULL;
+  openEntity->internalEventEndPtr = NULL;
+  textStart = (char *)entity->textPtr;
+  textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+                      next, &next, XML_FALSE);
+  }
+  else
+#endif /* XML_DTD */
+    result = doContent(parser, tagLevel, internalEncoding, textStart,
+                       textEnd, &next, XML_FALSE);
+
+  if (result == XML_ERROR_NONE) {
+    if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+      entity->processed = (int)(next - textStart);
+      processor = internalEntityProcessor;
+    }
+    else {
+      entity->open = XML_FALSE;
+      openInternalEntities = openEntity->next;
+      /* put openEntity back in list of free instances */
+      openEntity->next = freeInternalEntities;
+      freeInternalEntities = openEntity;
+    }
+  }
+  return result;
+}
+
+static enum XML_Error PTRCALL
+internalEntityProcessor(XML_Parser parser,
+                        const char *s,
+                        const char *end,
+                        const char **nextPtr)
+{
+  ENTITY *entity;
+  const char *textStart, *textEnd;
+  const char *next;
+  enum XML_Error result;
+  OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+  if (!openEntity)
+    return XML_ERROR_UNEXPECTED_STATE;
+
+  entity = openEntity->entity;
+  textStart = ((char *)entity->textPtr) + entity->processed;
+  textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+                      next, &next, XML_FALSE);
+  }
+  else
+#endif /* XML_DTD */
+    result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+                       textStart, textEnd, &next, XML_FALSE);
+
+  if (result != XML_ERROR_NONE)
+    return result;
+  else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+    entity->processed = (int)(next - (char *)entity->textPtr);
+    return result;
+  }
+  else {
+    entity->open = XML_FALSE;
+    openInternalEntities = openEntity->next;
+    /* put openEntity back in list of free instances */
+    openEntity->next = freeInternalEntities;
+    freeInternalEntities = openEntity;
+  }
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok;
+    processor = prologProcessor;
+    tok = XmlPrologTok(encoding, s, end, &next);
+    return doProlog(parser, encoding, s, end, tok, next, nextPtr,
+                    (XML_Bool)!ps_finalBuffer);
+  }
+  else
+#endif /* XML_DTD */
+  {
+    processor = contentProcessor;
+    /* see externalEntityContentProcessor vs contentProcessor */
+    return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
+                     nextPtr, (XML_Bool)!ps_finalBuffer);
+  }
+}
+
+static enum XML_Error PTRCALL
+errorProcessor(XML_Parser parser,
+               const char *s,
+               const char *end,
+               const char **nextPtr)
+{
+  return errorCode;
+}
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+                    const char *ptr, const char *end,
+                    STRING_POOL *pool)
+{
+  enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
+                                               end, pool);
+  if (result)
+    return result;
+  if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+    poolChop(pool);
+  if (!poolAppendChar(pool, XML_T('\0')))
+    return XML_ERROR_NO_MEMORY;
+  return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+                     const char *ptr, const char *end,
+                     STRING_POOL *pool)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  for (;;) {
+    const char *next;
+    int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+    switch (tok) {
+    case XML_TOK_NONE:
+      return XML_ERROR_NONE;
+    case XML_TOK_INVALID:
+      if (enc == encoding)
+        eventPtr = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (enc == encoding)
+        eventPtr = ptr;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_CHAR_REF:
+      {
+        XML_Char buf[XML_ENCODE_MAX];
+        int i;
+        int n = XmlCharRefNumber(enc, ptr);
+        if (n < 0) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BAD_CHAR_REF;
+        }
+        if (!isCdata
+            && n == 0x20 /* space */
+            && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+          break;
+        n = XmlEncode(n, (ICHAR *)buf);
+        if (!n) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BAD_CHAR_REF;
+        }
+        for (i = 0; i < n; i++) {
+          if (!poolAppendChar(pool, buf[i]))
+            return XML_ERROR_NO_MEMORY;
+        }
+      }
+      break;
+    case XML_TOK_DATA_CHARS:
+      if (!poolAppend(pool, enc, ptr, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_TRAILING_CR:
+      next = ptr + enc->minBytesPerChar;
+      /* fall through */
+    case XML_TOK_ATTRIBUTE_VALUE_S:
+    case XML_TOK_DATA_NEWLINE:
+      if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+        break;
+      if (!poolAppendChar(pool, 0x20))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_ENTITY_REF:
+      {
+        const XML_Char *name;
+        ENTITY *entity;
+        char checkEntityDecl;
+        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+                                              ptr + enc->minBytesPerChar,
+                                              next - enc->minBytesPerChar);
+        if (ch) {
+          if (!poolAppendChar(pool, ch))
+                return XML_ERROR_NO_MEMORY;
+          break;
+        }
+        name = poolStoreString(&temp2Pool, enc,
+                               ptr + enc->minBytesPerChar,
+                               next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+        poolDiscard(&temp2Pool);
+        /* First, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal.
+        */
+        if (pool == &dtd->pool)  /* are we called from prolog? */
+          checkEntityDecl =
+#ifdef XML_DTD
+              prologState.documentEntity &&
+#endif /* XML_DTD */
+              (dtd->standalone
+               ? !openInternalEntities
+               : !dtd->hasParamEntityRefs);
+        else /* if (pool == &tempPool): we are called from content */
+          checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
+        if (checkEntityDecl) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          /* Cannot report skipped entity here - see comments on
+             skippedEntityHandler.
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          */
+          /* Cannot call the default handler because this would be
+             out of sync with the call to the startElementHandler.
+          if ((pool == &tempPool) && defaultHandler)
+            reportDefault(parser, enc, ptr, next);
+          */
+          break;
+        }
+        if (entity->open) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        }
+        if (entity->notation) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BINARY_ENTITY_REF;
+        }
+        if (!entity->textPtr) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+        }
+        else {
+          enum XML_Error result;
+          const XML_Char *textEnd = entity->textPtr + entity->textLen;
+          entity->open = XML_TRUE;
+          result = appendAttributeValue(parser, internalEncoding, isCdata,
+                                        (char *)entity->textPtr,
+                                        (char *)textEnd, pool);
+          entity->open = XML_FALSE;
+          if (result)
+            return result;
+        }
+      }
+      break;
+    default:
+      if (enc == encoding)
+        eventPtr = ptr;
+      return XML_ERROR_UNEXPECTED_STATE;
+    }
+    ptr = next;
+  }
+  /* not reached */
+}
+
+static enum XML_Error
+storeEntityValue(XML_Parser parser,
+                 const ENCODING *enc,
+                 const char *entityTextPtr,
+                 const char *entityTextEnd)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  STRING_POOL *pool = &(dtd->entityValuePool);
+  enum XML_Error result = XML_ERROR_NONE;
+#ifdef XML_DTD
+  int oldInEntityValue = prologState.inEntityValue;
+  prologState.inEntityValue = 1;
+#endif /* XML_DTD */
+  /* never return Null for the value argument in EntityDeclHandler,
+     since this would indicate an external entity; therefore we
+     have to make sure that entityValuePool.start is not null */
+  if (!pool->blocks) {
+    if (!poolGrow(pool))
+      return XML_ERROR_NO_MEMORY;
+  }
+
+  for (;;) {
+    const char *next;
+    int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+    switch (tok) {
+    case XML_TOK_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+      if (isParamEntity || enc != encoding) {
+        const XML_Char *name;
+        ENTITY *entity;
+        name = poolStoreString(&tempPool, enc,
+                               entityTextPtr + enc->minBytesPerChar,
+                               next - enc->minBytesPerChar);
+        if (!name) {
+          result = XML_ERROR_NO_MEMORY;
+          goto endEntityValue;
+        }
+        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+        poolDiscard(&tempPool);
+        if (!entity) {
+          /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
+          /* cannot report skipped entity here - see comments on
+             skippedEntityHandler
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          */
+          dtd->keepProcessing = dtd->standalone;
+          goto endEntityValue;
+        }
+        if (entity->open) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_RECURSIVE_ENTITY_REF;
+          goto endEntityValue;
+        }
+        if (entity->systemId) {
+          if (externalEntityRefHandler) {
+            dtd->paramEntityRead = XML_FALSE;
+            entity->open = XML_TRUE;
+            if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                          0,
+                                          entity->base,
+                                          entity->systemId,
+                                          entity->publicId)) {
+              entity->open = XML_FALSE;
+              result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+              goto endEntityValue;
+            }
+            entity->open = XML_FALSE;
+            if (!dtd->paramEntityRead)
+              dtd->keepProcessing = dtd->standalone;
+          }
+          else
+            dtd->keepProcessing = dtd->standalone;
+        }
+        else {
+          entity->open = XML_TRUE;
+          result = storeEntityValue(parser,
+                                    internalEncoding,
+                                    (char *)entity->textPtr,
+                                    (char *)(entity->textPtr
+                                             + entity->textLen));
+          entity->open = XML_FALSE;
+          if (result)
+            goto endEntityValue;
+        }
+        break;
+      }
+#endif /* XML_DTD */
+      /* In the internal subset, PE references are not legal
+         within markup declarations, e.g entity values in this case. */
+      eventPtr = entityTextPtr;
+      result = XML_ERROR_PARAM_ENTITY_REF;
+      goto endEntityValue;
+    case XML_TOK_NONE:
+      result = XML_ERROR_NONE;
+      goto endEntityValue;
+    case XML_TOK_ENTITY_REF:
+    case XML_TOK_DATA_CHARS:
+      if (!poolAppend(pool, enc, entityTextPtr, next)) {
+        result = XML_ERROR_NO_MEMORY;
+        goto endEntityValue;
+      }
+      break;
+    case XML_TOK_TRAILING_CR:
+      next = entityTextPtr + enc->minBytesPerChar;
+      /* fall through */
+    case XML_TOK_DATA_NEWLINE:
+      if (pool->end == pool->ptr && !poolGrow(pool)) {
+              result = XML_ERROR_NO_MEMORY;
+        goto endEntityValue;
+      }
+      *(pool->ptr)++ = 0xA;
+      break;
+    case XML_TOK_CHAR_REF:
+      {
+        XML_Char buf[XML_ENCODE_MAX];
+        int i;
+        int n = XmlCharRefNumber(enc, entityTextPtr);
+        if (n < 0) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_BAD_CHAR_REF;
+          goto endEntityValue;
+        }
+        n = XmlEncode(n, (ICHAR *)buf);
+        if (!n) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_BAD_CHAR_REF;
+          goto endEntityValue;
+        }
+        for (i = 0; i < n; i++) {
+          if (pool->end == pool->ptr && !poolGrow(pool)) {
+            result = XML_ERROR_NO_MEMORY;
+            goto endEntityValue;
+          }
+          *(pool->ptr)++ = buf[i];
+        }
+      }
+      break;
+    case XML_TOK_PARTIAL:
+      if (enc == encoding)
+        eventPtr = entityTextPtr;
+      result = XML_ERROR_INVALID_TOKEN;
+      goto endEntityValue;
+    case XML_TOK_INVALID:
+      if (enc == encoding)
+        eventPtr = next;
+      result = XML_ERROR_INVALID_TOKEN;
+      goto endEntityValue;
+    default:
+      if (enc == encoding)
+        eventPtr = entityTextPtr;
+      result = XML_ERROR_UNEXPECTED_STATE;
+      goto endEntityValue;
+    }
+    entityTextPtr = next;
+  }
+endEntityValue:
+#ifdef XML_DTD
+  prologState.inEntityValue = oldInEntityValue;
+#endif /* XML_DTD */
+  return result;
+}
+
+static void FASTCALL
+normalizeLines(XML_Char *s)
+{
+  XML_Char *p;
+  for (;; s++) {
+    if (*s == XML_T('\0'))
+      return;
+    if (*s == 0xD)
+      break;
+  }
+  p = s;
+  do {
+    if (*s == 0xD) {
+      *p++ = 0xA;
+      if (*++s == 0xA)
+        s++;
+    }
+    else
+      *p++ = *s++;
+  } while (*s);
+  *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                            const char *start, const char *end)
+{
+  const XML_Char *target;
+  XML_Char *data;
+  const char *tem;
+  if (!processingInstructionHandler) {
+    if (defaultHandler)
+      reportDefault(parser, enc, start, end);
+    return 1;
+  }
+  start += enc->minBytesPerChar * 2;
+  tem = start + XmlNameLength(enc, start);
+  target = poolStoreString(&tempPool, enc, start, tem);
+  if (!target)
+    return 0;
+  poolFinish(&tempPool);
+  data = poolStoreString(&tempPool, enc,
+                        XmlSkipS(enc, tem),
+                        end - enc->minBytesPerChar*2);
+  if (!data)
+    return 0;
+  normalizeLines(data);
+  processingInstructionHandler(handlerArg, target, data);
+  poolClear(&tempPool);
+  return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc,
+              const char *start, const char *end)
+{
+  XML_Char *data;
+  if (!commentHandler) {
+    if (defaultHandler)
+      reportDefault(parser, enc, start, end);
+    return 1;
+  }
+  data = poolStoreString(&tempPool,
+                         enc,
+                         start + enc->minBytesPerChar * 4,
+                         end - enc->minBytesPerChar * 3);
+  if (!data)
+    return 0;
+  normalizeLines(data);
+  commentHandler(handlerArg, data);
+  poolClear(&tempPool);
+  return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc,
+              const char *s, const char *end)
+{
+  if (MUST_CONVERT(enc, s)) {
+    const char **eventPP;
+    const char **eventEndPP;
+    if (enc == encoding) {
+      eventPP = &eventPtr;
+      eventEndPP = &eventEndPtr;
+    }
+    else {
+      eventPP = &(openInternalEntities->internalEventPtr);
+      eventEndPP = &(openInternalEntities->internalEventEndPtr);
+    }
+    do {
+      ICHAR *dataPtr = (ICHAR *)dataBuf;
+      XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+      *eventEndPP = s;
+      defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+      *eventPP = s;
+    } while (s != end);
+  }
+  else
+    defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
+                XML_Bool isId, const XML_Char *value, XML_Parser parser)
+{
+  DEFAULT_ATTRIBUTE *att;
+  if (value || isId) {
+    /* The handling of default attributes gets messed up if we have
+       a default which duplicates a non-default. */
+    int i;
+    for (i = 0; i < type->nDefaultAtts; i++)
+      if (attId == type->defaultAtts[i].id)
+        return 1;
+    if (isId && !type->idAtt && !attId->xmlns)
+      type->idAtt = attId;
+  }
+  if (type->nDefaultAtts == type->allocDefaultAtts) {
+    if (type->allocDefaultAtts == 0) {
+      type->allocDefaultAtts = 8;
+      type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+                            * sizeof(DEFAULT_ATTRIBUTE));
+      if (!type->defaultAtts)
+        return 0;
+    }
+    else {
+      DEFAULT_ATTRIBUTE *temp;
+      int count = type->allocDefaultAtts * 2;
+      temp = (DEFAULT_ATTRIBUTE *)
+        REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+      if (temp == NULL)
+        return 0;
+      type->allocDefaultAtts = count;
+      type->defaultAtts = temp;
+    }
+  }
+  att = type->defaultAtts + type->nDefaultAtts;
+  att->id = attId;
+  att->value = value;
+  att->isCdata = isCdata;
+  if (!isCdata)
+    attId->maybeTokenized = XML_TRUE;
+  type->nDefaultAtts += 1;
+  return 1;
+}
+
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *name;
+  for (name = elementType->name; *name; name++) {
+    if (*name == XML_T(ASCII_COLON)) {
+      PREFIX *prefix;
+      const XML_Char *s;
+      for (s = elementType->name; s != name; s++) {
+        if (!poolAppendChar(&dtd->pool, *s))
+          return 0;
+      }
+      if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+        return 0;
+      prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+                                sizeof(PREFIX));
+      if (!prefix)
+        return 0;
+      if (prefix->name == poolStart(&dtd->pool))
+        poolFinish(&dtd->pool);
+      else
+        poolDiscard(&dtd->pool);
+      elementType->prefix = prefix;
+
+    }
+  }
+  return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc,
+               const char *start, const char *end)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  ATTRIBUTE_ID *id;
+  const XML_Char *name;
+  if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+    return NULL;
+  name = poolStoreString(&dtd->pool, enc, start, end);
+  if (!name)
+    return NULL;
+  /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+  ++name;
+  id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
+  if (!id)
+    return NULL;
+  if (id->name != name)
+    poolDiscard(&dtd->pool);
+  else {
+    poolFinish(&dtd->pool);
+    if (!ns)
+      ;
+    else if (name[0] == XML_T(ASCII_x)
+        && name[1] == XML_T(ASCII_m)
+        && name[2] == XML_T(ASCII_l)
+        && name[3] == XML_T(ASCII_n)
+        && name[4] == XML_T(ASCII_s)
+        && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
+      if (name[5] == XML_T('\0'))
+        id->prefix = &dtd->defaultPrefix;
+      else
+        id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
+      id->xmlns = XML_TRUE;
+    }
+    else {
+      int i;
+      for (i = 0; name[i]; i++) {
+        /* attributes without prefix are *not* in the default namespace */
+        if (name[i] == XML_T(ASCII_COLON)) {
+          int j;
+          for (j = 0; j < i; j++) {
+            if (!poolAppendChar(&dtd->pool, name[j]))
+              return NULL;
+          }
+          if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+            return NULL;
+          id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+                                        sizeof(PREFIX));
+          if (id->prefix->name == poolStart(&dtd->pool))
+            poolFinish(&dtd->pool);
+          else
+            poolDiscard(&dtd->pool);
+          break;
+        }
+      }
+    }
+  }
+  return id;
+}
+
+#define CONTEXT_SEP XML_T(ASCII_FF)
+
+static const XML_Char *
+getContext(XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  HASH_TABLE_ITER iter;
+  XML_Bool needSep = XML_FALSE;
+
+  if (dtd->defaultPrefix.binding) {
+    int i;
+    int len;
+    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+      return NULL;
+    len = dtd->defaultPrefix.binding->uriLen;
+    if (namespaceSeparator)
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
+        return NULL;
+    needSep = XML_TRUE;
+  }
+
+  hashTableIterInit(&iter, &(dtd->prefixes));
+  for (;;) {
+    int i;
+    int len;
+    const XML_Char *s;
+    PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+    if (!prefix)
+      break;
+    if (!prefix->binding)
+      continue;
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+      return NULL;
+    for (s = prefix->name; *s; s++)
+      if (!poolAppendChar(&tempPool, *s))
+        return NULL;
+    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+      return NULL;
+    len = prefix->binding->uriLen;
+    if (namespaceSeparator)
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+        return NULL;
+    needSep = XML_TRUE;
+  }
+
+
+  hashTableIterInit(&iter, &(dtd->generalEntities));
+  for (;;) {
+    const XML_Char *s;
+    ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (!e->open)
+      continue;
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+      return NULL;
+    for (s = e->name; *s; s++)
+      if (!poolAppendChar(&tempPool, *s))
+        return 0;
+    needSep = XML_TRUE;
+  }
+
+  if (!poolAppendChar(&tempPool, XML_T('\0')))
+    return NULL;
+  return tempPool.start;
+}
+
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *s = context;
+
+  while (*context != XML_T('\0')) {
+    if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+      ENTITY *e;
+      if (!poolAppendChar(&tempPool, XML_T('\0')))
+        return XML_FALSE;
+      e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+      if (e)
+        e->open = XML_TRUE;
+      if (*s != XML_T('\0'))
+        s++;
+      context = s;
+      poolDiscard(&tempPool);
+    }
+    else if (*s == XML_T(ASCII_EQUALS)) {
+      PREFIX *prefix;
+      if (poolLength(&tempPool) == 0)
+        prefix = &dtd->defaultPrefix;
+      else {
+        if (!poolAppendChar(&tempPool, XML_T('\0')))
+          return XML_FALSE;
+        prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+                                  sizeof(PREFIX));
+        if (!prefix)
+          return XML_FALSE;
+        if (prefix->name == poolStart(&tempPool)) {
+          prefix->name = poolCopyString(&dtd->pool, prefix->name);
+          if (!prefix->name)
+            return XML_FALSE;
+        }
+        poolDiscard(&tempPool);
+      }
+      for (context = s + 1;
+           *context != CONTEXT_SEP && *context != XML_T('\0');
+           context++)
+        if (!poolAppendChar(&tempPool, *context))
+          return XML_FALSE;
+      if (!poolAppendChar(&tempPool, XML_T('\0')))
+        return XML_FALSE;
+      if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
+                     &inheritedBindings) != XML_ERROR_NONE)
+        return XML_FALSE;
+      poolDiscard(&tempPool);
+      if (*context != XML_T('\0'))
+        ++context;
+      s = context;
+    }
+    else {
+      if (!poolAppendChar(&tempPool, *s))
+        return XML_FALSE;
+      s++;
+    }
+  }
+  return XML_TRUE;
+}
+
+static void FASTCALL
+normalizePublicId(XML_Char *publicId)
+{
+  XML_Char *p = publicId;
+  XML_Char *s;
+  for (s = publicId; *s; s++) {
+    switch (*s) {
+    case 0x20:
+    case 0xD:
+    case 0xA:
+      if (p != publicId && p[-1] != 0x20)
+        *p++ = 0x20;
+      break;
+    default:
+      *p++ = *s;
+    }
+  }
+  if (p != publicId && p[-1] == 0x20)
+    --p;
+  *p = XML_T('\0');
+}
+
+static DTD *
+dtdCreate(const XML_Memory_Handling_Suite *ms)
+{
+  DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+  if (p == NULL)
+    return p;
+  poolInit(&(p->pool), ms);
+  poolInit(&(p->entityValuePool), ms);
+  hashTableInit(&(p->generalEntities), ms);
+  hashTableInit(&(p->elementTypes), ms);
+  hashTableInit(&(p->attributeIds), ms);
+  hashTableInit(&(p->prefixes), ms);
+#ifdef XML_DTD
+  p->paramEntityRead = XML_FALSE;
+  hashTableInit(&(p->paramEntities), ms);
+#endif /* XML_DTD */
+  p->defaultPrefix.name = NULL;
+  p->defaultPrefix.binding = NULL;
+
+  p->in_eldecl = XML_FALSE;
+  p->scaffIndex = NULL;
+  p->scaffold = NULL;
+  p->scaffLevel = 0;
+  p->scaffSize = 0;
+  p->scaffCount = 0;
+  p->contentStringLen = 0;
+
+  p->keepProcessing = XML_TRUE;
+  p->hasParamEntityRefs = XML_FALSE;
+  p->standalone = XML_FALSE;
+  return p;
+}
+
+static void
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+  hashTableIterInit(&iter, &(p->elementTypes));
+  for (;;) {
+    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (e->allocDefaultAtts != 0)
+      ms->free_fcn(e->defaultAtts);
+  }
+  hashTableClear(&(p->generalEntities));
+#ifdef XML_DTD
+  p->paramEntityRead = XML_FALSE;
+  hashTableClear(&(p->paramEntities));
+#endif /* XML_DTD */
+  hashTableClear(&(p->elementTypes));
+  hashTableClear(&(p->attributeIds));
+  hashTableClear(&(p->prefixes));
+  poolClear(&(p->pool));
+  poolClear(&(p->entityValuePool));
+  p->defaultPrefix.name = NULL;
+  p->defaultPrefix.binding = NULL;
+
+  p->in_eldecl = XML_FALSE;
+
+  ms->free_fcn(p->scaffIndex);
+  p->scaffIndex = NULL;
+  ms->free_fcn(p->scaffold);
+  p->scaffold = NULL;
+
+  p->scaffLevel = 0;
+  p->scaffSize = 0;
+  p->scaffCount = 0;
+  p->contentStringLen = 0;
+
+  p->keepProcessing = XML_TRUE;
+  p->hasParamEntityRefs = XML_FALSE;
+  p->standalone = XML_FALSE;
+}
+
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+  hashTableIterInit(&iter, &(p->elementTypes));
+  for (;;) {
+    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (e->allocDefaultAtts != 0)
+      ms->free_fcn(e->defaultAtts);
+  }
+  hashTableDestroy(&(p->generalEntities));
+#ifdef XML_DTD
+  hashTableDestroy(&(p->paramEntities));
+#endif /* XML_DTD */
+  hashTableDestroy(&(p->elementTypes));
+  hashTableDestroy(&(p->attributeIds));
+  hashTableDestroy(&(p->prefixes));
+  poolDestroy(&(p->pool));
+  poolDestroy(&(p->entityValuePool));
+  if (isDocEntity) {
+    ms->free_fcn(p->scaffIndex);
+    ms->free_fcn(p->scaffold);
+  }
+  ms->free_fcn(p);
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
+   The new DTD has already been initialized.
+*/
+static int
+dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+
+  /* Copy the prefix table. */
+
+  hashTableIterInit(&iter, &(oldDtd->prefixes));
+  for (;;) {
+    const XML_Char *name;
+    const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+    if (!oldP)
+      break;
+    name = poolCopyString(&(newDtd->pool), oldP->name);
+    if (!name)
+      return 0;
+    if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
+      return 0;
+  }
+
+  hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+  /* Copy the attribute id table. */
+
+  for (;;) {
+    ATTRIBUTE_ID *newA;
+    const XML_Char *name;
+    const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+    if (!oldA)
+      break;
+    /* Remember to allocate the scratch byte before the name. */
+    if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+      return 0;
+    name = poolCopyString(&(newDtd->pool), oldA->name);
+    if (!name)
+      return 0;
+    ++name;
+    newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
+                                  sizeof(ATTRIBUTE_ID));
+    if (!newA)
+      return 0;
+    newA->maybeTokenized = oldA->maybeTokenized;
+    if (oldA->prefix) {
+      newA->xmlns = oldA->xmlns;
+      if (oldA->prefix == &oldDtd->defaultPrefix)
+        newA->prefix = &newDtd->defaultPrefix;
+      else
+        newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+                                        oldA->prefix->name, 0);
+    }
+  }
+
+  /* Copy the element type table. */
+
+  hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+  for (;;) {
+    int i;
+    ELEMENT_TYPE *newE;
+    const XML_Char *name;
+    const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!oldE)
+      break;
+    name = poolCopyString(&(newDtd->pool), oldE->name);
+    if (!name)
+      return 0;
+    newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
+                                  sizeof(ELEMENT_TYPE));
+    if (!newE)
+      return 0;
+    if (oldE->nDefaultAtts) {
+      newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
+          ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+      if (!newE->defaultAtts) {
+        ms->free_fcn(newE);
+        return 0;
+      }
+    }
+    if (oldE->idAtt)
+      newE->idAtt = (ATTRIBUTE_ID *)
+          lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
+    newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+    if (oldE->prefix)
+      newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+                                      oldE->prefix->name, 0);
+    for (i = 0; i < newE->nDefaultAtts; i++) {
+      newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
+          lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+      newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+      if (oldE->defaultAtts[i].value) {
+        newE->defaultAtts[i].value
+            = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+        if (!newE->defaultAtts[i].value)
+          return 0;
+      }
+      else
+        newE->defaultAtts[i].value = NULL;
+    }
+  }
+
+  /* Copy the entity tables. */
+  if (!copyEntityTable(oldParser,
+                       &(newDtd->generalEntities),
+                       &(newDtd->pool),
+                       &(oldDtd->generalEntities)))
+      return 0;
+
+#ifdef XML_DTD
+  if (!copyEntityTable(oldParser,
+                       &(newDtd->paramEntities),
+                       &(newDtd->pool),
+                       &(oldDtd->paramEntities)))
+      return 0;
+  newDtd->paramEntityRead = oldDtd->paramEntityRead;
+#endif /* XML_DTD */
+
+  newDtd->keepProcessing = oldDtd->keepProcessing;
+  newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
+  newDtd->standalone = oldDtd->standalone;
+
+  /* Don't want deep copying for scaffolding */
+  newDtd->in_eldecl = oldDtd->in_eldecl;
+  newDtd->scaffold = oldDtd->scaffold;
+  newDtd->contentStringLen = oldDtd->contentStringLen;
+  newDtd->scaffSize = oldDtd->scaffSize;
+  newDtd->scaffLevel = oldDtd->scaffLevel;
+  newDtd->scaffIndex = oldDtd->scaffIndex;
+
+  return 1;
+}  /* End dtdCopy */
+
+static int
+copyEntityTable(XML_Parser oldParser,
+                HASH_TABLE *newTable,
+                STRING_POOL *newPool,
+                const HASH_TABLE *oldTable)
+{
+  HASH_TABLE_ITER iter;
+  const XML_Char *cachedOldBase = NULL;
+  const XML_Char *cachedNewBase = NULL;
+
+  hashTableIterInit(&iter, oldTable);
+
+  for (;;) {
+    ENTITY *newE;
+    const XML_Char *name;
+    const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+    if (!oldE)
+      break;
+    name = poolCopyString(newPool, oldE->name);
+    if (!name)
+      return 0;
+    newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
+    if (!newE)
+      return 0;
+    if (oldE->systemId) {
+      const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
+      if (!tem)
+        return 0;
+      newE->systemId = tem;
+      if (oldE->base) {
+        if (oldE->base == cachedOldBase)
+          newE->base = cachedNewBase;
+        else {
+          cachedOldBase = oldE->base;
+          tem = poolCopyString(newPool, cachedOldBase);
+          if (!tem)
+            return 0;
+          cachedNewBase = newE->base = tem;
+        }
+      }
+      if (oldE->publicId) {
+        tem = poolCopyString(newPool, oldE->publicId);
+        if (!tem)
+          return 0;
+        newE->publicId = tem;
+      }
+    }
+    else {
+      const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
+                                            oldE->textLen);
+      if (!tem)
+        return 0;
+      newE->textPtr = tem;
+      newE->textLen = oldE->textLen;
+    }
+    if (oldE->notation) {
+      const XML_Char *tem = poolCopyString(newPool, oldE->notation);
+      if (!tem)
+        return 0;
+      newE->notation = tem;
+    }
+    newE->is_param = oldE->is_param;
+    newE->is_internal = oldE->is_internal;
+  }
+  return 1;
+}
+
+#define INIT_POWER 6
+
+static XML_Bool FASTCALL
+keyeq(KEY s1, KEY s2)
+{
+  for (; *s1 == *s2; s1++, s2++)
+    if (*s1 == 0)
+      return XML_TRUE;
+  return XML_FALSE;
+}
+
+static unsigned long FASTCALL
+hash(XML_Parser parser, KEY s)
+{
+  unsigned long h = hash_secret_salt;
+  while (*s)
+    h = CHAR_HASH(h, *s++);
+  return h;
+}
+
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
+{
+  size_t i;
+  if (table->size == 0) {
+    size_t tsize;
+    if (!createSize)
+      return NULL;
+    table->power = INIT_POWER;
+    /* table->size is a power of 2 */
+    table->size = (size_t)1 << INIT_POWER;
+    tsize = table->size * sizeof(NAMED *);
+    table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+    if (!table->v) {
+      table->size = 0;
+      return NULL;
+    }
+    memset(table->v, 0, tsize);
+    i = hash(parser, name) & ((unsigned long)table->size - 1);
+  }
+  else {
+    unsigned long h = hash(parser, name);
+    unsigned long mask = (unsigned long)table->size - 1;
+    unsigned char step = 0;
+    i = h & mask;
+    while (table->v[i]) {
+      if (keyeq(name, table->v[i]->name))
+        return table->v[i];
+      if (!step)
+        step = PROBE_STEP(h, mask, table->power);
+      i < step ? (i += table->size - step) : (i -= step);
+    }
+    if (!createSize)
+      return NULL;
+
+    /* check for overflow (table is half full) */
+    if (table->used >> (table->power - 1)) {
+      unsigned char newPower = table->power + 1;
+      size_t newSize = (size_t)1 << newPower;
+      unsigned long newMask = (unsigned long)newSize - 1;
+      size_t tsize = newSize * sizeof(NAMED *);
+      NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+      if (!newV)
+        return NULL;
+      memset(newV, 0, tsize);
+      for (i = 0; i < table->size; i++)
+        if (table->v[i]) {
+          unsigned long newHash = hash(parser, table->v[i]->name);
+          size_t j = newHash & newMask;
+          step = 0;
+          while (newV[j]) {
+            if (!step)
+              step = PROBE_STEP(newHash, newMask, newPower);
+            j < step ? (j += newSize - step) : (j -= step);
+          }
+          newV[j] = table->v[i];
+        }
+      table->mem->free_fcn(table->v);
+      table->v = newV;
+      table->power = newPower;
+      table->size = newSize;
+      i = h & newMask;
+      step = 0;
+      while (table->v[i]) {
+        if (!step)
+          step = PROBE_STEP(h, newMask, newPower);
+        i < step ? (i += newSize - step) : (i -= step);
+      }
+    }
+  }
+  table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+  if (!table->v[i])
+    return NULL;
+  memset(table->v[i], 0, createSize);
+  table->v[i]->name = name;
+  (table->used)++;
+  return table->v[i];
+}
+
+static void FASTCALL
+hashTableClear(HASH_TABLE *table)
+{
+  size_t i;
+  for (i = 0; i < table->size; i++) {
+    table->mem->free_fcn(table->v[i]);
+    table->v[i] = NULL;
+  }
+  table->used = 0;
+}
+
+static void FASTCALL
+hashTableDestroy(HASH_TABLE *table)
+{
+  size_t i;
+  for (i = 0; i < table->size; i++)
+    table->mem->free_fcn(table->v[i]);
+  table->mem->free_fcn(table->v);
+}
+
+static void FASTCALL
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
+{
+  p->power = 0;
+  p->size = 0;
+  p->used = 0;
+  p->v = NULL;
+  p->mem = ms;
+}
+
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+  iter->p = table->v;
+  iter->end = iter->p + table->size;
+}
+
+static NAMED * FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+  while (iter->p != iter->end) {
+    NAMED *tem = *(iter->p)++;
+    if (tem)
+      return tem;
+  }
+  return NULL;
+}
+
+static void FASTCALL
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
+{
+  pool->blocks = NULL;
+  pool->freeBlocks = NULL;
+  pool->start = NULL;
+  pool->ptr = NULL;
+  pool->end = NULL;
+  pool->mem = ms;
+}
+
+static void FASTCALL
+poolClear(STRING_POOL *pool)
+{
+  if (!pool->freeBlocks)
+    pool->freeBlocks = pool->blocks;
+  else {
+    BLOCK *p = pool->blocks;
+    while (p) {
+      BLOCK *tem = p->next;
+      p->next = pool->freeBlocks;
+      pool->freeBlocks = p;
+      p = tem;
+    }
+  }
+  pool->blocks = NULL;
+  pool->start = NULL;
+  pool->ptr = NULL;
+  pool->end = NULL;
+}
+
+static void FASTCALL
+poolDestroy(STRING_POOL *pool)
+{
+  BLOCK *p = pool->blocks;
+  while (p) {
+    BLOCK *tem = p->next;
+    pool->mem->free_fcn(p);
+    p = tem;
+  }
+  p = pool->freeBlocks;
+  while (p) {
+    BLOCK *tem = p->next;
+    pool->mem->free_fcn(p);
+    p = tem;
+  }
+}
+
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+           const char *ptr, const char *end)
+{
+  if (!pool->ptr && !poolGrow(pool))
+    return NULL;
+  for (;;) {
+    XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+    if (ptr == end)
+      break;
+    if (!poolGrow(pool))
+      return NULL;
+  }
+  return pool->start;
+}
+
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+  do {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+  } while (*s++);
+  s = pool->start;
+  poolFinish(pool);
+  return s;
+}
+
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+  if (!pool->ptr && !poolGrow(pool))
+    return NULL;
+  for (; n > 0; --n, s++) {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+  }
+  s = pool->start;
+  poolFinish(pool);
+  return s;
+}
+
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s)
+{
+  while (*s) {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+    s++;
+  }
+  return pool->start;
+}
+
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+                const char *ptr, const char *end)
+{
+  if (!poolAppend(pool, enc, ptr, end))
+    return NULL;
+  if (pool->ptr == pool->end && !poolGrow(pool))
+    return NULL;
+  *(pool->ptr)++ = 0;
+  return pool->start;
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+  if (pool->freeBlocks) {
+    if (pool->start == 0) {
+      pool->blocks = pool->freeBlocks;
+      pool->freeBlocks = pool->freeBlocks->next;
+      pool->blocks->next = NULL;
+      pool->start = pool->blocks->s;
+      pool->end = pool->start + pool->blocks->size;
+      pool->ptr = pool->start;
+      return XML_TRUE;
+    }
+    if (pool->end - pool->start < pool->freeBlocks->size) {
+      BLOCK *tem = pool->freeBlocks->next;
+      pool->freeBlocks->next = pool->blocks;
+      pool->blocks = pool->freeBlocks;
+      pool->freeBlocks = tem;
+      memcpy(pool->blocks->s, pool->start,
+             (pool->end - pool->start) * sizeof(XML_Char));
+      pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+      pool->start = pool->blocks->s;
+      pool->end = pool->start + pool->blocks->size;
+      return XML_TRUE;
+    }
+  }
+  if (pool->blocks && pool->start == pool->blocks->s) {
+    int blockSize = (int)(pool->end - pool->start)*2;
+    BLOCK *temp = (BLOCK *)
+      pool->mem->realloc_fcn(pool->blocks,
+                             (offsetof(BLOCK, s)
+                              + blockSize * sizeof(XML_Char)));
+    if (temp == NULL)
+      return XML_FALSE;
+    pool->blocks = temp;
+    pool->blocks->size = blockSize;
+    pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+    pool->start = pool->blocks->s;
+    pool->end = pool->start + blockSize;
+  }
+  else {
+    BLOCK *tem;
+    int blockSize = (int)(pool->end - pool->start);
+    if (blockSize < INIT_BLOCK_SIZE)
+      blockSize = INIT_BLOCK_SIZE;
+    else
+      blockSize *= 2;
+    tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
+                                        + blockSize * sizeof(XML_Char));
+    if (!tem)
+      return XML_FALSE;
+    tem->size = blockSize;
+    tem->next = pool->blocks;
+    pool->blocks = tem;
+    if (pool->ptr != pool->start)
+      memcpy(tem->s, pool->start,
+             (pool->ptr - pool->start) * sizeof(XML_Char));
+    pool->ptr = tem->s + (pool->ptr - pool->start);
+    pool->start = tem->s;
+    pool->end = tem->s + blockSize;
+  }
+  return XML_TRUE;
+}
+
+static int FASTCALL
+nextScaffoldPart(XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  CONTENT_SCAFFOLD * me;
+  int next;
+
+  if (!dtd->scaffIndex) {
+    dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+    if (!dtd->scaffIndex)
+      return -1;
+    dtd->scaffIndex[0] = 0;
+  }
+
+  if (dtd->scaffCount >= dtd->scaffSize) {
+    CONTENT_SCAFFOLD *temp;
+    if (dtd->scaffold) {
+      temp = (CONTENT_SCAFFOLD *)
+        REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+      if (temp == NULL)
+        return -1;
+      dtd->scaffSize *= 2;
+    }
+    else {
+      temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+                                        * sizeof(CONTENT_SCAFFOLD));
+      if (temp == NULL)
+        return -1;
+      dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
+    }
+    dtd->scaffold = temp;
+  }
+  next = dtd->scaffCount++;
+  me = &dtd->scaffold[next];
+  if (dtd->scaffLevel) {
+    CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+    if (parent->lastchild) {
+      dtd->scaffold[parent->lastchild].nextsib = next;
+    }
+    if (!parent->childcnt)
+      parent->firstchild = next;
+    parent->lastchild = next;
+    parent->childcnt++;
+  }
+  me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
+  return next;
+}
+
+static void
+build_node(XML_Parser parser,
+           int src_node,
+           XML_Content *dest,
+           XML_Content **contpos,
+           XML_Char **strpos)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  dest->type = dtd->scaffold[src_node].type;
+  dest->quant = dtd->scaffold[src_node].quant;
+  if (dest->type == XML_CTYPE_NAME) {
+    const XML_Char *src;
+    dest->name = *strpos;
+    src = dtd->scaffold[src_node].name;
+    for (;;) {
+      *(*strpos)++ = *src;
+      if (!*src)
+        break;
+      src++;
+    }
+    dest->numchildren = 0;
+    dest->children = NULL;
+  }
+  else {
+    unsigned int i;
+    int cn;
+    dest->numchildren = dtd->scaffold[src_node].childcnt;
+    dest->children = *contpos;
+    *contpos += dest->numchildren;
+    for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+         i < dest->numchildren;
+         i++, cn = dtd->scaffold[cn].nextsib) {
+      build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+    }
+    dest->name = NULL;
+  }
+}
+
+static XML_Content *
+build_model (XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  XML_Content *ret;
+  XML_Content *cpos;
+  XML_Char * str;
+  int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+                   + (dtd->contentStringLen * sizeof(XML_Char)));
+
+  ret = (XML_Content *)MALLOC(allocsize);
+  if (!ret)
+    return NULL;
+
+  str =  (XML_Char *) (&ret[dtd->scaffCount]);
+  cpos = &ret[1];
+
+  build_node(parser, 0, ret, &cpos, &str);
+  return ret;
+}
+
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser,
+               const ENCODING *enc,
+               const char *ptr,
+               const char *end)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
+  ELEMENT_TYPE *ret;
+
+  if (!name)
+    return NULL;
+  ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+  if (!ret)
+    return NULL;
+  if (ret->name != name)
+    poolDiscard(&dtd->pool);
+  else {
+    poolFinish(&dtd->pool);
+    if (!setElementTypePrefix(parser, ret))
+      return NULL;
+  }
+  return ret;
+}

+ 1336 - 0
libs/expat/lib/xmlrole.c

@@ -0,0 +1,1336 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmlrole.h"
+#include "ascii.h"
+
+/* Doesn't check:
+
+ that ,| are not mixed in a model group
+ content of literals
+
+*/
+
+static const char KW_ANY[] = {
+    ASCII_A, ASCII_N, ASCII_Y, '\0' };
+static const char KW_ATTLIST[] = {
+    ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
+static const char KW_CDATA[] = {
+    ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_DOCTYPE[] = {
+    ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
+static const char KW_ELEMENT[] = {
+    ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
+static const char KW_EMPTY[] = {
+    ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
+static const char KW_ENTITIES[] = {
+    ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
+    '\0' };
+static const char KW_ENTITY[] = {
+    ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+static const char KW_FIXED[] = {
+    ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
+static const char KW_ID[] = {
+    ASCII_I, ASCII_D, '\0' };
+static const char KW_IDREF[] = {
+    ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+static const char KW_IDREFS[] = {
+    ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+#ifdef XML_DTD
+static const char KW_IGNORE[] = {
+    ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
+#endif
+static const char KW_IMPLIED[] = {
+    ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
+#ifdef XML_DTD
+static const char KW_INCLUDE[] = {
+    ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
+#endif
+static const char KW_NDATA[] = {
+    ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_NMTOKEN[] = {
+    ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+static const char KW_NMTOKENS[] = {
+    ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
+    '\0' };
+static const char KW_NOTATION[] =
+    { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
+      '\0' };
+static const char KW_PCDATA[] = {
+    ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_PUBLIC[] = {
+    ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
+static const char KW_REQUIRED[] = {
+    ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
+    '\0' };
+static const char KW_SYSTEM[] = {
+    ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
+
+#ifndef MIN_BYTES_PER_CHAR
+#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+#endif
+
+#ifdef XML_DTD
+#define setTopLevel(state) \
+  ((state)->handler = ((state)->documentEntity \
+                       ? internalSubset \
+                       : externalSubset1))
+#else /* not XML_DTD */
+#define setTopLevel(state) ((state)->handler = internalSubset)
+#endif /* not XML_DTD */
+
+typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
+                                   int tok,
+                                   const char *ptr,
+                                   const char *end,
+                                   const ENCODING *enc);
+
+static PROLOG_HANDLER
+  prolog0, prolog1, prolog2,
+  doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
+  internalSubset,
+  entity0, entity1, entity2, entity3, entity4, entity5, entity6,
+  entity7, entity8, entity9, entity10,
+  notation0, notation1, notation2, notation3, notation4,
+  attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
+  attlist7, attlist8, attlist9,
+  element0, element1, element2, element3, element4, element5, element6,
+  element7,
+#ifdef XML_DTD
+  externalSubset0, externalSubset1,
+  condSect0, condSect1, condSect2,
+#endif /* XML_DTD */
+  declClose,
+  error;
+
+static int FASTCALL common(PROLOG_STATE *state, int tok);
+
+static int PTRCALL
+prolog0(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    state->handler = prolog1;
+    return XML_ROLE_NONE;
+  case XML_TOK_XML_DECL:
+    state->handler = prolog1;
+    return XML_ROLE_XML_DECL;
+  case XML_TOK_PI:
+    state->handler = prolog1;
+    return XML_ROLE_PI;
+  case XML_TOK_COMMENT:
+    state->handler = prolog1;
+    return XML_ROLE_COMMENT;
+  case XML_TOK_BOM:
+    return XML_ROLE_NONE;
+  case XML_TOK_DECL_OPEN:
+    if (!XmlNameMatchesAscii(enc,
+                             ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                             end,
+                             KW_DOCTYPE))
+      break;
+    state->handler = doctype0;
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_INSTANCE_START:
+    state->handler = error;
+    return XML_ROLE_INSTANCE_START;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+prolog1(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_PI:
+    return XML_ROLE_PI;
+  case XML_TOK_COMMENT:
+    return XML_ROLE_COMMENT;
+  case XML_TOK_BOM:
+    return XML_ROLE_NONE;
+  case XML_TOK_DECL_OPEN:
+    if (!XmlNameMatchesAscii(enc,
+                             ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                             end,
+                             KW_DOCTYPE))
+      break;
+    state->handler = doctype0;
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_INSTANCE_START:
+    state->handler = error;
+    return XML_ROLE_INSTANCE_START;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+prolog2(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_PI:
+    return XML_ROLE_PI;
+  case XML_TOK_COMMENT:
+    return XML_ROLE_COMMENT;
+  case XML_TOK_INSTANCE_START:
+    state->handler = error;
+    return XML_ROLE_INSTANCE_START;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype0(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = doctype1;
+    return XML_ROLE_DOCTYPE_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype1(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_OPEN_BRACKET:
+    state->handler = internalSubset;
+    return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+  case XML_TOK_DECL_CLOSE:
+    state->handler = prolog2;
+    return XML_ROLE_DOCTYPE_CLOSE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+      state->handler = doctype3;
+      return XML_ROLE_DOCTYPE_NONE;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+      state->handler = doctype2;
+      return XML_ROLE_DOCTYPE_NONE;
+    }
+    break;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype2(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = doctype3;
+    return XML_ROLE_DOCTYPE_PUBLIC_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype3(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = doctype4;
+    return XML_ROLE_DOCTYPE_SYSTEM_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype4(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_OPEN_BRACKET:
+    state->handler = internalSubset;
+    return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+  case XML_TOK_DECL_CLOSE:
+    state->handler = prolog2;
+    return XML_ROLE_DOCTYPE_CLOSE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+doctype5(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_DECL_CLOSE:
+    state->handler = prolog2;
+    return XML_ROLE_DOCTYPE_CLOSE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+internalSubset(PROLOG_STATE *state,
+               int tok,
+               const char *ptr,
+               const char *end,
+               const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_DECL_OPEN:
+    if (XmlNameMatchesAscii(enc,
+                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_ENTITY)) {
+      state->handler = entity0;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    if (XmlNameMatchesAscii(enc,
+                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_ATTLIST)) {
+      state->handler = attlist0;
+      return XML_ROLE_ATTLIST_NONE;
+    }
+    if (XmlNameMatchesAscii(enc,
+                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_ELEMENT)) {
+      state->handler = element0;
+      return XML_ROLE_ELEMENT_NONE;
+    }
+    if (XmlNameMatchesAscii(enc,
+                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_NOTATION)) {
+      state->handler = notation0;
+      return XML_ROLE_NOTATION_NONE;
+    }
+    break;
+  case XML_TOK_PI:
+    return XML_ROLE_PI;
+  case XML_TOK_COMMENT:
+    return XML_ROLE_COMMENT;
+  case XML_TOK_PARAM_ENTITY_REF:
+    return XML_ROLE_PARAM_ENTITY_REF;
+  case XML_TOK_CLOSE_BRACKET:
+    state->handler = doctype5;
+    return XML_ROLE_DOCTYPE_NONE;
+  case XML_TOK_NONE:
+    return XML_ROLE_NONE;
+  }
+  return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+externalSubset0(PROLOG_STATE *state,
+                int tok,
+                const char *ptr,
+                const char *end,
+                const ENCODING *enc)
+{
+  state->handler = externalSubset1;
+  if (tok == XML_TOK_XML_DECL)
+    return XML_ROLE_TEXT_DECL;
+  return externalSubset1(state, tok, ptr, end, enc);
+}
+
+static int PTRCALL
+externalSubset1(PROLOG_STATE *state,
+                int tok,
+                const char *ptr,
+                const char *end,
+                const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_COND_SECT_OPEN:
+    state->handler = condSect0;
+    return XML_ROLE_NONE;
+  case XML_TOK_COND_SECT_CLOSE:
+    if (state->includeLevel == 0)
+      break;
+    state->includeLevel -= 1;
+    return XML_ROLE_NONE;
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_CLOSE_BRACKET:
+    break;
+  case XML_TOK_NONE:
+    if (state->includeLevel)
+      break;
+    return XML_ROLE_NONE;
+  default:
+    return internalSubset(state, tok, ptr, end, enc);
+  }
+  return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+entity0(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_PERCENT:
+    state->handler = entity1;
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_NAME:
+    state->handler = entity2;
+    return XML_ROLE_GENERAL_ENTITY_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity1(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_NAME:
+    state->handler = entity7;
+    return XML_ROLE_PARAM_ENTITY_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity2(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+      state->handler = entity4;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+      state->handler = entity3;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    break;
+  case XML_TOK_LITERAL:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ENTITY_NONE;
+    return XML_ROLE_ENTITY_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity3(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = entity4;
+    return XML_ROLE_ENTITY_PUBLIC_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity4(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = entity5;
+    return XML_ROLE_ENTITY_SYSTEM_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity5(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_DECL_CLOSE:
+    setTopLevel(state);
+    return XML_ROLE_ENTITY_COMPLETE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
+      state->handler = entity6;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    break;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity6(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_NAME:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ENTITY_NONE;
+    return XML_ROLE_ENTITY_NOTATION_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity7(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+      state->handler = entity9;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+      state->handler = entity8;
+      return XML_ROLE_ENTITY_NONE;
+    }
+    break;
+  case XML_TOK_LITERAL:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ENTITY_NONE;
+    return XML_ROLE_ENTITY_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity8(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = entity9;
+    return XML_ROLE_ENTITY_PUBLIC_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity9(PROLOG_STATE *state,
+        int tok,
+        const char *ptr,
+        const char *end,
+        const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = entity10;
+    return XML_ROLE_ENTITY_SYSTEM_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+entity10(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ENTITY_NONE;
+  case XML_TOK_DECL_CLOSE:
+    setTopLevel(state);
+    return XML_ROLE_ENTITY_COMPLETE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+notation0(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NOTATION_NONE;
+  case XML_TOK_NAME:
+    state->handler = notation1;
+    return XML_ROLE_NOTATION_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+notation1(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NOTATION_NONE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+      state->handler = notation3;
+      return XML_ROLE_NOTATION_NONE;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+      state->handler = notation2;
+      return XML_ROLE_NOTATION_NONE;
+    }
+    break;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+notation2(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NOTATION_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = notation4;
+    return XML_ROLE_NOTATION_PUBLIC_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+notation3(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NOTATION_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_NOTATION_NONE;
+    return XML_ROLE_NOTATION_SYSTEM_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+notation4(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NOTATION_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_NOTATION_NONE;
+    return XML_ROLE_NOTATION_SYSTEM_ID;
+  case XML_TOK_DECL_CLOSE:
+    setTopLevel(state);
+    return XML_ROLE_NOTATION_NO_SYSTEM_ID;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist0(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = attlist1;
+    return XML_ROLE_ATTLIST_ELEMENT_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist1(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_DECL_CLOSE:
+    setTopLevel(state);
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = attlist2;
+    return XML_ROLE_ATTRIBUTE_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist2(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_NAME:
+    {
+      static const char * const types[] = {
+        KW_CDATA,
+        KW_ID,
+        KW_IDREF,
+        KW_IDREFS,
+        KW_ENTITY,
+        KW_ENTITIES,
+        KW_NMTOKEN,
+        KW_NMTOKENS,
+      };
+      int i;
+      for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
+        if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
+          state->handler = attlist8;
+          return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+        }
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
+      state->handler = attlist5;
+      return XML_ROLE_ATTLIST_NONE;
+    }
+    break;
+  case XML_TOK_OPEN_PAREN:
+    state->handler = attlist3;
+    return XML_ROLE_ATTLIST_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist3(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_NMTOKEN:
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = attlist4;
+    return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist4(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_CLOSE_PAREN:
+    state->handler = attlist8;
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_OR:
+    state->handler = attlist3;
+    return XML_ROLE_ATTLIST_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist5(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_OPEN_PAREN:
+    state->handler = attlist6;
+    return XML_ROLE_ATTLIST_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist6(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_NAME:
+    state->handler = attlist7;
+    return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist7(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_CLOSE_PAREN:
+    state->handler = attlist8;
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_OR:
+    state->handler = attlist6;
+    return XML_ROLE_ATTLIST_NONE;
+  }
+  return common(state, tok);
+}
+
+/* default value */
+static int PTRCALL
+attlist8(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_POUND_NAME:
+    if (XmlNameMatchesAscii(enc,
+                            ptr + MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_IMPLIED)) {
+      state->handler = attlist1;
+      return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
+    }
+    if (XmlNameMatchesAscii(enc,
+                            ptr + MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_REQUIRED)) {
+      state->handler = attlist1;
+      return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
+    }
+    if (XmlNameMatchesAscii(enc,
+                            ptr + MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_FIXED)) {
+      state->handler = attlist9;
+      return XML_ROLE_ATTLIST_NONE;
+    }
+    break;
+  case XML_TOK_LITERAL:
+    state->handler = attlist1;
+    return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+attlist9(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ATTLIST_NONE;
+  case XML_TOK_LITERAL:
+    state->handler = attlist1;
+    return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element0(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = element1;
+    return XML_ROLE_ELEMENT_NAME;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element1(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+      return XML_ROLE_CONTENT_EMPTY;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+      return XML_ROLE_CONTENT_ANY;
+    }
+    break;
+  case XML_TOK_OPEN_PAREN:
+    state->handler = element2;
+    state->level = 1;
+    return XML_ROLE_GROUP_OPEN;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element2(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_POUND_NAME:
+    if (XmlNameMatchesAscii(enc,
+                            ptr + MIN_BYTES_PER_CHAR(enc),
+                            end,
+                            KW_PCDATA)) {
+      state->handler = element3;
+      return XML_ROLE_CONTENT_PCDATA;
+    }
+    break;
+  case XML_TOK_OPEN_PAREN:
+    state->level = 2;
+    state->handler = element6;
+    return XML_ROLE_GROUP_OPEN;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT;
+  case XML_TOK_NAME_QUESTION:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_OPT;
+  case XML_TOK_NAME_ASTERISK:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_REP;
+  case XML_TOK_NAME_PLUS:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_PLUS;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element3(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_CLOSE_PAREN:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ELEMENT_NONE;
+    return XML_ROLE_GROUP_CLOSE;
+  case XML_TOK_CLOSE_PAREN_ASTERISK:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ELEMENT_NONE;
+    return XML_ROLE_GROUP_CLOSE_REP;
+  case XML_TOK_OR:
+    state->handler = element4;
+    return XML_ROLE_ELEMENT_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element4(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = element5;
+    return XML_ROLE_CONTENT_ELEMENT;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element5(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_CLOSE_PAREN_ASTERISK:
+    state->handler = declClose;
+    state->role_none = XML_ROLE_ELEMENT_NONE;
+    return XML_ROLE_GROUP_CLOSE_REP;
+  case XML_TOK_OR:
+    state->handler = element4;
+    return XML_ROLE_ELEMENT_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element6(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_OPEN_PAREN:
+    state->level += 1;
+    return XML_ROLE_GROUP_OPEN;
+  case XML_TOK_NAME:
+  case XML_TOK_PREFIXED_NAME:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT;
+  case XML_TOK_NAME_QUESTION:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_OPT;
+  case XML_TOK_NAME_ASTERISK:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_REP;
+  case XML_TOK_NAME_PLUS:
+    state->handler = element7;
+    return XML_ROLE_CONTENT_ELEMENT_PLUS;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+element7(PROLOG_STATE *state,
+         int tok,
+         const char *ptr,
+         const char *end,
+         const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_ELEMENT_NONE;
+  case XML_TOK_CLOSE_PAREN:
+    state->level -= 1;
+    if (state->level == 0) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+    }
+    return XML_ROLE_GROUP_CLOSE;
+  case XML_TOK_CLOSE_PAREN_ASTERISK:
+    state->level -= 1;
+    if (state->level == 0) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+    }
+    return XML_ROLE_GROUP_CLOSE_REP;
+  case XML_TOK_CLOSE_PAREN_QUESTION:
+    state->level -= 1;
+    if (state->level == 0) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+    }
+    return XML_ROLE_GROUP_CLOSE_OPT;
+  case XML_TOK_CLOSE_PAREN_PLUS:
+    state->level -= 1;
+    if (state->level == 0) {
+      state->handler = declClose;
+      state->role_none = XML_ROLE_ELEMENT_NONE;
+    }
+    return XML_ROLE_GROUP_CLOSE_PLUS;
+  case XML_TOK_COMMA:
+    state->handler = element6;
+    return XML_ROLE_GROUP_SEQUENCE;
+  case XML_TOK_OR:
+    state->handler = element6;
+    return XML_ROLE_GROUP_CHOICE;
+  }
+  return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+condSect0(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_NAME:
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
+      state->handler = condSect1;
+      return XML_ROLE_NONE;
+    }
+    if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
+      state->handler = condSect2;
+      return XML_ROLE_NONE;
+    }
+    break;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+condSect1(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_OPEN_BRACKET:
+    state->handler = externalSubset1;
+    state->includeLevel += 1;
+    return XML_ROLE_NONE;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+condSect2(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return XML_ROLE_NONE;
+  case XML_TOK_OPEN_BRACKET:
+    state->handler = externalSubset1;
+    return XML_ROLE_IGNORE_SECT;
+  }
+  return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+declClose(PROLOG_STATE *state,
+          int tok,
+          const char *ptr,
+          const char *end,
+          const ENCODING *enc)
+{
+  switch (tok) {
+  case XML_TOK_PROLOG_S:
+    return state->role_none;
+  case XML_TOK_DECL_CLOSE:
+    setTopLevel(state);
+    return state->role_none;
+  }
+  return common(state, tok);
+}
+
+static int PTRCALL
+error(PROLOG_STATE *state,
+      int tok,
+      const char *ptr,
+      const char *end,
+      const ENCODING *enc)
+{
+  return XML_ROLE_NONE;
+}
+
+static int FASTCALL
+common(PROLOG_STATE *state, int tok)
+{
+#ifdef XML_DTD
+  if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
+    return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#endif
+  state->handler = error;
+  return XML_ROLE_ERROR;
+}
+
+void
+XmlPrologStateInit(PROLOG_STATE *state)
+{
+  state->handler = prolog0;
+#ifdef XML_DTD
+  state->documentEntity = 1;
+  state->includeLevel = 0;
+  state->inEntityValue = 0;
+#endif /* XML_DTD */
+}
+
+#ifdef XML_DTD
+
+void
+XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
+{
+  state->handler = externalSubset0;
+  state->documentEntity = 0;
+  state->includeLevel = 0;
+}
+
+#endif /* XML_DTD */

+ 114 - 0
libs/expat/lib/xmlrole.h

@@ -0,0 +1,114 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#ifndef XmlRole_INCLUDED
+#define XmlRole_INCLUDED 1
+
+#ifdef __VMS
+/*      0        1         2         3      0        1         2         3
+        1234567890123456789012345678901     1234567890123456789012345678901 */
+#define XmlPrologStateInitExternalEntity    XmlPrologStateInitExternalEnt
+#endif
+
+#include "xmltok.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+  XML_ROLE_ERROR = -1,
+  XML_ROLE_NONE = 0,
+  XML_ROLE_XML_DECL,
+  XML_ROLE_INSTANCE_START,
+  XML_ROLE_DOCTYPE_NONE,
+  XML_ROLE_DOCTYPE_NAME,
+  XML_ROLE_DOCTYPE_SYSTEM_ID,
+  XML_ROLE_DOCTYPE_PUBLIC_ID,
+  XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
+  XML_ROLE_DOCTYPE_CLOSE,
+  XML_ROLE_GENERAL_ENTITY_NAME,
+  XML_ROLE_PARAM_ENTITY_NAME,
+  XML_ROLE_ENTITY_NONE,
+  XML_ROLE_ENTITY_VALUE,
+  XML_ROLE_ENTITY_SYSTEM_ID,
+  XML_ROLE_ENTITY_PUBLIC_ID,
+  XML_ROLE_ENTITY_COMPLETE,
+  XML_ROLE_ENTITY_NOTATION_NAME,
+  XML_ROLE_NOTATION_NONE,
+  XML_ROLE_NOTATION_NAME,
+  XML_ROLE_NOTATION_SYSTEM_ID,
+  XML_ROLE_NOTATION_NO_SYSTEM_ID,
+  XML_ROLE_NOTATION_PUBLIC_ID,
+  XML_ROLE_ATTRIBUTE_NAME,
+  XML_ROLE_ATTRIBUTE_TYPE_CDATA,
+  XML_ROLE_ATTRIBUTE_TYPE_ID,
+  XML_ROLE_ATTRIBUTE_TYPE_IDREF,
+  XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
+  XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
+  XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
+  XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
+  XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
+  XML_ROLE_ATTRIBUTE_ENUM_VALUE,
+  XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
+  XML_ROLE_ATTLIST_NONE,
+  XML_ROLE_ATTLIST_ELEMENT_NAME,
+  XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
+  XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
+  XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
+  XML_ROLE_FIXED_ATTRIBUTE_VALUE,
+  XML_ROLE_ELEMENT_NONE,
+  XML_ROLE_ELEMENT_NAME,
+  XML_ROLE_CONTENT_ANY,
+  XML_ROLE_CONTENT_EMPTY,
+  XML_ROLE_CONTENT_PCDATA,
+  XML_ROLE_GROUP_OPEN,
+  XML_ROLE_GROUP_CLOSE,
+  XML_ROLE_GROUP_CLOSE_REP,
+  XML_ROLE_GROUP_CLOSE_OPT,
+  XML_ROLE_GROUP_CLOSE_PLUS,
+  XML_ROLE_GROUP_CHOICE,
+  XML_ROLE_GROUP_SEQUENCE,
+  XML_ROLE_CONTENT_ELEMENT,
+  XML_ROLE_CONTENT_ELEMENT_REP,
+  XML_ROLE_CONTENT_ELEMENT_OPT,
+  XML_ROLE_CONTENT_ELEMENT_PLUS,
+  XML_ROLE_PI,
+  XML_ROLE_COMMENT,
+#ifdef XML_DTD
+  XML_ROLE_TEXT_DECL,
+  XML_ROLE_IGNORE_SECT,
+  XML_ROLE_INNER_PARAM_ENTITY_REF,
+#endif /* XML_DTD */
+  XML_ROLE_PARAM_ENTITY_REF
+};
+
+typedef struct prolog_state {
+  int (PTRCALL *handler) (struct prolog_state *state,
+                          int tok,
+                          const char *ptr,
+                          const char *end,
+                          const ENCODING *enc);
+  unsigned level;
+  int role_none;
+#ifdef XML_DTD
+  unsigned includeLevel;
+  int documentEntity;
+  int inEntityValue;
+#endif /* XML_DTD */
+} PROLOG_STATE;
+
+void XmlPrologStateInit(PROLOG_STATE *);
+#ifdef XML_DTD
+void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
+#endif /* XML_DTD */
+
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlRole_INCLUDED */

+ 1651 - 0
libs/expat/lib/xmltok.c

@@ -0,0 +1,1651 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmltok.h"
+#include "nametab.h"
+
+#ifdef XML_DTD
+#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
+#else
+#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
+#endif
+
+#define VTABLE1 \
+  { PREFIX(prologTok), PREFIX(contentTok), \
+    PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
+  { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
+  PREFIX(sameName), \
+  PREFIX(nameMatchesAscii), \
+  PREFIX(nameLength), \
+  PREFIX(skipS), \
+  PREFIX(getAtts), \
+  PREFIX(charRefNumber), \
+  PREFIX(predefinedEntityName), \
+  PREFIX(updatePosition), \
+  PREFIX(isPublicId)
+
+#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
+
+#define UCS2_GET_NAMING(pages, hi, lo) \
+   (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+
+/* A 2 byte UTF-8 representation splits the characters 11 bits between
+   the bottom 5 and 6 bits of the bytes.  We need 8 bits to index into
+   pages, 3 bits to add to that index and 5 bits to generate the mask.
+*/
+#define UTF8_GET_NAMING2(pages, byte) \
+    (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+                      + ((((byte)[0]) & 3) << 1) \
+                      + ((((byte)[1]) >> 5) & 1)] \
+         & (1 << (((byte)[1]) & 0x1F)))
+
+/* A 3 byte UTF-8 representation splits the characters 16 bits between
+   the bottom 4, 6 and 6 bits of the bytes.  We need 8 bits to index
+   into pages, 3 bits to add to that index and 5 bits to generate the
+   mask.
+*/
+#define UTF8_GET_NAMING3(pages, byte) \
+  (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
+                             + ((((byte)[1]) >> 2) & 0xF)] \
+                       << 3) \
+                      + ((((byte)[1]) & 3) << 1) \
+                      + ((((byte)[2]) >> 5) & 1)] \
+         & (1 << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+  ((n) == 2 \
+  ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+  : ((n) == 3 \
+     ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
+     : 0))
+
+/* Detection of invalid UTF-8 sequences is based on Table 3.1B
+   of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
+   with the additional restriction of not allowing the Unicode
+   code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
+   Implementation details:
+     (A & 0x80) == 0     means A < 0x80
+   and
+     (A & 0xC0) == 0xC0  means A > 0xBF
+*/
+
+#define UTF8_INVALID2(p) \
+  ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
+
+#define UTF8_INVALID3(p) \
+  (((p)[2] & 0x80) == 0 \
+  || \
+  ((*p) == 0xEF && (p)[1] == 0xBF \
+    ? \
+    (p)[2] > 0xBD \
+    : \
+    ((p)[2] & 0xC0) == 0xC0) \
+  || \
+  ((*p) == 0xE0 \
+    ? \
+    (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
+    : \
+    ((p)[1] & 0x80) == 0 \
+    || \
+    ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
+
+#define UTF8_INVALID4(p) \
+  (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
+  || \
+  ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
+  || \
+  ((*p) == 0xF0 \
+    ? \
+    (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
+    : \
+    ((p)[1] & 0x80) == 0 \
+    || \
+    ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
+
+static int PTRFASTCALL
+isNever(const ENCODING *enc, const char *p)
+{
+  return 0;
+}
+
+static int PTRFASTCALL
+utf8_isName2(const ENCODING *enc, const char *p)
+{
+  return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isName3(const ENCODING *enc, const char *p)
+{
+  return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
+}
+
+#define utf8_isName4 isNever
+
+static int PTRFASTCALL
+utf8_isNmstrt2(const ENCODING *enc, const char *p)
+{
+  return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isNmstrt3(const ENCODING *enc, const char *p)
+{
+  return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
+}
+
+#define utf8_isNmstrt4 isNever
+
+static int PTRFASTCALL
+utf8_isInvalid2(const ENCODING *enc, const char *p)
+{
+  return UTF8_INVALID2((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid3(const ENCODING *enc, const char *p)
+{
+  return UTF8_INVALID3((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid4(const ENCODING *enc, const char *p)
+{
+  return UTF8_INVALID4((const unsigned char *)p);
+}
+
+struct normal_encoding {
+  ENCODING enc;
+  unsigned char type[256];
+#ifdef XML_MIN_SIZE
+  int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
+  int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
+  int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
+#endif /* XML_MIN_SIZE */
+  int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
+  int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+};
+
+#define AS_NORMAL_ENCODING(enc)   ((const struct normal_encoding *) (enc))
+
+#ifdef XML_MIN_SIZE
+
+#define STANDARD_VTABLE(E) \
+ E ## byteType, \
+ E ## isNameMin, \
+ E ## isNmstrtMin, \
+ E ## byteToAscii, \
+ E ## charMatches,
+
+#else
+
+#define STANDARD_VTABLE(E) /* as nothing */
+
+#endif
+
+#define NORMAL_VTABLE(E) \
+ E ## isName2, \
+ E ## isName3, \
+ E ## isName4, \
+ E ## isNmstrt2, \
+ E ## isNmstrt3, \
+ E ## isNmstrt4, \
+ E ## isInvalid2, \
+ E ## isInvalid3, \
+ E ## isInvalid4
+
+static int FASTCALL checkCharRefNumber(int);
+
+#include "xmltok_impl.h"
+#include "ascii.h"
+
+#ifdef XML_MIN_SIZE
+#define sb_isNameMin isNever
+#define sb_isNmstrtMin isNever
+#endif
+
+#ifdef XML_MIN_SIZE
+#define MINBPC(enc) ((enc)->minBytesPerChar)
+#else
+/* minimum bytes per character */
+#define MINBPC(enc) 1
+#endif
+
+#define SB_BYTE_TYPE(enc, p) \
+  (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+
+#ifdef XML_MIN_SIZE
+static int PTRFASTCALL
+sb_byteType(const ENCODING *enc, const char *p)
+{
+  return SB_BYTE_TYPE(enc, p);
+}
+#define BYTE_TYPE(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
+#else
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define BYTE_TO_ASCII(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
+static int PTRFASTCALL
+sb_byteToAscii(const ENCODING *enc, const char *p)
+{
+  return *p;
+}
+#else
+#define BYTE_TO_ASCII(enc, p) (*(p))
+#endif
+
+#define IS_NAME_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
+
+#ifdef XML_MIN_SIZE
+#define IS_NAME_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
+#else
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define CHAR_MATCHES(enc, p, c) \
+ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
+static int PTRCALL
+sb_charMatches(const ENCODING *enc, const char *p, int c)
+{
+  return *p == c;
+}
+#else
+/* c is an ASCII character */
+#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+#endif
+
+#define PREFIX(ident) normal_ ## ident
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+enum {  /* UTF8_cvalN is value of masked first byte of N byte sequence */
+  UTF8_cval1 = 0x00,
+  UTF8_cval2 = 0xc0,
+  UTF8_cval3 = 0xe0,
+  UTF8_cval4 = 0xf0
+};
+
+static void PTRCALL
+utf8_toUtf8(const ENCODING *enc,
+            const char **fromP, const char *fromLim,
+            char **toP, const char *toLim)
+{
+  char *to;
+  const char *from;
+  if (fromLim - *fromP > toLim - *toP) {
+    /* Avoid copying partial characters. */
+    for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
+      if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
+        break;
+  }
+  for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+    *to = *from;
+  *fromP = from;
+  *toP = to;
+}
+
+static void PTRCALL
+utf8_toUtf16(const ENCODING *enc,
+             const char **fromP, const char *fromLim,
+             unsigned short **toP, const unsigned short *toLim)
+{
+  unsigned short *to = *toP;
+  const char *from = *fromP;
+  while (from != fromLim && to != toLim) {
+    switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+    case BT_LEAD2:
+      *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
+      from += 2;
+      break;
+    case BT_LEAD3:
+      *to++ = (unsigned short)(((from[0] & 0xf) << 12)
+                               | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
+      from += 3;
+      break;
+    case BT_LEAD4:
+      {
+        unsigned long n;
+        if (to + 1 == toLim)
+          goto after;
+        n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
+            | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+        n -= 0x10000;
+        to[0] = (unsigned short)((n >> 10) | 0xD800);
+        to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+        to += 2;
+        from += 4;
+      }
+      break;
+    default:
+      *to++ = *from++;
+      break;
+    }
+  }
+after:
+  *fromP = from;
+  *toP = to;
+}
+
+#ifdef XML_NS
+static const struct normal_encoding utf8_encoding_ns = {
+  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+  {
+#include "asciitab.h"
+#include "utf8tab.h"
+  },
+  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+#endif
+
+static const struct normal_encoding utf8_encoding = {
+  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+  },
+  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_utf8_encoding_ns = {
+  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+  {
+#include "iasciitab.h"
+#include "utf8tab.h"
+  },
+  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#endif
+
+static const struct normal_encoding internal_utf8_encoding = {
+  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+  },
+  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+static void PTRCALL
+latin1_toUtf8(const ENCODING *enc,
+              const char **fromP, const char *fromLim,
+              char **toP, const char *toLim)
+{
+  for (;;) {
+    unsigned char c;
+    if (*fromP == fromLim)
+      break;
+    c = (unsigned char)**fromP;
+    if (c & 0x80) {
+      if (toLim - *toP < 2)
+        break;
+      *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
+      *(*toP)++ = (char)((c & 0x3f) | 0x80);
+      (*fromP)++;
+    }
+    else {
+      if (*toP == toLim)
+        break;
+      *(*toP)++ = *(*fromP)++;
+    }
+  }
+}
+
+static void PTRCALL
+latin1_toUtf16(const ENCODING *enc,
+               const char **fromP, const char *fromLim,
+               unsigned short **toP, const unsigned short *toLim)
+{
+  while (*fromP != fromLim && *toP != toLim)
+    *(*toP)++ = (unsigned char)*(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding latin1_encoding_ns = {
+  { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+  {
+#include "asciitab.h"
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding latin1_encoding = {
+  { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(sb_)
+};
+
+static void PTRCALL
+ascii_toUtf8(const ENCODING *enc,
+             const char **fromP, const char *fromLim,
+             char **toP, const char *toLim)
+{
+  while (*fromP != fromLim && *toP != toLim)
+    *(*toP)++ = *(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding ascii_encoding_ns = {
+  { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+  {
+#include "asciitab.h"
+/* BT_NONXML == 0 */
+  },
+  STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding ascii_encoding = {
+  { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+/* BT_NONXML == 0 */
+  },
+  STANDARD_VTABLE(sb_)
+};
+
+static int PTRFASTCALL
+unicode_byte_type(char hi, char lo)
+{
+  switch ((unsigned char)hi) {
+  case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+    return BT_LEAD4;
+  case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+    return BT_TRAIL;
+  case 0xFF:
+    switch ((unsigned char)lo) {
+    case 0xFF:
+    case 0xFE:
+      return BT_NONXML;
+    }
+    break;
+  }
+  return BT_NONASCII;
+}
+
+#define DEFINE_UTF16_TO_UTF8(E) \
+static void  PTRCALL \
+E ## toUtf8(const ENCODING *enc, \
+            const char **fromP, const char *fromLim, \
+            char **toP, const char *toLim) \
+{ \
+  const char *from; \
+  for (from = *fromP; from != fromLim; from += 2) { \
+    int plane; \
+    unsigned char lo2; \
+    unsigned char lo = GET_LO(from); \
+    unsigned char hi = GET_HI(from); \
+    switch (hi) { \
+    case 0: \
+      if (lo < 0x80) { \
+        if (*toP == toLim) { \
+          *fromP = from; \
+          return; \
+        } \
+        *(*toP)++ = lo; \
+        break; \
+      } \
+      /* fall through */ \
+    case 0x1: case 0x2: case 0x3: \
+    case 0x4: case 0x5: case 0x6: case 0x7: \
+      if (toLim -  *toP < 2) { \
+        *fromP = from; \
+        return; \
+      } \
+      *(*toP)++ = ((lo >> 6) | (hi << 2) |  UTF8_cval2); \
+      *(*toP)++ = ((lo & 0x3f) | 0x80); \
+      break; \
+    default: \
+      if (toLim -  *toP < 3)  { \
+        *fromP = from; \
+        return; \
+      } \
+      /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+      *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+      *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+      *(*toP)++ = ((lo & 0x3f) | 0x80); \
+      break; \
+    case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
+      if (toLim -  *toP < 4) { \
+        *fromP = from; \
+        return; \
+      } \
+      plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+      *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
+      *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+      from += 2; \
+      lo2 = GET_LO(from); \
+      *(*toP)++ = (((lo & 0x3) << 4) \
+                   | ((GET_HI(from) & 0x3) << 2) \
+                   | (lo2 >> 6) \
+                   | 0x80); \
+      *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+      break; \
+    } \
+  } \
+  *fromP = from; \
+}
+
+#define DEFINE_UTF16_TO_UTF16(E) \
+static void  PTRCALL \
+E ## toUtf16(const ENCODING *enc, \
+             const char **fromP, const char *fromLim, \
+             unsigned short **toP, const unsigned short *toLim) \
+{ \
+  /* Avoid copying first half only of surrogate */ \
+  if (fromLim - *fromP > ((toLim - *toP) << 1) \
+      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+    fromLim -= 2; \
+  for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+    *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+}
+
+#define SET2(ptr, ch) \
+  (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[0])
+#define GET_HI(ptr) ((unsigned char)(ptr)[1])
+
+DEFINE_UTF16_TO_UTF8(little2_)
+DEFINE_UTF16_TO_UTF16(little2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define SET2(ptr, ch) \
+  (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[1])
+#define GET_HI(ptr) ((unsigned char)(ptr)[0])
+
+DEFINE_UTF16_TO_UTF8(big2_)
+DEFINE_UTF16_TO_UTF16(big2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 \
+  ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+  : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+  UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+  UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+little2_byteType(const ENCODING *enc, const char *p)
+{
+  return LITTLE2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+little2_byteToAscii(const ENCODING *enc, const char *p)
+{
+  return LITTLE2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+little2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+  return LITTLE2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+little2_isNameMin(const ENCODING *enc, const char *p)
+{
+  return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+little2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+  return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) little2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding little2_encoding_ns = {
+  { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+    1
+#else
+    0
+#endif
+  },
+  {
+#include "asciitab.h"
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding little2_encoding = {
+  { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+    1
+#else
+    0
+#endif
+  },
+  {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(little2_)
+};
+
+#if BYTEORDER != 4321
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_little2_encoding_ns = {
+  { VTABLE, 2, 0, 1 },
+  {
+#include "iasciitab.h"
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_little2_encoding = {
+  { VTABLE, 2, 0, 1 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+  ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+  : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+  UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+  UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+big2_byteType(const ENCODING *enc, const char *p)
+{
+  return BIG2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+big2_byteToAscii(const ENCODING *enc, const char *p)
+{
+  return BIG2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+big2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+  return BIG2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+big2_isNameMin(const ENCODING *enc, const char *p)
+{
+  return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+big2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+  return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) big2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding big2_encoding_ns = {
+  { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+  1
+#else
+  0
+#endif
+  },
+  {
+#include "asciitab.h"
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding big2_encoding = {
+  { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+  1
+#else
+  0
+#endif
+  },
+  {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(big2_)
+};
+
+#if BYTEORDER != 1234
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_big2_encoding_ns = {
+  { VTABLE, 2, 0, 1 },
+  {
+#include "iasciitab.h"
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_big2_encoding = {
+  { VTABLE, 2, 0, 1 },
+  {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+  },
+  STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+#undef PREFIX
+
+static int FASTCALL
+streqci(const char *s1, const char *s2)
+{
+  for (;;) {
+    char c1 = *s1++;
+    char c2 = *s2++;
+    if (ASCII_a <= c1 && c1 <= ASCII_z)
+      c1 += ASCII_A - ASCII_a;
+    if (ASCII_a <= c2 && c2 <= ASCII_z)
+      c2 += ASCII_A - ASCII_a;
+    if (c1 != c2)
+      return 0;
+    if (!c1)
+      break;
+  }
+  return 1;
+}
+
+static void PTRCALL
+initUpdatePosition(const ENCODING *enc, const char *ptr,
+                   const char *end, POSITION *pos)
+{
+  normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
+}
+
+static int
+toAscii(const ENCODING *enc, const char *ptr, const char *end)
+{
+  char buf[1];
+  char *p = buf;
+  XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
+  if (p == buf)
+    return -1;
+  else
+    return buf[0];
+}
+
+static int FASTCALL
+isSpace(int c)
+{
+  switch (c) {
+  case 0x20:
+  case 0xD:
+  case 0xA:
+  case 0x9:
+    return 1;
+  }
+  return 0;
+}
+
+/* Return 1 if there's just optional white space or there's an S
+   followed by name=val.
+*/
+static int
+parsePseudoAttribute(const ENCODING *enc,
+                     const char *ptr,
+                     const char *end,
+                     const char **namePtr,
+                     const char **nameEndPtr,
+                     const char **valPtr,
+                     const char **nextTokPtr)
+{
+  int c;
+  char open;
+  if (ptr == end) {
+    *namePtr = NULL;
+    return 1;
+  }
+  if (!isSpace(toAscii(enc, ptr, end))) {
+    *nextTokPtr = ptr;
+    return 0;
+  }
+  do {
+    ptr += enc->minBytesPerChar;
+  } while (isSpace(toAscii(enc, ptr, end)));
+  if (ptr == end) {
+    *namePtr = NULL;
+    return 1;
+  }
+  *namePtr = ptr;
+  for (;;) {
+    c = toAscii(enc, ptr, end);
+    if (c == -1) {
+      *nextTokPtr = ptr;
+      return 0;
+    }
+    if (c == ASCII_EQUALS) {
+      *nameEndPtr = ptr;
+      break;
+    }
+    if (isSpace(c)) {
+      *nameEndPtr = ptr;
+      do {
+        ptr += enc->minBytesPerChar;
+      } while (isSpace(c = toAscii(enc, ptr, end)));
+      if (c != ASCII_EQUALS) {
+        *nextTokPtr = ptr;
+        return 0;
+      }
+      break;
+    }
+    ptr += enc->minBytesPerChar;
+  }
+  if (ptr == *namePtr) {
+    *nextTokPtr = ptr;
+    return 0;
+  }
+  ptr += enc->minBytesPerChar;
+  c = toAscii(enc, ptr, end);
+  while (isSpace(c)) {
+    ptr += enc->minBytesPerChar;
+    c = toAscii(enc, ptr, end);
+  }
+  if (c != ASCII_QUOT && c != ASCII_APOS) {
+    *nextTokPtr = ptr;
+    return 0;
+  }
+  open = (char)c;
+  ptr += enc->minBytesPerChar;
+  *valPtr = ptr;
+  for (;; ptr += enc->minBytesPerChar) {
+    c = toAscii(enc, ptr, end);
+    if (c == open)
+      break;
+    if (!(ASCII_a <= c && c <= ASCII_z)
+        && !(ASCII_A <= c && c <= ASCII_Z)
+        && !(ASCII_0 <= c && c <= ASCII_9)
+        && c != ASCII_PERIOD
+        && c != ASCII_MINUS
+        && c != ASCII_UNDERSCORE) {
+      *nextTokPtr = ptr;
+      return 0;
+    }
+  }
+  *nextTokPtr = ptr + enc->minBytesPerChar;
+  return 1;
+}
+
+static const char KW_version[] = {
+  ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
+};
+
+static const char KW_encoding[] = {
+  ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
+};
+
+static const char KW_standalone[] = {
+  ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
+  ASCII_n, ASCII_e, '\0'
+};
+
+static const char KW_yes[] = {
+  ASCII_y, ASCII_e, ASCII_s,  '\0'
+};
+
+static const char KW_no[] = {
+  ASCII_n, ASCII_o,  '\0'
+};
+
+static int
+doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
+                                                 const char *,
+                                                 const char *),
+               int isGeneralTextEntity,
+               const ENCODING *enc,
+               const char *ptr,
+               const char *end,
+               const char **badPtr,
+               const char **versionPtr,
+               const char **versionEndPtr,
+               const char **encodingName,
+               const ENCODING **encoding,
+               int *standalone)
+{
+  const char *val = NULL;
+  const char *name = NULL;
+  const char *nameEnd = NULL;
+  ptr += 5 * enc->minBytesPerChar;
+  end -= 2 * enc->minBytesPerChar;
+  if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
+      || !name) {
+    *badPtr = ptr;
+    return 0;
+  }
+  if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
+    if (!isGeneralTextEntity) {
+      *badPtr = name;
+      return 0;
+    }
+  }
+  else {
+    if (versionPtr)
+      *versionPtr = val;
+    if (versionEndPtr)
+      *versionEndPtr = ptr;
+    if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+      *badPtr = ptr;
+      return 0;
+    }
+    if (!name) {
+      if (isGeneralTextEntity) {
+        /* a TextDecl must have an EncodingDecl */
+        *badPtr = ptr;
+        return 0;
+      }
+      return 1;
+    }
+  }
+  if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
+    int c = toAscii(enc, val, end);
+    if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
+      *badPtr = val;
+      return 0;
+    }
+    if (encodingName)
+      *encodingName = val;
+    if (encoding)
+      *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
+    if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+      *badPtr = ptr;
+      return 0;
+    }
+    if (!name)
+      return 1;
+  }
+  if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
+      || isGeneralTextEntity) {
+    *badPtr = name;
+    return 0;
+  }
+  if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
+    if (standalone)
+      *standalone = 1;
+  }
+  else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
+    if (standalone)
+      *standalone = 0;
+  }
+  else {
+    *badPtr = val;
+    return 0;
+  }
+  while (isSpace(toAscii(enc, ptr, end)))
+    ptr += enc->minBytesPerChar;
+  if (ptr != end) {
+    *badPtr = ptr;
+    return 0;
+  }
+  return 1;
+}
+
+static int FASTCALL
+checkCharRefNumber(int result)
+{
+  switch (result >> 8) {
+  case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+  case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+    return -1;
+  case 0:
+    if (latin1_encoding.type[result] == BT_NONXML)
+      return -1;
+    break;
+  case 0xFF:
+    if (result == 0xFFFE || result == 0xFFFF)
+      return -1;
+    break;
+  }
+  return result;
+}
+
+int FASTCALL
+XmlUtf8Encode(int c, char *buf)
+{
+  enum {
+    /* minN is minimum legal resulting value for N byte sequence */
+    min2 = 0x80,
+    min3 = 0x800,
+    min4 = 0x10000
+  };
+
+  if (c < 0)
+    return 0;
+  if (c < min2) {
+    buf[0] = (char)(c | UTF8_cval1);
+    return 1;
+  }
+  if (c < min3) {
+    buf[0] = (char)((c >> 6) | UTF8_cval2);
+    buf[1] = (char)((c & 0x3f) | 0x80);
+    return 2;
+  }
+  if (c < min4) {
+    buf[0] = (char)((c >> 12) | UTF8_cval3);
+    buf[1] = (char)(((c >> 6) & 0x3f) | 0x80);
+    buf[2] = (char)((c & 0x3f) | 0x80);
+    return 3;
+  }
+  if (c < 0x110000) {
+    buf[0] = (char)((c >> 18) | UTF8_cval4);
+    buf[1] = (char)(((c >> 12) & 0x3f) | 0x80);
+    buf[2] = (char)(((c >> 6) & 0x3f) | 0x80);
+    buf[3] = (char)((c & 0x3f) | 0x80);
+    return 4;
+  }
+  return 0;
+}
+
+int FASTCALL
+XmlUtf16Encode(int charNum, unsigned short *buf)
+{
+  if (charNum < 0)
+    return 0;
+  if (charNum < 0x10000) {
+    buf[0] = (unsigned short)charNum;
+    return 1;
+  }
+  if (charNum < 0x110000) {
+    charNum -= 0x10000;
+    buf[0] = (unsigned short)((charNum >> 10) + 0xD800);
+    buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00);
+    return 2;
+  }
+  return 0;
+}
+
+struct unknown_encoding {
+  struct normal_encoding normal;
+  CONVERTER convert;
+  void *userData;
+  unsigned short utf16[256];
+  char utf8[256][4];
+};
+
+#define AS_UNKNOWN_ENCODING(enc)  ((const struct unknown_encoding *) (enc))
+
+int
+XmlSizeOfUnknownEncoding(void)
+{
+  return sizeof(struct unknown_encoding);
+}
+
+static int PTRFASTCALL
+unknown_isName(const ENCODING *enc, const char *p)
+{
+  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+  int c = uenc->convert(uenc->userData, p);
+  if (c & ~0xFFFF)
+    return 0;
+  return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isNmstrt(const ENCODING *enc, const char *p)
+{
+  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+  int c = uenc->convert(uenc->userData, p);
+  if (c & ~0xFFFF)
+    return 0;
+  return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isInvalid(const ENCODING *enc, const char *p)
+{
+  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+  int c = uenc->convert(uenc->userData, p);
+  return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
+}
+
+static void PTRCALL
+unknown_toUtf8(const ENCODING *enc,
+               const char **fromP, const char *fromLim,
+               char **toP, const char *toLim)
+{
+  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+  char buf[XML_UTF8_ENCODE_MAX];
+  for (;;) {
+    const char *utf8;
+    int n;
+    if (*fromP == fromLim)
+      break;
+    utf8 = uenc->utf8[(unsigned char)**fromP];
+    n = *utf8++;
+    if (n == 0) {
+      int c = uenc->convert(uenc->userData, *fromP);
+      n = XmlUtf8Encode(c, buf);
+      if (n > toLim - *toP)
+        break;
+      utf8 = buf;
+      *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+                 - (BT_LEAD2 - 2));
+    }
+    else {
+      if (n > toLim - *toP)
+        break;
+      (*fromP)++;
+    }
+    do {
+      *(*toP)++ = *utf8++;
+    } while (--n != 0);
+  }
+}
+
+static void PTRCALL
+unknown_toUtf16(const ENCODING *enc,
+                const char **fromP, const char *fromLim,
+                unsigned short **toP, const unsigned short *toLim)
+{
+  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+  while (*fromP != fromLim && *toP != toLim) {
+    unsigned short c = uenc->utf16[(unsigned char)**fromP];
+    if (c == 0) {
+      c = (unsigned short)
+          uenc->convert(uenc->userData, *fromP);
+      *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+                 - (BT_LEAD2 - 2));
+    }
+    else
+      (*fromP)++;
+    *(*toP)++ = c;
+  }
+}
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+                       int *table,
+                       CONVERTER convert,
+                       void *userData)
+{
+  int i;
+  struct unknown_encoding *e = (struct unknown_encoding *)mem;
+  for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
+    ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+  for (i = 0; i < 128; i++)
+    if (latin1_encoding.type[i] != BT_OTHER
+        && latin1_encoding.type[i] != BT_NONXML
+        && table[i] != i)
+      return 0;
+  for (i = 0; i < 256; i++) {
+    int c = table[i];
+    if (c == -1) {
+      e->normal.type[i] = BT_MALFORM;
+      /* This shouldn't really get used. */
+      e->utf16[i] = 0xFFFF;
+      e->utf8[i][0] = 1;
+      e->utf8[i][1] = 0;
+    }
+    else if (c < 0) {
+      if (c < -4)
+        return 0;
+      e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
+      e->utf8[i][0] = 0;
+      e->utf16[i] = 0;
+    }
+    else if (c < 0x80) {
+      if (latin1_encoding.type[c] != BT_OTHER
+          && latin1_encoding.type[c] != BT_NONXML
+          && c != i)
+        return 0;
+      e->normal.type[i] = latin1_encoding.type[c];
+      e->utf8[i][0] = 1;
+      e->utf8[i][1] = (char)c;
+      e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
+    }
+    else if (checkCharRefNumber(c) < 0) {
+      e->normal.type[i] = BT_NONXML;
+      /* This shouldn't really get used. */
+      e->utf16[i] = 0xFFFF;
+      e->utf8[i][0] = 1;
+      e->utf8[i][1] = 0;
+    }
+    else {
+      if (c > 0xFFFF)
+        return 0;
+      if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
+        e->normal.type[i] = BT_NMSTRT;
+      else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
+        e->normal.type[i] = BT_NAME;
+      else
+        e->normal.type[i] = BT_OTHER;
+      e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
+      e->utf16[i] = (unsigned short)c;
+    }
+  }
+  e->userData = userData;
+  e->convert = convert;
+  if (convert) {
+    e->normal.isName2 = unknown_isName;
+    e->normal.isName3 = unknown_isName;
+    e->normal.isName4 = unknown_isName;
+    e->normal.isNmstrt2 = unknown_isNmstrt;
+    e->normal.isNmstrt3 = unknown_isNmstrt;
+    e->normal.isNmstrt4 = unknown_isNmstrt;
+    e->normal.isInvalid2 = unknown_isInvalid;
+    e->normal.isInvalid3 = unknown_isInvalid;
+    e->normal.isInvalid4 = unknown_isInvalid;
+  }
+  e->normal.enc.utf8Convert = unknown_toUtf8;
+  e->normal.enc.utf16Convert = unknown_toUtf16;
+  return &(e->normal.enc);
+}
+
+/* If this enumeration is changed, getEncodingIndex and encodings
+must also be changed. */
+enum {
+  UNKNOWN_ENC = -1,
+  ISO_8859_1_ENC = 0,
+  US_ASCII_ENC,
+  UTF_8_ENC,
+  UTF_16_ENC,
+  UTF_16BE_ENC,
+  UTF_16LE_ENC,
+  /* must match encodingNames up to here */
+  NO_ENC
+};
+
+static const char KW_ISO_8859_1[] = {
+  ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
+  ASCII_MINUS, ASCII_1, '\0'
+};
+static const char KW_US_ASCII[] = {
+  ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
+  '\0'
+};
+static const char KW_UTF_8[] =  {
+  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
+};
+static const char KW_UTF_16[] = {
+  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
+};
+static const char KW_UTF_16BE[] = {
+  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
+  '\0'
+};
+static const char KW_UTF_16LE[] = {
+  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
+  '\0'
+};
+
+static int FASTCALL
+getEncodingIndex(const char *name)
+{
+  static const char * const encodingNames[] = {
+    KW_ISO_8859_1,
+    KW_US_ASCII,
+    KW_UTF_8,
+    KW_UTF_16,
+    KW_UTF_16BE,
+    KW_UTF_16LE,
+  };
+  int i;
+  if (name == NULL)
+    return NO_ENC;
+  for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
+    if (streqci(name, encodingNames[i]))
+      return i;
+  return UNKNOWN_ENC;
+}
+
+/* For binary compatibility, we store the index of the encoding
+   specified at initialization in the isUtf16 member.
+*/
+
+#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
+#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
+
+/* This is what detects the encoding.  encodingTable maps from
+   encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of
+   the external (protocol) specified encoding; state is
+   XML_CONTENT_STATE if we're parsing an external text entity, and
+   XML_PROLOG_STATE otherwise.
+*/
+
+
+static int
+initScan(const ENCODING * const *encodingTable,
+         const INIT_ENCODING *enc,
+         int state,
+         const char *ptr,
+         const char *end,
+         const char **nextTokPtr)
+{
+  const ENCODING **encPtr;
+
+  if (ptr == end)
+    return XML_TOK_NONE;
+  encPtr = enc->encPtr;
+  if (ptr + 1 == end) {
+    /* only a single byte available for auto-detection */
+#ifndef XML_DTD /* FIXME */
+    /* a well-formed document entity must have more than one byte */
+    if (state != XML_CONTENT_STATE)
+      return XML_TOK_PARTIAL;
+#endif
+    /* so we're parsing an external text entity... */
+    /* if UTF-16 was externally specified, then we need at least 2 bytes */
+    switch (INIT_ENC_INDEX(enc)) {
+    case UTF_16_ENC:
+    case UTF_16LE_ENC:
+    case UTF_16BE_ENC:
+      return XML_TOK_PARTIAL;
+    }
+    switch ((unsigned char)*ptr) {
+    case 0xFE:
+    case 0xFF:
+    case 0xEF: /* possibly first byte of UTF-8 BOM */
+      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+          && state == XML_CONTENT_STATE)
+        break;
+      /* fall through */
+    case 0x00:
+    case 0x3C:
+      return XML_TOK_PARTIAL;
+    }
+  }
+  else {
+    switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
+    case 0xFEFF:
+      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+          && state == XML_CONTENT_STATE)
+        break;
+      *nextTokPtr = ptr + 2;
+      *encPtr = encodingTable[UTF_16BE_ENC];
+      return XML_TOK_BOM;
+    /* 00 3C is handled in the default case */
+    case 0x3C00:
+      if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
+           || INIT_ENC_INDEX(enc) == UTF_16_ENC)
+          && state == XML_CONTENT_STATE)
+        break;
+      *encPtr = encodingTable[UTF_16LE_ENC];
+      return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+    case 0xFFFE:
+      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+          && state == XML_CONTENT_STATE)
+        break;
+      *nextTokPtr = ptr + 2;
+      *encPtr = encodingTable[UTF_16LE_ENC];
+      return XML_TOK_BOM;
+    case 0xEFBB:
+      /* Maybe a UTF-8 BOM (EF BB BF) */
+      /* If there's an explicitly specified (external) encoding
+         of ISO-8859-1 or some flavour of UTF-16
+         and this is an external text entity,
+         don't look for the BOM,
+         because it might be a legal data.
+      */
+      if (state == XML_CONTENT_STATE) {
+        int e = INIT_ENC_INDEX(enc);
+        if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
+            || e == UTF_16LE_ENC || e == UTF_16_ENC)
+          break;
+      }
+      if (ptr + 2 == end)
+        return XML_TOK_PARTIAL;
+      if ((unsigned char)ptr[2] == 0xBF) {
+        *nextTokPtr = ptr + 3;
+        *encPtr = encodingTable[UTF_8_ENC];
+        return XML_TOK_BOM;
+      }
+      break;
+    default:
+      if (ptr[0] == '\0') {
+        /* 0 isn't a legal data character. Furthermore a document
+           entity can only start with ASCII characters.  So the only
+           way this can fail to be big-endian UTF-16 if it it's an
+           external parsed general entity that's labelled as
+           UTF-16LE.
+        */
+        if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
+          break;
+        *encPtr = encodingTable[UTF_16BE_ENC];
+        return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+      }
+      else if (ptr[1] == '\0') {
+        /* We could recover here in the case:
+            - parsing an external entity
+            - second byte is 0
+            - no externally specified encoding
+            - no encoding declaration
+           by assuming UTF-16LE.  But we don't, because this would mean when
+           presented just with a single byte, we couldn't reliably determine
+           whether we needed further bytes.
+        */
+        if (state == XML_CONTENT_STATE)
+          break;
+        *encPtr = encodingTable[UTF_16LE_ENC];
+        return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+      }
+      break;
+    }
+  }
+  *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
+  return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+}
+
+
+#define NS(x) x
+#define ns(x) x
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+#undef NS
+#undef ns
+
+#ifdef XML_NS
+
+#define NS(x) x ## NS
+#define ns(x) x ## _ns
+
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+
+#undef NS
+#undef ns
+
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+                         int *table,
+                         CONVERTER convert,
+                         void *userData)
+{
+  ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
+  if (enc)
+    ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
+  return enc;
+}
+
+#endif /* XML_NS */

+ 316 - 0
libs/expat/lib/xmltok.h

@@ -0,0 +1,316 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#ifndef XmlTok_INCLUDED
+#define XmlTok_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following token may be returned by XmlContentTok */
+#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
+                                    start of illegal ]]> sequence */
+/* The following tokens may be returned by both XmlPrologTok and
+   XmlContentTok.
+*/
+#define XML_TOK_NONE -4          /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR -3   /* A CR at the end of the scan;
+                                    might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2  /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1       /* only part of a token */
+#define XML_TOK_INVALID 0
+
+/* The following tokens are returned by XmlContentTok; some are also
+   returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
+*/
+#define XML_TOK_START_TAG_WITH_ATTS 1
+#define XML_TOK_START_TAG_NO_ATTS 2
+#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
+#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
+#define XML_TOK_END_TAG 5
+#define XML_TOK_DATA_CHARS 6
+#define XML_TOK_DATA_NEWLINE 7
+#define XML_TOK_CDATA_SECT_OPEN 8
+#define XML_TOK_ENTITY_REF 9
+#define XML_TOK_CHAR_REF 10               /* numeric character reference */
+
+/* The following tokens may be returned by both XmlPrologTok and
+   XmlContentTok.
+*/
+#define XML_TOK_PI 11                     /* processing instruction */
+#define XML_TOK_XML_DECL 12               /* XML decl or text decl */
+#define XML_TOK_COMMENT 13
+#define XML_TOK_BOM 14                    /* Byte order mark */
+
+/* The following tokens are returned only by XmlPrologTok */
+#define XML_TOK_PROLOG_S 15
+#define XML_TOK_DECL_OPEN 16              /* <!foo */
+#define XML_TOK_DECL_CLOSE 17             /* > */
+#define XML_TOK_NAME 18
+#define XML_TOK_NMTOKEN 19
+#define XML_TOK_POUND_NAME 20             /* #name */
+#define XML_TOK_OR 21                     /* | */
+#define XML_TOK_PERCENT 22
+#define XML_TOK_OPEN_PAREN 23
+#define XML_TOK_CLOSE_PAREN 24
+#define XML_TOK_OPEN_BRACKET 25
+#define XML_TOK_CLOSE_BRACKET 26
+#define XML_TOK_LITERAL 27
+#define XML_TOK_PARAM_ENTITY_REF 28
+#define XML_TOK_INSTANCE_START 29
+
+/* The following occur only in element type declarations */
+#define XML_TOK_NAME_QUESTION 30          /* name? */
+#define XML_TOK_NAME_ASTERISK 31          /* name* */
+#define XML_TOK_NAME_PLUS 32              /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33         /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34        /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35   /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36   /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37       /* )+ */
+#define XML_TOK_COMMA 38
+
+/* The following token is returned only by XmlAttributeValueTok */
+#define XML_TOK_ATTRIBUTE_VALUE_S 39
+
+/* The following token is returned only by XmlCdataSectionTok */
+#define XML_TOK_CDATA_SECT_CLOSE 40
+
+/* With namespace processing this is returned by XmlPrologTok for a
+   name with a colon.
+*/
+#define XML_TOK_PREFIXED_NAME 41
+
+#ifdef XML_DTD
+#define XML_TOK_IGNORE_SECT 42
+#endif /* XML_DTD */
+
+#ifdef XML_DTD
+#define XML_N_STATES 4
+#else /* not XML_DTD */
+#define XML_N_STATES 3
+#endif /* not XML_DTD */
+
+#define XML_PROLOG_STATE 0
+#define XML_CONTENT_STATE 1
+#define XML_CDATA_SECTION_STATE 2
+#ifdef XML_DTD
+#define XML_IGNORE_SECTION_STATE 3
+#endif /* XML_DTD */
+
+#define XML_N_LITERAL_TYPES 2
+#define XML_ATTRIBUTE_VALUE_LITERAL 0
+#define XML_ENTITY_VALUE_LITERAL 1
+
+/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
+#define XML_UTF8_ENCODE_MAX 4
+/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
+#define XML_UTF16_ENCODE_MAX 2
+
+typedef struct position {
+  /* first line and first column are 0 not 1 */
+  XML_Size lineNumber;
+  XML_Size columnNumber;
+} POSITION;
+
+typedef struct {
+  const char *name;
+  const char *valuePtr;
+  const char *valueEnd;
+  char normalized;
+} ATTRIBUTE;
+
+struct encoding;
+typedef struct encoding ENCODING;
+
+typedef int (PTRCALL *SCANNER)(const ENCODING *,
+                               const char *,
+                               const char *,
+                               const char **);
+
+struct encoding {
+  SCANNER scanners[XML_N_STATES];
+  SCANNER literalScanners[XML_N_LITERAL_TYPES];
+  int (PTRCALL *sameName)(const ENCODING *,
+                          const char *,
+                          const char *);
+  int (PTRCALL *nameMatchesAscii)(const ENCODING *,
+                                  const char *,
+                                  const char *,
+                                  const char *);
+  int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
+  const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
+  int (PTRCALL *getAtts)(const ENCODING *enc,
+                         const char *ptr,
+                         int attsMax,
+                         ATTRIBUTE *atts);
+  int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
+  int (PTRCALL *predefinedEntityName)(const ENCODING *,
+                                      const char *,
+                                      const char *);
+  void (PTRCALL *updatePosition)(const ENCODING *,
+                                 const char *ptr,
+                                 const char *end,
+                                 POSITION *);
+  int (PTRCALL *isPublicId)(const ENCODING *enc,
+                            const char *ptr,
+                            const char *end,
+                            const char **badPtr);
+  void (PTRCALL *utf8Convert)(const ENCODING *enc,
+                              const char **fromP,
+                              const char *fromLim,
+                              char **toP,
+                              const char *toLim);
+  void (PTRCALL *utf16Convert)(const ENCODING *enc,
+                               const char **fromP,
+                               const char *fromLim,
+                               unsigned short **toP,
+                               const unsigned short *toLim);
+  int minBytesPerChar;
+  char isUtf8;
+  char isUtf16;
+};
+
+/* Scan the string starting at ptr until the end of the next complete
+   token, but do not scan past eptr.  Return an integer giving the
+   type of token.
+
+   Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
+
+   Return XML_TOK_PARTIAL when the string does not contain a complete
+   token; nextTokPtr will not be set.
+
+   Return XML_TOK_INVALID when the string does not start a valid
+   token; nextTokPtr will be set to point to the character which made
+   the token invalid.
+
+   Otherwise the string starts with a valid token; nextTokPtr will be
+   set to point to the character following the end of that token.
+
+   Each data character counts as a single token, but adjacent data
+   characters may be returned together.  Similarly for characters in
+   the prolog outside literals, comments and processing instructions.
+*/
+
+
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+  (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
+
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+   XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+   XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+   XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+
+#ifdef XML_DTD
+
+#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
+   XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
+
+#endif /* XML_DTD */
+
+/* This is used for performing a 2nd-level tokenization on the content
+   of a literal that has already been returned by XmlTok.
+*/
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+  (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
+
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+   XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+   XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
+
+#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
+  (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
+
+#define XmlNameLength(enc, ptr) \
+  (((enc)->nameLength)(enc, ptr))
+
+#define XmlSkipS(enc, ptr) \
+  (((enc)->skipS)(enc, ptr))
+
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+  (((enc)->getAtts)(enc, ptr, attsMax, atts))
+
+#define XmlCharRefNumber(enc, ptr) \
+  (((enc)->charRefNumber)(enc, ptr))
+
+#define XmlPredefinedEntityName(enc, ptr, end) \
+  (((enc)->predefinedEntityName)(enc, ptr, end))
+
+#define XmlUpdatePosition(enc, ptr, end, pos) \
+  (((enc)->updatePosition)(enc, ptr, end, pos))
+
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
+  (((enc)->isPublicId)(enc, ptr, end, badPtr))
+
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+  (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
+
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+  (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
+
+typedef struct {
+  ENCODING initEnc;
+  const ENCODING **encPtr;
+} INIT_ENCODING;
+
+int XmlParseXmlDecl(int isGeneralTextEntity,
+                    const ENCODING *enc,
+                    const char *ptr,
+                    const char *end,
+                    const char **badPtr,
+                    const char **versionPtr,
+                    const char **versionEndPtr,
+                    const char **encodingNamePtr,
+                    const ENCODING **namedEncodingPtr,
+                    int *standalonePtr);
+
+int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncoding(void);
+const ENCODING *XmlGetUtf16InternalEncoding(void);
+int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
+int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
+int XmlSizeOfUnknownEncoding(void);
+
+
+typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+                       int *table,
+                       CONVERTER convert,
+                       void *userData);
+
+int XmlParseXmlDeclNS(int isGeneralTextEntity,
+                      const ENCODING *enc,
+                      const char *ptr,
+                      const char *end,
+                      const char **badPtr,
+                      const char **versionPtr,
+                      const char **versionEndPtr,
+                      const char **encodingNamePtr,
+                      const ENCODING **namedEncodingPtr,
+                      int *standalonePtr);
+
+int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncodingNS(void);
+const ENCODING *XmlGetUtf16InternalEncodingNS(void);
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+                         int *table,
+                         CONVERTER convert,
+                         void *userData);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlTok_INCLUDED */

+ 1786 - 0
libs/expat/lib/xmltok_impl.c

@@ -0,0 +1,1786 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_IMPL_C
+
+#ifndef IS_INVALID_CHAR
+#define IS_INVALID_CHAR(enc, ptr, n) (0)
+#endif
+
+#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+    case BT_LEAD ## n: \
+      if (end - ptr < n) \
+        return XML_TOK_PARTIAL_CHAR; \
+      if (IS_INVALID_CHAR(enc, ptr, n)) { \
+        *(nextTokPtr) = (ptr); \
+        return XML_TOK_INVALID; \
+      } \
+      ptr += n; \
+      break;
+
+#define INVALID_CASES(ptr, nextTokPtr) \
+  INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+  INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+  INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+  case BT_NONXML: \
+  case BT_MALFORM: \
+  case BT_TRAIL: \
+    *(nextTokPtr) = (ptr); \
+    return XML_TOK_INVALID;
+
+#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+   case BT_LEAD ## n: \
+     if (end - ptr < n) \
+       return XML_TOK_PARTIAL_CHAR; \
+     if (!IS_NAME_CHAR(enc, ptr, n)) { \
+       *nextTokPtr = ptr; \
+       return XML_TOK_INVALID; \
+     } \
+     ptr += n; \
+     break;
+
+#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+  case BT_NONASCII: \
+    if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+      *nextTokPtr = ptr; \
+      return XML_TOK_INVALID; \
+    } \
+  case BT_NMSTRT: \
+  case BT_HEX: \
+  case BT_DIGIT: \
+  case BT_NAME: \
+  case BT_MINUS: \
+    ptr += MINBPC(enc); \
+    break; \
+  CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+  CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+  CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+
+#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+   case BT_LEAD ## n: \
+     if (end - ptr < n) \
+       return XML_TOK_PARTIAL_CHAR; \
+     if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
+       *nextTokPtr = ptr; \
+       return XML_TOK_INVALID; \
+     } \
+     ptr += n; \
+     break;
+
+#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+  case BT_NONASCII: \
+    if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+      *nextTokPtr = ptr; \
+      return XML_TOK_INVALID; \
+    } \
+  case BT_NMSTRT: \
+  case BT_HEX: \
+    ptr += MINBPC(enc); \
+    break; \
+  CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+  CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+  CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+
+#ifndef PREFIX
+#define PREFIX(ident) ident
+#endif
+
+/* ptr points to character following "<!-" */
+
+static int PTRCALL
+PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
+                    const char *end, const char **nextTokPtr)
+{
+  if (ptr != end) {
+    if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+    ptr += MINBPC(enc);
+    while (ptr != end) {
+      switch (BYTE_TYPE(enc, ptr)) {
+      INVALID_CASES(ptr, nextTokPtr)
+      case BT_MINUS:
+        if ((ptr += MINBPC(enc)) == end)
+          return XML_TOK_PARTIAL;
+        if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+          if ((ptr += MINBPC(enc)) == end)
+            return XML_TOK_PARTIAL;
+          if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+            *nextTokPtr = ptr;
+            return XML_TOK_INVALID;
+          }
+          *nextTokPtr = ptr + MINBPC(enc);
+          return XML_TOK_COMMENT;
+        }
+        break;
+      default:
+        ptr += MINBPC(enc);
+        break;
+      }
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<!" */
+
+static int PTRCALL
+PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
+                 const char *end, const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  case BT_MINUS:
+    return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_LSQB:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_COND_SECT_OPEN;
+  case BT_NMSTRT:
+  case BT_HEX:
+    ptr += MINBPC(enc);
+    break;
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_PERCNT:
+      if (ptr + MINBPC(enc) == end)
+        return XML_TOK_PARTIAL;
+      /* don't allow <!ENTITY% foo "whatever"> */
+      switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
+      case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      /* fall through */
+    case BT_S: case BT_CR: case BT_LF:
+      *nextTokPtr = ptr;
+      return XML_TOK_DECL_OPEN;
+    case BT_NMSTRT:
+    case BT_HEX:
+      ptr += MINBPC(enc);
+      break;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
+                      const char *end, int *tokPtr)
+{
+  int upper = 0;
+  *tokPtr = XML_TOK_PI;
+  if (end - ptr != MINBPC(enc)*3)
+    return 1;
+  switch (BYTE_TO_ASCII(enc, ptr)) {
+  case ASCII_x:
+    break;
+  case ASCII_X:
+    upper = 1;
+    break;
+  default:
+    return 1;
+  }
+  ptr += MINBPC(enc);
+  switch (BYTE_TO_ASCII(enc, ptr)) {
+  case ASCII_m:
+    break;
+  case ASCII_M:
+    upper = 1;
+    break;
+  default:
+    return 1;
+  }
+  ptr += MINBPC(enc);
+  switch (BYTE_TO_ASCII(enc, ptr)) {
+  case ASCII_l:
+    break;
+  case ASCII_L:
+    upper = 1;
+    break;
+  default:
+    return 1;
+  }
+  if (upper)
+    return 0;
+  *tokPtr = XML_TOK_XML_DECL;
+  return 1;
+}
+
+/* ptr points to character following "<?" */
+
+static int PTRCALL
+PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
+               const char *end, const char **nextTokPtr)
+{
+  int tok;
+  const char *target = ptr;
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_S: case BT_CR: case BT_LF:
+      if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      ptr += MINBPC(enc);
+      while (ptr != end) {
+        switch (BYTE_TYPE(enc, ptr)) {
+        INVALID_CASES(ptr, nextTokPtr)
+        case BT_QUEST:
+          ptr += MINBPC(enc);
+          if (ptr == end)
+            return XML_TOK_PARTIAL;
+          if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+            *nextTokPtr = ptr + MINBPC(enc);
+            return tok;
+          }
+          break;
+        default:
+          ptr += MINBPC(enc);
+          break;
+        }
+      }
+      return XML_TOK_PARTIAL;
+    case BT_QUEST:
+      if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        return XML_TOK_PARTIAL;
+      if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+        *nextTokPtr = ptr + MINBPC(enc);
+        return tok;
+      }
+      /* fall through */
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
+                         const char *end, const char **nextTokPtr)
+{
+  static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
+                                     ASCII_T, ASCII_A, ASCII_LSQB };
+  int i;
+  /* CDATA[ */
+  if (end - ptr < 6 * MINBPC(enc))
+    return XML_TOK_PARTIAL;
+  for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
+    if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  *nextTokPtr = ptr;
+  return XML_TOK_CDATA_SECT_OPEN;
+}
+
+static int PTRCALL
+PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
+                        const char *end, const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_NONE;
+  if (MINBPC(enc) > 1) {
+    size_t n = end - ptr;
+    if (n & (MINBPC(enc) - 1)) {
+      n &= ~(MINBPC(enc) - 1);
+      if (n == 0)
+        return XML_TOK_PARTIAL;
+      end = ptr + n;
+    }
+  }
+  switch (BYTE_TYPE(enc, ptr)) {
+  case BT_RSQB:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_PARTIAL;
+    if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+      break;
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_PARTIAL;
+    if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+      ptr -= MINBPC(enc);
+      break;
+    }
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_CDATA_SECT_CLOSE;
+  case BT_CR:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_PARTIAL;
+    if (BYTE_TYPE(enc, ptr) == BT_LF)
+      ptr += MINBPC(enc);
+    *nextTokPtr = ptr;
+    return XML_TOK_DATA_NEWLINE;
+  case BT_LF:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_DATA_NEWLINE;
+  INVALID_CASES(ptr, nextTokPtr)
+  default:
+    ptr += MINBPC(enc);
+    break;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: \
+      if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+        *nextTokPtr = ptr; \
+        return XML_TOK_DATA_CHARS; \
+      } \
+      ptr += n; \
+      break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_NONXML:
+    case BT_MALFORM:
+    case BT_TRAIL:
+    case BT_CR:
+    case BT_LF:
+    case BT_RSQB:
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  *nextTokPtr = ptr;
+  return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "</" */
+
+static int PTRCALL
+PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
+                   const char *end, const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_S: case BT_CR: case BT_LF:
+      for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+        switch (BYTE_TYPE(enc, ptr)) {
+        case BT_S: case BT_CR: case BT_LF:
+          break;
+        case BT_GT:
+          *nextTokPtr = ptr + MINBPC(enc);
+          return XML_TOK_END_TAG;
+        default:
+          *nextTokPtr = ptr;
+          return XML_TOK_INVALID;
+        }
+      }
+      return XML_TOK_PARTIAL;
+#ifdef XML_NS
+    case BT_COLON:
+      /* no need to check qname syntax here,
+         since end-tag must match exactly */
+      ptr += MINBPC(enc);
+      break;
+#endif
+    case BT_GT:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_END_TAG;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#X" */
+
+static int PTRCALL
+PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
+                       const char *end, const char **nextTokPtr)
+{
+  if (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_DIGIT:
+    case BT_HEX:
+      break;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+      switch (BYTE_TYPE(enc, ptr)) {
+      case BT_DIGIT:
+      case BT_HEX:
+        break;
+      case BT_SEMI:
+        *nextTokPtr = ptr + MINBPC(enc);
+        return XML_TOK_CHAR_REF;
+      default:
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#" */
+
+static int PTRCALL
+PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
+                    const char *end, const char **nextTokPtr)
+{
+  if (ptr != end) {
+    if (CHAR_MATCHES(enc, ptr, ASCII_x))
+      return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_DIGIT:
+      break;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+      switch (BYTE_TYPE(enc, ptr)) {
+      case BT_DIGIT:
+        break;
+      case BT_SEMI:
+        *nextTokPtr = ptr + MINBPC(enc);
+        return XML_TOK_CHAR_REF;
+      default:
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&" */
+
+static int PTRCALL
+PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
+                const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  case BT_NUM:
+    return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_SEMI:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_ENTITY_REF;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following first character of attribute name */
+
+static int PTRCALL
+PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
+                 const char **nextTokPtr)
+{
+#ifdef XML_NS
+  int hadColon = 0;
+#endif
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+    case BT_COLON:
+      if (hadColon) {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      hadColon = 1;
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        return XML_TOK_PARTIAL;
+      switch (BYTE_TYPE(enc, ptr)) {
+      CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+      default:
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      break;
+#endif
+    case BT_S: case BT_CR: case BT_LF:
+      for (;;) {
+        int t;
+
+        ptr += MINBPC(enc);
+        if (ptr == end)
+          return XML_TOK_PARTIAL;
+        t = BYTE_TYPE(enc, ptr);
+        if (t == BT_EQUALS)
+          break;
+        switch (t) {
+        case BT_S:
+        case BT_LF:
+        case BT_CR:
+          break;
+        default:
+          *nextTokPtr = ptr;
+          return XML_TOK_INVALID;
+        }
+      }
+    /* fall through */
+    case BT_EQUALS:
+      {
+        int open;
+#ifdef XML_NS
+        hadColon = 0;
+#endif
+        for (;;) {
+          ptr += MINBPC(enc);
+          if (ptr == end)
+            return XML_TOK_PARTIAL;
+          open = BYTE_TYPE(enc, ptr);
+          if (open == BT_QUOT || open == BT_APOS)
+            break;
+          switch (open) {
+          case BT_S:
+          case BT_LF:
+          case BT_CR:
+            break;
+          default:
+            *nextTokPtr = ptr;
+            return XML_TOK_INVALID;
+          }
+        }
+        ptr += MINBPC(enc);
+        /* in attribute value */
+        for (;;) {
+          int t;
+          if (ptr == end)
+            return XML_TOK_PARTIAL;
+          t = BYTE_TYPE(enc, ptr);
+          if (t == open)
+            break;
+          switch (t) {
+          INVALID_CASES(ptr, nextTokPtr)
+          case BT_AMP:
+            {
+              int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+              if (tok <= 0) {
+                if (tok == XML_TOK_INVALID)
+                  *nextTokPtr = ptr;
+                return tok;
+              }
+              break;
+            }
+          case BT_LT:
+            *nextTokPtr = ptr;
+            return XML_TOK_INVALID;
+          default:
+            ptr += MINBPC(enc);
+            break;
+          }
+        }
+        ptr += MINBPC(enc);
+        if (ptr == end)
+          return XML_TOK_PARTIAL;
+        switch (BYTE_TYPE(enc, ptr)) {
+        case BT_S:
+        case BT_CR:
+        case BT_LF:
+          break;
+        case BT_SOL:
+          goto sol;
+        case BT_GT:
+          goto gt;
+        default:
+          *nextTokPtr = ptr;
+          return XML_TOK_INVALID;
+        }
+        /* ptr points to closing quote */
+        for (;;) {
+          ptr += MINBPC(enc);
+          if (ptr == end)
+            return XML_TOK_PARTIAL;
+          switch (BYTE_TYPE(enc, ptr)) {
+          CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+          case BT_S: case BT_CR: case BT_LF:
+            continue;
+          case BT_GT:
+          gt:
+            *nextTokPtr = ptr + MINBPC(enc);
+            return XML_TOK_START_TAG_WITH_ATTS;
+          case BT_SOL:
+          sol:
+            ptr += MINBPC(enc);
+            if (ptr == end)
+              return XML_TOK_PARTIAL;
+            if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+              *nextTokPtr = ptr;
+              return XML_TOK_INVALID;
+            }
+            *nextTokPtr = ptr + MINBPC(enc);
+            return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+          default:
+            *nextTokPtr = ptr;
+            return XML_TOK_INVALID;
+          }
+          break;
+        }
+        break;
+      }
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<" */
+
+static int PTRCALL
+PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
+               const char **nextTokPtr)
+{
+#ifdef XML_NS
+  int hadColon;
+#endif
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  case BT_EXCL:
+    if ((ptr += MINBPC(enc)) == end)
+      return XML_TOK_PARTIAL;
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_MINUS:
+      return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+    case BT_LSQB:
+      return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
+                                      end, nextTokPtr);
+    }
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  case BT_QUEST:
+    return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_SOL:
+    return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+#ifdef XML_NS
+  hadColon = 0;
+#endif
+  /* we have a start-tag */
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+    case BT_COLON:
+      if (hadColon) {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      hadColon = 1;
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        return XML_TOK_PARTIAL;
+      switch (BYTE_TYPE(enc, ptr)) {
+      CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+      default:
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      break;
+#endif
+    case BT_S: case BT_CR: case BT_LF:
+      {
+        ptr += MINBPC(enc);
+        while (ptr != end) {
+          switch (BYTE_TYPE(enc, ptr)) {
+          CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+          case BT_GT:
+            goto gt;
+          case BT_SOL:
+            goto sol;
+          case BT_S: case BT_CR: case BT_LF:
+            ptr += MINBPC(enc);
+            continue;
+          default:
+            *nextTokPtr = ptr;
+            return XML_TOK_INVALID;
+          }
+          return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+        }
+        return XML_TOK_PARTIAL;
+      }
+    case BT_GT:
+    gt:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_START_TAG_NO_ATTS;
+    case BT_SOL:
+    sol:
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        return XML_TOK_PARTIAL;
+      if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
+                   const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_NONE;
+  if (MINBPC(enc) > 1) {
+    size_t n = end - ptr;
+    if (n & (MINBPC(enc) - 1)) {
+      n &= ~(MINBPC(enc) - 1);
+      if (n == 0)
+        return XML_TOK_PARTIAL;
+      end = ptr + n;
+    }
+  }
+  switch (BYTE_TYPE(enc, ptr)) {
+  case BT_LT:
+    return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_AMP:
+    return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_CR:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_TRAILING_CR;
+    if (BYTE_TYPE(enc, ptr) == BT_LF)
+      ptr += MINBPC(enc);
+    *nextTokPtr = ptr;
+    return XML_TOK_DATA_NEWLINE;
+  case BT_LF:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_DATA_NEWLINE;
+  case BT_RSQB:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_TRAILING_RSQB;
+    if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+      break;
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return XML_TOK_TRAILING_RSQB;
+    if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+      ptr -= MINBPC(enc);
+      break;
+    }
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  INVALID_CASES(ptr, nextTokPtr)
+  default:
+    ptr += MINBPC(enc);
+    break;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: \
+      if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+        *nextTokPtr = ptr; \
+        return XML_TOK_DATA_CHARS; \
+      } \
+      ptr += n; \
+      break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_RSQB:
+      if (ptr + MINBPC(enc) != end) {
+         if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
+           ptr += MINBPC(enc);
+           break;
+         }
+         if (ptr + 2*MINBPC(enc) != end) {
+           if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
+             ptr += MINBPC(enc);
+             break;
+           }
+           *nextTokPtr = ptr + 2*MINBPC(enc);
+           return XML_TOK_INVALID;
+         }
+      }
+      /* fall through */
+    case BT_AMP:
+    case BT_LT:
+    case BT_NONXML:
+    case BT_MALFORM:
+    case BT_TRAIL:
+    case BT_CR:
+    case BT_LF:
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  *nextTokPtr = ptr;
+  return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "%" */
+
+static int PTRCALL
+PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
+                    const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+    *nextTokPtr = ptr;
+    return XML_TOK_PERCENT;
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_SEMI:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_PARAM_ENTITY_REF;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
+                      const char **nextTokPtr)
+{
+  if (ptr == end)
+    return XML_TOK_PARTIAL;
+  switch (BYTE_TYPE(enc, ptr)) {
+  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_CR: case BT_LF: case BT_S:
+    case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+      *nextTokPtr = ptr;
+      return XML_TOK_POUND_NAME;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return -XML_TOK_POUND_NAME;
+}
+
+static int PTRCALL
+PREFIX(scanLit)(int open, const ENCODING *enc,
+                const char *ptr, const char *end,
+                const char **nextTokPtr)
+{
+  while (ptr != end) {
+    int t = BYTE_TYPE(enc, ptr);
+    switch (t) {
+    INVALID_CASES(ptr, nextTokPtr)
+    case BT_QUOT:
+    case BT_APOS:
+      ptr += MINBPC(enc);
+      if (t != open)
+        break;
+      if (ptr == end)
+        return -XML_TOK_LITERAL;
+      *nextTokPtr = ptr;
+      switch (BYTE_TYPE(enc, ptr)) {
+      case BT_S: case BT_CR: case BT_LF:
+      case BT_GT: case BT_PERCNT: case BT_LSQB:
+        return XML_TOK_LITERAL;
+      default:
+        return XML_TOK_INVALID;
+      }
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
+                  const char **nextTokPtr)
+{
+  int tok;
+  if (ptr == end)
+    return XML_TOK_NONE;
+  if (MINBPC(enc) > 1) {
+    size_t n = end - ptr;
+    if (n & (MINBPC(enc) - 1)) {
+      n &= ~(MINBPC(enc) - 1);
+      if (n == 0)
+        return XML_TOK_PARTIAL;
+      end = ptr + n;
+    }
+  }
+  switch (BYTE_TYPE(enc, ptr)) {
+  case BT_QUOT:
+    return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_APOS:
+    return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_LT:
+    {
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        return XML_TOK_PARTIAL;
+      switch (BYTE_TYPE(enc, ptr)) {
+      case BT_EXCL:
+        return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+      case BT_QUEST:
+        return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+      case BT_NMSTRT:
+      case BT_HEX:
+      case BT_NONASCII:
+      case BT_LEAD2:
+      case BT_LEAD3:
+      case BT_LEAD4:
+        *nextTokPtr = ptr - MINBPC(enc);
+        return XML_TOK_INSTANCE_START;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  case BT_CR:
+    if (ptr + MINBPC(enc) == end) {
+      *nextTokPtr = end;
+      /* indicate that this might be part of a CR/LF pair */
+      return -XML_TOK_PROLOG_S;
+    }
+    /* fall through */
+  case BT_S: case BT_LF:
+    for (;;) {
+      ptr += MINBPC(enc);
+      if (ptr == end)
+        break;
+      switch (BYTE_TYPE(enc, ptr)) {
+      case BT_S: case BT_LF:
+        break;
+      case BT_CR:
+        /* don't split CR/LF pair */
+        if (ptr + MINBPC(enc) != end)
+          break;
+        /* fall through */
+      default:
+        *nextTokPtr = ptr;
+        return XML_TOK_PROLOG_S;
+      }
+    }
+    *nextTokPtr = ptr;
+    return XML_TOK_PROLOG_S;
+  case BT_PERCNT:
+    return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+  case BT_COMMA:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_COMMA;
+  case BT_LSQB:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_OPEN_BRACKET;
+  case BT_RSQB:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return -XML_TOK_CLOSE_BRACKET;
+    if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+      if (ptr + MINBPC(enc) == end)
+        return XML_TOK_PARTIAL;
+      if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
+        *nextTokPtr = ptr + 2*MINBPC(enc);
+        return XML_TOK_COND_SECT_CLOSE;
+      }
+    }
+    *nextTokPtr = ptr;
+    return XML_TOK_CLOSE_BRACKET;
+  case BT_LPAR:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_OPEN_PAREN;
+  case BT_RPAR:
+    ptr += MINBPC(enc);
+    if (ptr == end)
+      return -XML_TOK_CLOSE_PAREN;
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_AST:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_CLOSE_PAREN_ASTERISK;
+    case BT_QUEST:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_CLOSE_PAREN_QUESTION;
+    case BT_PLUS:
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_CLOSE_PAREN_PLUS;
+    case BT_CR: case BT_LF: case BT_S:
+    case BT_GT: case BT_COMMA: case BT_VERBAR:
+    case BT_RPAR:
+      *nextTokPtr = ptr;
+      return XML_TOK_CLOSE_PAREN;
+    }
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  case BT_VERBAR:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_OR;
+  case BT_GT:
+    *nextTokPtr = ptr + MINBPC(enc);
+    return XML_TOK_DECL_CLOSE;
+  case BT_NUM:
+    return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+#define LEAD_CASE(n) \
+  case BT_LEAD ## n: \
+    if (end - ptr < n) \
+      return XML_TOK_PARTIAL_CHAR; \
+    if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+      ptr += n; \
+      tok = XML_TOK_NAME; \
+      break; \
+    } \
+    if (IS_NAME_CHAR(enc, ptr, n)) { \
+      ptr += n; \
+      tok = XML_TOK_NMTOKEN; \
+      break; \
+    } \
+    *nextTokPtr = ptr; \
+    return XML_TOK_INVALID;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+  case BT_NMSTRT:
+  case BT_HEX:
+    tok = XML_TOK_NAME;
+    ptr += MINBPC(enc);
+    break;
+  case BT_DIGIT:
+  case BT_NAME:
+  case BT_MINUS:
+#ifdef XML_NS
+  case BT_COLON:
+#endif
+    tok = XML_TOK_NMTOKEN;
+    ptr += MINBPC(enc);
+    break;
+  case BT_NONASCII:
+    if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
+      ptr += MINBPC(enc);
+      tok = XML_TOK_NAME;
+      break;
+    }
+    if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
+      ptr += MINBPC(enc);
+      tok = XML_TOK_NMTOKEN;
+      break;
+    }
+    /* fall through */
+  default:
+    *nextTokPtr = ptr;
+    return XML_TOK_INVALID;
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+    case BT_GT: case BT_RPAR: case BT_COMMA:
+    case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
+    case BT_S: case BT_CR: case BT_LF:
+      *nextTokPtr = ptr;
+      return tok;
+#ifdef XML_NS
+    case BT_COLON:
+      ptr += MINBPC(enc);
+      switch (tok) {
+      case XML_TOK_NAME:
+        if (ptr == end)
+          return XML_TOK_PARTIAL;
+        tok = XML_TOK_PREFIXED_NAME;
+        switch (BYTE_TYPE(enc, ptr)) {
+        CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+        default:
+          tok = XML_TOK_NMTOKEN;
+          break;
+        }
+        break;
+      case XML_TOK_PREFIXED_NAME:
+        tok = XML_TOK_NMTOKEN;
+        break;
+      }
+      break;
+#endif
+    case BT_PLUS:
+      if (tok == XML_TOK_NMTOKEN)  {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_NAME_PLUS;
+    case BT_AST:
+      if (tok == XML_TOK_NMTOKEN)  {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_NAME_ASTERISK;
+    case BT_QUEST:
+      if (tok == XML_TOK_NMTOKEN)  {
+        *nextTokPtr = ptr;
+        return XML_TOK_INVALID;
+      }
+      *nextTokPtr = ptr + MINBPC(enc);
+      return XML_TOK_NAME_QUESTION;
+    default:
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    }
+  }
+  return -tok;
+}
+
+static int PTRCALL
+PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
+                          const char *end, const char **nextTokPtr)
+{
+  const char *start;
+  if (ptr == end)
+    return XML_TOK_NONE;
+  start = ptr;
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: ptr += n; break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_AMP:
+      if (ptr == start)
+        return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_LT:
+      /* this is for inside entity references */
+      *nextTokPtr = ptr;
+      return XML_TOK_INVALID;
+    case BT_LF:
+      if (ptr == start) {
+        *nextTokPtr = ptr + MINBPC(enc);
+        return XML_TOK_DATA_NEWLINE;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_CR:
+      if (ptr == start) {
+        ptr += MINBPC(enc);
+        if (ptr == end)
+          return XML_TOK_TRAILING_CR;
+        if (BYTE_TYPE(enc, ptr) == BT_LF)
+          ptr += MINBPC(enc);
+        *nextTokPtr = ptr;
+        return XML_TOK_DATA_NEWLINE;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_S:
+      if (ptr == start) {
+        *nextTokPtr = ptr + MINBPC(enc);
+        return XML_TOK_ATTRIBUTE_VALUE_S;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  *nextTokPtr = ptr;
+  return XML_TOK_DATA_CHARS;
+}
+
+static int PTRCALL
+PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
+                       const char *end, const char **nextTokPtr)
+{
+  const char *start;
+  if (ptr == end)
+    return XML_TOK_NONE;
+  start = ptr;
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: ptr += n; break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_AMP:
+      if (ptr == start)
+        return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_PERCNT:
+      if (ptr == start) {
+        int tok =  PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
+                                       end, nextTokPtr);
+        return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_LF:
+      if (ptr == start) {
+        *nextTokPtr = ptr + MINBPC(enc);
+        return XML_TOK_DATA_NEWLINE;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    case BT_CR:
+      if (ptr == start) {
+        ptr += MINBPC(enc);
+        if (ptr == end)
+          return XML_TOK_TRAILING_CR;
+        if (BYTE_TYPE(enc, ptr) == BT_LF)
+          ptr += MINBPC(enc);
+        *nextTokPtr = ptr;
+        return XML_TOK_DATA_NEWLINE;
+      }
+      *nextTokPtr = ptr;
+      return XML_TOK_DATA_CHARS;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  *nextTokPtr = ptr;
+  return XML_TOK_DATA_CHARS;
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
+                         const char *end, const char **nextTokPtr)
+{
+  int level = 0;
+  if (MINBPC(enc) > 1) {
+    size_t n = end - ptr;
+    if (n & (MINBPC(enc) - 1)) {
+      n &= ~(MINBPC(enc) - 1);
+      end = ptr + n;
+    }
+  }
+  while (ptr != end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    INVALID_CASES(ptr, nextTokPtr)
+    case BT_LT:
+      if ((ptr += MINBPC(enc)) == end)
+        return XML_TOK_PARTIAL;
+      if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
+        if ((ptr += MINBPC(enc)) == end)
+          return XML_TOK_PARTIAL;
+        if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
+          ++level;
+          ptr += MINBPC(enc);
+        }
+      }
+      break;
+    case BT_RSQB:
+      if ((ptr += MINBPC(enc)) == end)
+        return XML_TOK_PARTIAL;
+      if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+        if ((ptr += MINBPC(enc)) == end)
+          return XML_TOK_PARTIAL;
+        if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+          ptr += MINBPC(enc);
+          if (level == 0) {
+            *nextTokPtr = ptr;
+            return XML_TOK_IGNORE_SECT;
+          }
+          --level;
+        }
+      }
+      break;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+  }
+  return XML_TOK_PARTIAL;
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+                   const char **badPtr)
+{
+  ptr += MINBPC(enc);
+  end -= MINBPC(enc);
+  for (; ptr != end; ptr += MINBPC(enc)) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_DIGIT:
+    case BT_HEX:
+    case BT_MINUS:
+    case BT_APOS:
+    case BT_LPAR:
+    case BT_RPAR:
+    case BT_PLUS:
+    case BT_COMMA:
+    case BT_SOL:
+    case BT_EQUALS:
+    case BT_QUEST:
+    case BT_CR:
+    case BT_LF:
+    case BT_SEMI:
+    case BT_EXCL:
+    case BT_AST:
+    case BT_PERCNT:
+    case BT_NUM:
+#ifdef XML_NS
+    case BT_COLON:
+#endif
+      break;
+    case BT_S:
+      if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
+        *badPtr = ptr;
+        return 0;
+      }
+      break;
+    case BT_NAME:
+    case BT_NMSTRT:
+      if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+        break;
+    default:
+      switch (BYTE_TO_ASCII(enc, ptr)) {
+      case 0x24: /* $ */
+      case 0x40: /* @ */
+        break;
+      default:
+        *badPtr = ptr;
+        return 0;
+      }
+      break;
+    }
+  }
+  return 1;
+}
+
+/* This must only be called for a well-formed start-tag or empty
+   element tag.  Returns the number of attributes.  Pointers to the
+   first attsMax attributes are stored in atts.
+*/
+
+static int PTRCALL
+PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
+                int attsMax, ATTRIBUTE *atts)
+{
+  enum { other, inName, inValue } state = inName;
+  int nAtts = 0;
+  int open = 0; /* defined when state == inValue;
+                   initialization just to shut up compilers */
+
+  for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define START_NAME \
+      if (state == other) { \
+        if (nAtts < attsMax) { \
+          atts[nAtts].name = ptr; \
+          atts[nAtts].normalized = 1; \
+        } \
+        state = inName; \
+      }
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_NONASCII:
+    case BT_NMSTRT:
+    case BT_HEX:
+      START_NAME
+      break;
+#undef START_NAME
+    case BT_QUOT:
+      if (state != inValue) {
+        if (nAtts < attsMax)
+          atts[nAtts].valuePtr = ptr + MINBPC(enc);
+        state = inValue;
+        open = BT_QUOT;
+      }
+      else if (open == BT_QUOT) {
+        state = other;
+        if (nAtts < attsMax)
+          atts[nAtts].valueEnd = ptr;
+        nAtts++;
+      }
+      break;
+    case BT_APOS:
+      if (state != inValue) {
+        if (nAtts < attsMax)
+          atts[nAtts].valuePtr = ptr + MINBPC(enc);
+        state = inValue;
+        open = BT_APOS;
+      }
+      else if (open == BT_APOS) {
+        state = other;
+        if (nAtts < attsMax)
+          atts[nAtts].valueEnd = ptr;
+        nAtts++;
+      }
+      break;
+    case BT_AMP:
+      if (nAtts < attsMax)
+        atts[nAtts].normalized = 0;
+      break;
+    case BT_S:
+      if (state == inName)
+        state = other;
+      else if (state == inValue
+               && nAtts < attsMax
+               && atts[nAtts].normalized
+               && (ptr == atts[nAtts].valuePtr
+                   || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
+                   || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
+                   || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
+        atts[nAtts].normalized = 0;
+      break;
+    case BT_CR: case BT_LF:
+      /* This case ensures that the first attribute name is counted
+         Apart from that we could just change state on the quote. */
+      if (state == inName)
+        state = other;
+      else if (state == inValue && nAtts < attsMax)
+        atts[nAtts].normalized = 0;
+      break;
+    case BT_GT:
+    case BT_SOL:
+      if (state != inValue)
+        return nAtts;
+      break;
+    default:
+      break;
+    }
+  }
+  /* not reached */
+}
+
+static int PTRFASTCALL
+PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+{
+  int result = 0;
+  /* skip &# */
+  ptr += 2*MINBPC(enc);
+  if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
+    for (ptr += MINBPC(enc);
+         !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
+         ptr += MINBPC(enc)) {
+      int c = BYTE_TO_ASCII(enc, ptr);
+      switch (c) {
+      case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
+      case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
+        result <<= 4;
+        result |= (c - ASCII_0);
+        break;
+      case ASCII_A: case ASCII_B: case ASCII_C:
+      case ASCII_D: case ASCII_E: case ASCII_F:
+        result <<= 4;
+        result += 10 + (c - ASCII_A);
+        break;
+      case ASCII_a: case ASCII_b: case ASCII_c:
+      case ASCII_d: case ASCII_e: case ASCII_f:
+        result <<= 4;
+        result += 10 + (c - ASCII_a);
+        break;
+      }
+      if (result >= 0x110000)
+        return -1;
+    }
+  }
+  else {
+    for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
+      int c = BYTE_TO_ASCII(enc, ptr);
+      result *= 10;
+      result += (c - ASCII_0);
+      if (result >= 0x110000)
+        return -1;
+    }
+  }
+  return checkCharRefNumber(result);
+}
+
+static int PTRCALL
+PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
+                             const char *end)
+{
+  switch ((end - ptr)/MINBPC(enc)) {
+  case 2:
+    if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
+      switch (BYTE_TO_ASCII(enc, ptr)) {
+      case ASCII_l:
+        return ASCII_LT;
+      case ASCII_g:
+        return ASCII_GT;
+      }
+    }
+    break;
+  case 3:
+    if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
+      ptr += MINBPC(enc);
+      if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
+        ptr += MINBPC(enc);
+        if (CHAR_MATCHES(enc, ptr, ASCII_p))
+          return ASCII_AMP;
+      }
+    }
+    break;
+  case 4:
+    switch (BYTE_TO_ASCII(enc, ptr)) {
+    case ASCII_q:
+      ptr += MINBPC(enc);
+      if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
+        ptr += MINBPC(enc);
+        if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+          ptr += MINBPC(enc);
+          if (CHAR_MATCHES(enc, ptr, ASCII_t))
+            return ASCII_QUOT;
+        }
+      }
+      break;
+    case ASCII_a:
+      ptr += MINBPC(enc);
+      if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
+        ptr += MINBPC(enc);
+        if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+          ptr += MINBPC(enc);
+          if (CHAR_MATCHES(enc, ptr, ASCII_s))
+            return ASCII_APOS;
+        }
+      }
+      break;
+    }
+  }
+  return 0;
+}
+
+static int PTRCALL
+PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+  for (;;) {
+    switch (BYTE_TYPE(enc, ptr1)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: \
+      if (*ptr1++ != *ptr2++) \
+        return 0;
+    LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
+#undef LEAD_CASE
+      /* fall through */
+      if (*ptr1++ != *ptr2++)
+        return 0;
+      break;
+    case BT_NONASCII:
+    case BT_NMSTRT:
+#ifdef XML_NS
+    case BT_COLON:
+#endif
+    case BT_HEX:
+    case BT_DIGIT:
+    case BT_NAME:
+    case BT_MINUS:
+      if (*ptr2++ != *ptr1++)
+        return 0;
+      if (MINBPC(enc) > 1) {
+        if (*ptr2++ != *ptr1++)
+          return 0;
+        if (MINBPC(enc) > 2) {
+          if (*ptr2++ != *ptr1++)
+            return 0;
+          if (MINBPC(enc) > 3) {
+            if (*ptr2++ != *ptr1++)
+              return 0;
+          }
+        }
+      }
+      break;
+    default:
+      if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
+        return 1;
+      switch (BYTE_TYPE(enc, ptr2)) {
+      case BT_LEAD2:
+      case BT_LEAD3:
+      case BT_LEAD4:
+      case BT_NONASCII:
+      case BT_NMSTRT:
+#ifdef XML_NS
+      case BT_COLON:
+#endif
+      case BT_HEX:
+      case BT_DIGIT:
+      case BT_NAME:
+      case BT_MINUS:
+        return 0;
+      default:
+        return 1;
+      }
+    }
+  }
+  /* not reached */
+}
+
+static int PTRCALL
+PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
+                         const char *end1, const char *ptr2)
+{
+  for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
+    if (ptr1 == end1)
+      return 0;
+    if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+      return 0;
+  }
+  return ptr1 == end1;
+}
+
+static int PTRFASTCALL
+PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
+{
+  const char *start = ptr;
+  for (;;) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: ptr += n; break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_NONASCII:
+    case BT_NMSTRT:
+#ifdef XML_NS
+    case BT_COLON:
+#endif
+    case BT_HEX:
+    case BT_DIGIT:
+    case BT_NAME:
+    case BT_MINUS:
+      ptr += MINBPC(enc);
+      break;
+    default:
+      return (int)(ptr - start);
+    }
+  }
+}
+
+static const char * PTRFASTCALL
+PREFIX(skipS)(const ENCODING *enc, const char *ptr)
+{
+  for (;;) {
+    switch (BYTE_TYPE(enc, ptr)) {
+    case BT_LF:
+    case BT_CR:
+    case BT_S:
+      ptr += MINBPC(enc);
+      break;
+    default:
+      return ptr;
+    }
+  }
+}
+
+static void PTRCALL
+PREFIX(updatePosition)(const ENCODING *enc,
+                       const char *ptr,
+                       const char *end,
+                       POSITION *pos)
+{
+  while (ptr < end) {
+    switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+    case BT_LEAD ## n: \
+      if (end - ptr < n) { \
+        return; \
+      } \
+      ptr += n; \
+      break;
+    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+    case BT_LF:
+      pos->columnNumber = (XML_Size)-1;
+      pos->lineNumber++;
+      ptr += MINBPC(enc);
+      break;
+    case BT_CR:
+      pos->lineNumber++;
+      ptr += MINBPC(enc);
+      if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+        ptr += MINBPC(enc);
+      pos->columnNumber = (XML_Size)-1;
+      break;
+    default:
+      ptr += MINBPC(enc);
+      break;
+    }
+    pos->columnNumber++;
+  }
+}
+
+#undef DO_LEAD_CASE
+#undef MULTIBYTE_CASES
+#undef INVALID_CASES
+#undef CHECK_NAME_CASE
+#undef CHECK_NAME_CASES
+#undef CHECK_NMSTRT_CASE
+#undef CHECK_NMSTRT_CASES
+
+#endif /* XML_TOK_IMPL_C */

+ 46 - 0
libs/expat/lib/xmltok_impl.h

@@ -0,0 +1,46 @@
+/*
+Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+See the file COPYING for copying permission.
+*/
+
+enum {
+  BT_NONXML,
+  BT_MALFORM,
+  BT_LT,
+  BT_AMP,
+  BT_RSQB,
+  BT_LEAD2,
+  BT_LEAD3,
+  BT_LEAD4,
+  BT_TRAIL,
+  BT_CR,
+  BT_LF,
+  BT_GT,
+  BT_QUOT,
+  BT_APOS,
+  BT_EQUALS,
+  BT_QUEST,
+  BT_EXCL,
+  BT_SOL,
+  BT_SEMI,
+  BT_NUM,
+  BT_LSQB,
+  BT_S,
+  BT_NMSTRT,
+  BT_COLON,
+  BT_HEX,
+  BT_DIGIT,
+  BT_NAME,
+  BT_MINUS,
+  BT_OTHER, /* known not to be a name or name start character */
+  BT_NONASCII, /* might be a name or name start character */
+  BT_PERCNT,
+  BT_LPAR,
+  BT_RPAR,
+  BT_AST,
+  BT_PLUS,
+  BT_COMMA,
+  BT_VERBAR
+};
+
+#include <stddef.h>

+ 115 - 0
libs/expat/lib/xmltok_ns.c

@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_NS_C
+
+const ENCODING *
+NS(XmlGetUtf8InternalEncoding)(void)
+{
+  return &ns(internal_utf8_encoding).enc;
+}
+
+const ENCODING *
+NS(XmlGetUtf16InternalEncoding)(void)
+{
+#if BYTEORDER == 1234
+  return &ns(internal_little2_encoding).enc;
+#elif BYTEORDER == 4321
+  return &ns(internal_big2_encoding).enc;
+#else
+  const short n = 1;
+  return (*(const char *)&n
+          ? &ns(internal_little2_encoding).enc
+          : &ns(internal_big2_encoding).enc);
+#endif
+}
+
+static const ENCODING * const NS(encodings)[] = {
+  &ns(latin1_encoding).enc,
+  &ns(ascii_encoding).enc,
+  &ns(utf8_encoding).enc,
+  &ns(big2_encoding).enc,
+  &ns(big2_encoding).enc,
+  &ns(little2_encoding).enc,
+  &ns(utf8_encoding).enc /* NO_ENC */
+};
+
+static int PTRCALL
+NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
+                   const char **nextTokPtr)
+{
+  return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+                  XML_PROLOG_STATE, ptr, end, nextTokPtr);
+}
+
+static int PTRCALL
+NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
+                    const char **nextTokPtr)
+{
+  return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+                  XML_CONTENT_STATE, ptr, end, nextTokPtr);
+}
+
+int
+NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
+                    const char *name)
+{
+  int i = getEncodingIndex(name);
+  if (i == UNKNOWN_ENC)
+    return 0;
+  SET_INIT_ENC_INDEX(p, i);
+  p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
+  p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
+  p->initEnc.updatePosition = initUpdatePosition;
+  p->encPtr = encPtr;
+  *encPtr = &(p->initEnc);
+  return 1;
+}
+
+static const ENCODING *
+NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
+{
+#define ENCODING_MAX 128
+  char buf[ENCODING_MAX];
+  char *p = buf;
+  int i;
+  XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+  if (ptr != end)
+    return 0;
+  *p = 0;
+  if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
+    return enc;
+  i = getEncodingIndex(buf);
+  if (i == UNKNOWN_ENC)
+    return 0;
+  return NS(encodings)[i];
+}
+
+int
+NS(XmlParseXmlDecl)(int isGeneralTextEntity,
+                    const ENCODING *enc,
+                    const char *ptr,
+                    const char *end,
+                    const char **badPtr,
+                    const char **versionPtr,
+                    const char **versionEndPtr,
+                    const char **encodingName,
+                    const ENCODING **encoding,
+                    int *standalone)
+{
+  return doParseXmlDecl(NS(findEncoding),
+                        isGeneralTextEntity,
+                        enc,
+                        ptr,
+                        end,
+                        badPtr,
+                        versionPtr,
+                        versionEndPtr,
+                        encodingName,
+                        encoding,
+                        standalone);
+}
+
+#endif /* XML_TOK_NS_C */

+ 0 - 17
libs/install/openssl/build_source.bat

@@ -1,17 +0,0 @@
-@echo off
-rem See INSTALL.W32
-call perl Configure BC-32
-call ms\do_nasm
-call ms\x86asm
-call %~dp0\cleanup.bat
-
-copy %~dp0\..\..\..\libs\openssl\Makefile
-
-echo. >> crypto\opensslconf.h
-echo #ifndef _timeb >> crypto\opensslconf.h
-echo #define _timeb timeb >> crypto\opensslconf.h
-echo #endif >> crypto\opensslconf.h
-echo. >> crypto\opensslconf.h
-echo #ifndef _ftime >> crypto\opensslconf.h
-echo #define _ftime ftime >> crypto\opensslconf.h
-echo #endif >> crypto\opensslconf.h

+ 0 - 234
libs/install/openssl/cleanup.bat

@@ -1,234 +0,0 @@
-@echo off
-
-cd crypto
-del /s Makefile.*
-del /s README
-del /s VERSION
-del /s INSTALL
-del /s todo
-del /s test
-del /s example
-del /s generate
-
-del /s *.pl
-del /s *.mul
-del /s *.pem
-del /s *.ec
-
-del /s *586*.*
-del /s *ia64*.*
-del /s *x86_64*.*
-del /s *mips*.*
-del /s *risc2*.*
-del /s *sparc*.*
-del /s *vms*.*
-
-del /s *speed*.c
-del /s *test*.c
-
-
-rmdir /s /q aes\asm
-rem del asn1\p8_key.c
-rem del asn1\tasn_prn.c
-del bf\bf_cbc.c
-del bf\bf_enc.c
-del bf\bf_opts.c
-del bf\bfs.cpp
-del bio\bf_lbuf.c
-del bio\bss_rtcp.c
-del bio\bss_dgram.c
-rmdir /s /q bn\asm
-rem del bn\bn_opt.c
-rem del bn\bn_x931p.c
-del bn\exp.c
-rmdir /s /q camellia
-del cast\c_enc.c
-del cast\cast_spd.c
-del cast\castopts.c
-del cast\casts.cpp
-rmdir /s /q cms
-del conf\cnf_save.c
-del conf\ssleay.cnf
-del des\asm\des_enc.m4
-rmdir /s /q des\t
-rmdir /s /q des\times
-del des\cbc3_enc.c
-del des\des.c
-del des\DES.pm
-del des\des.pod
-del des\DES.xs
-del des\des-lib.com
-del des\des_enc.c
-rem del des\des_lib.c
-del des\des_old.c
-del des\des_old.h
-del des\des_old2.c
-del des\des_opts.c
-del des\des3s.cpp
-del des\dess.cpp
-del des\fcrypt_b.c
-del des\FILES0
-del des\Imakefile
-del des\KERBEROS
-del des\options.txt
-del des\read_pwd.c
-del des\read2pwd.c
-del des\rpw.c
-del des\typemap
-del dh\p1024.c
-del dh\p192.c
-del dh\p512.c
-del dsa\fips186a.txt
-del dsa\dsagen.c
-del dso\dso_beos.c
-rmdir /s /q engine
-rem del evp\dig_eng.c
-del evp\e_camellia.c
-del evp\e_dsa.c
-del evp\e_rc5.c
-del evp\e_seed.c
-rem del evp\evp_cnf.c
-del evp\evptests.txt
-del evp\m_md2.c
-del evp\m_mdc2.c
-del evp\openbsd_hw.c
-del idea\idea_spd.c
-rmdir /s /q jpake
-rmdir /s /q md2
-del md4\md4.c
-del md4\md4s.cpp
-del md5\md5.c
-del md5\md5s.cpp
-rmdir /s /q mdc2
-del objects\objects.README
-del pem\message
-del pem\pkcs7.lis
-rmdir perlasm
-rmdir /s /q pkcs7\p7
-rmdir /s /q pkcs7\t
-del pkcs7\bio_ber.c
-del pkcs7\dec.c
-del pkcs7\doc
-del pkcs7\enc.c
-del pkcs7\example.c
-del pkcs7\example.h
-del pkcs7\pk7_dgst.c
-del pkcs7\pk7_enc.c
-del pkcs7\sign.c
-del pkcs7\verify.c
-rem del rand\rand_eng.c
-del rand\rand_nw.c
-del rand\rand_os2.c
-del rand\rand_unix.c
-del rand\randfile.c
-del rc2\rrc2.doc
-del rc2\tab.c
-del rc4\rc4.c
-rem del rc4\rc4_enc.c
-rmdir /s /q rc4\asm
-rem del rc4\rc4_fblk.c
-del rc4\rc4s.cpp
-del rc4\rrc4.doc
-rmdir /s /q rc5
-rmdir /s /q ripemd\asm
-del ripemd\rmd160.c
-rem del rsa\rsa_x931g.c
-rmdir /s /q seed
-rem del sha\asm\sha512-sse2.asm
-del sha\sha.c
-del sha\sha1.c
-rem del sha\sha1s.cpp
-del sha\sha256t.c
-del sha\sha512t.c
-rmdir /s /q store
-rmdir /s /q threads
-del x509v3\v3conf.c
-del x509v3\v3prin.c
-rem del cpu_win32.asm
-del crypto-lib.com
-rem del dyn_lck.c
-rem del fips_err.c
-rem del fips_err.h
-del install-crypto.com
-del LPdir_nyi.c
-del LPdir_unix.c
-del LPdir_wince.c
-rem del o_init.c
-del opensslconf.h.bak
-del opensslconf.h.in
-
-rem openssl-0.9.8k:
-del aes\aes_x86core.c
-rem del asn1\ameth_lib.c
-rem del asn1\asn1_locl.h
-del asn1\bio_asn1.c
-del asn1\bio_ndef.c
-del asn1\x_nx509.c
-
-rmdir /s /q ec
-rmdir /s /q ecdh
-rmdir /s /q ecdsa
-rmdir /s /q whrlpool
-
-cd ..
-
-cd ssl
-del install-ssl.com
-del Makefile
-del ssl-lib.com
-del ssl_task.c
-del ssltest.c
-cd ..
-
-rmdir /s /q apps
-rmdir /s /q bugs
-rmdir /s /q certs
-rmdir /s /q demos
-rmdir /s /q doc
-rmdir /s /q engines
-rem rmdir /s /q fips
-rmdir /s /q include
-rmdir /s /q MacOS
-rmdir /s /q ms
-rmdir /s /q Netware
-rmdir /s /q os2
-rmdir /s /q perl
-rmdir /s /q shlib
-rmdir /s /q test
-rmdir /s /q times
-rmdir /s /q tools
-rmdir /s /q util
-rmdir /s /q VMS
-
-del /q CHANGES.*
-del config
-del Configure
-del FAQ
-del /q INSTALL.*
-del Makefile.bak
-del Makefile.org
-del Makefile.shared
-del makevms.com
-del MINFO
-del NEWS
-del openssl.doxy
-del openssl.spec
-del PROBLEMS
-del /q README.*
-
-ren crypto\des\asm\d-win32.asm d_win32.asm
-ren crypto\des\asm\y-win32.asm y_win32.asm
-ren crypto\bf\asm\b-win32.asm b_win32.asm
-ren crypto\cast\asm\c-win32.asm c_win32.asm
-rem ren crypto\rc4\asm\r4-win32.asm r4_win32.asm
-ren crypto\md5\asm\m5-win32.asm m5_win32.asm
-ren crypto\sha\asm\s1-win32.asm s1_win32.asm
-rem ren crypto\ripemd\asm\rm-win32.asm rm_win32
-
-set PHP=%~dp0\..\..\..\buildtools\php\php.exe
-%PHP% %~dp0\fixasmalign.php crypto\des\asm\d_win32.asm 
-%PHP% %~dp0\fixasmalign.php crypto\des\asm\y_win32.asm
-%PHP% %~dp0\fixasmalign.php crypto\bf\asm\b_win32.asm
-%PHP% %~dp0\fixasmalign.php crypto\cast\asm\c_win32.asm
-%PHP% %~dp0\fixasmalign.php crypto\md5\asm\m5_win32.asm
-%PHP% %~dp0\fixasmalign.php crypto\sha\asm\s1_win32.asm

+ 0 - 14
libs/install/openssl/fixasmalign.php

@@ -1,14 +0,0 @@
-<?
-
-$filename = $_SERVER["argv"][1];
-
-$timestamp = filemtime($filename);
-$contents = file_get_contents($filename);
-
-$contents = str_replace("align=64", "align=256", $contents);
-
-file_put_contents($filename, $contents);
-
-touch($filename, $timestamp);
-
-?>

+ 0 - 31
libs/install/openssl/readme

@@ -1,31 +0,0 @@
-- Stahnout zdrojaky
-  http://www.openssl.org/source/
-
-- Rozbalit zdrojaky z openssl-x.x.xx.tar.gz do docasneho adresare.
-  Bude hlasit chyby ohledne symlinku, zda se ze to nevadi.
-
-  Musi byt takovato struktura:
-  openssl-x.x.xx\
-  lib\
-
-- Spustit build_source.bat z rootu zdrojaku, tj. ze openssl-x.x.xx\
-  Presmerovat do souboru kvuli kontrole chyb.
-
-- Zvazit pridani novych zdrojaku do Makefile
-
-- Nakopirovat zdrojaky, tj. openssl-x.x.xx\*, do
-  libs\openssl
-
-- Spustit make z openssl-x.x.xx\
-  Presmerovat do souboru kvuli kontrole chyb.
-
-- Zazalohovat knihovny z lib\ do libs\lib\
-
-- Nakopirovat hlavicky z openssl-x.x.xx\openssl do libs\openssl\openssl\
-
-- Zmenit cislo verze a rok OpenSSL v source\resource\TextsCore1.rc
-  OPENSSL_COPYRIGHT
-  OPENSSL_VERSION
-
-- Je treba udelat zvlast pro master a winscp52x
-  (jiny postup a vysledne binarky)

+ 0 - 6
libs/install/openssl/readme_debug

@@ -1,6 +0,0 @@
-Debug build:
-- do CFLAG pridat 
-  -v -y -k -r- -vi-
-  pro CodeGuard pridat
-  -vG 
-  nahradit -O2 za -Od

+ 1 - 1
source/Console.cbproj

@@ -41,7 +41,7 @@
 			<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.0.2.0;InternalName=console;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.2.4.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.0.2.0;InternalName=console;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.2.5.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_Release>2</VerInfo_Release>

+ 1 - 1
source/DragExt.cbproj

@@ -42,7 +42,7 @@
 			<ProjectType>CppDynamicLibrary</ProjectType>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.2.4.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.2.5.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_Release>1</VerInfo_Release>

+ 2 - 2
source/DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
 FILEVERSION 1,2,1,0
-PRODUCTVERSION 5,2,4,0
+PRODUCTVERSION 5,2,5,0
 FILEOS 0x4
 FILETYPE 0x2
 {
@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "5.2.4.0\0"
+            VALUE "ProductVersion", "5.2.5.0\0"
             VALUE "ReleaseType", "beta\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 8 - 0
source/Putty.cbproj

@@ -98,10 +98,18 @@
 			<TASM_Debugging>None</TASM_Debugging>
 		</PropertyGroup>
 		<ItemGroup>
+			<CppCompile Include="putty\CALLBACK.C">
+				<BuildOrder>5</BuildOrder>
+				<BuildOrder>25</BuildOrder>
+			</CppCompile>
 			<CppCompile Include="putty\CHARSET\UTF8.C">
 				<BuildOrder>80</BuildOrder>
 				<BuildOrder>0</BuildOrder>
 			</CppCompile>
+			<CppCompile Include="putty\CONF.C">
+				<BuildOrder>5</BuildOrder>
+				<BuildOrder>25</BuildOrder>
+			</CppCompile>
 			<CppCompile Include="putty\CPROXY.C">
 				<BuildOrder>5</BuildOrder>
 				<BuildOrder>25</BuildOrder>

+ 9 - 3
source/WinSCP.cbproj

@@ -39,6 +39,9 @@
 			<BRCC_CodePage>65001</BRCC_CodePage>
 			<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
 			<DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Vcl;$(DCC_Namespace)</DCC_Namespace>
+			<DCC_SYMBOL_DEPRECATED>false</DCC_SYMBOL_DEPRECATED>
+			<DCC_SYMBOL_PLATFORM>false</DCC_SYMBOL_PLATFORM>
+			<DCC_UNSUPPORTED_CONSTRUCT>false</DCC_UNSUPPORTED_CONSTRUCT>
 			<Defines>OLD_DND;STRICT;$(Defines)</Defines>
 			<Icon_MainIcon>resource\Icon256.ico</Icon_MainIcon>
 			<ILINK_GenerateDRC>true</ILINK_GenerateDRC>
@@ -51,11 +54,11 @@
 			<ProjectType>CppVCLApplication</ProjectType>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.2.4.0;InternalName=winscp;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.2.4.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.2.5.0;InternalName=winscp;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.2.5.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
-			<VerInfo_Release>4</VerInfo_Release>
+			<VerInfo_Release>5</VerInfo_Release>
 		</PropertyGroup>
 		<PropertyGroup Condition="'$(Cfg_1)'!=''">
 			<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
@@ -82,7 +85,7 @@
 			<BCC_MonitorInlinePtrAccess>true</BCC_MonitorInlinePtrAccess>
 			<BCC_MonitorThis>true</BCC_MonitorThis>
 			<DCC_DebugDCUs>true</DCC_DebugDCUs>
-			<Debugger_DebugSourcePath>packages\my; packages\filemng;..\libs\openssl\crypto\bio;..\libs\openssl\ssl;..\libs\openssl\crypto\stack;$(Debugger_DebugSourcePath)</Debugger_DebugSourcePath>
+			<Debugger_DebugSourcePath>packages\my; packages\filemng;..\libs\openssl\crypto\bio;..\libs\openssl\ssl;..\libs\openssl\crypto\stack;..\libs\openssl\crypto\x509;$(Debugger_DebugSourcePath)</Debugger_DebugSourcePath>
 		</PropertyGroup>
 		<PropertyGroup Condition="'$(Cfg_2)'!=''">
 			<Defines>NDEBUG;$(Defines)</Defines>
@@ -176,6 +179,9 @@
 				<BuildOrder>6</BuildOrder>
 				<BuildOrder>53</BuildOrder>
 			</CppCompile>
+			<DelphiCompile Include="windows\Vcl.Controls.pas">
+				<BuildOrder>35</BuildOrder>
+			</DelphiCompile>
 			<CppCompile Include="windows\WinConfiguration.cpp">
 				<BuildOrder>56</BuildOrder>
 				<BuildOrder>3</BuildOrder>

+ 10 - 5
source/components/ThemePageControl.cpp

@@ -4,6 +4,7 @@
 
 #include <Common.h>
 #include <vsstyle.h>
+#include <memory>
 #include "ThemePageControl.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -183,7 +184,7 @@ void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
       RectMem.Bottom--;
     }
 
-    DrawTabItem(DCMem, Item, RectMem, (State == TIS_SELECTED));
+    DrawTabItem(DCMem, Item, RectMem, (State == TIS_SELECTED), (State == TIS_DISABLED));
   }
 
   // Blit image to the screen
@@ -194,7 +195,8 @@ void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
 }
 //----------------------------------------------------------------------------------------------------------
 // draw tab item context: possible icon and text
-void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, bool Selected)
+void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect,
+  bool Selected, bool Shadowed)
 {
   if (Selected)
   {
@@ -210,7 +212,6 @@ void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, boo
 
   UnicodeString Text = Pages[Item]->Caption;
 
-  int OldMode = SetBkMode(DC, TRANSPARENT);
   if ((Images != NULL) && (Pages[Item]->ImageIndex >= 0))
   {
     int Left;
@@ -223,8 +224,11 @@ void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, boo
       Left = (Rect.Right - Images->Width - Rect.Left) / 2;
     }
     int Y = ((Rect.Top + Rect.Bottom - Images->Height) / 2) - 1 + (Selected ? 0 : -2);
-    ImageList_Draw((HIMAGELIST)Images->Handle, Pages[Item]->ImageIndex, DC,
-      Left, Y, ILD_TRANSPARENT);
+    std::unique_ptr<TCanvas> Canvas(new TCanvas());
+    Canvas->Handle = DC;
+    Images->Draw(Canvas.get(), Left, Y, Pages[Item]->ImageIndex, !Shadowed);
+    //ImageList_Draw((HIMAGELIST)Images->Handle, Pages[Item]->ImageIndex, DC,
+    //  Left, Y, ILD_TRANSPARENT, );
     Rect.Left += Images->Width + 3;
   }
   else
@@ -232,6 +236,7 @@ void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, boo
     Rect.Left -= 2;
   }
 
+  int OldMode = SetBkMode(DC, TRANSPARENT);
   if (!Text.IsEmpty())
   {
     HFONT OldFont = (HFONT)SelectObject(DC, Font->Handle);

+ 1 - 1
source/components/ThemePageControl.h

@@ -32,7 +32,7 @@ protected:
 
 private:
   void __fastcall DrawThemesXpTabItem(HDC DC, int Item, const TRect & Rect, bool Body, int State);
-  void __fastcall DrawTabItem(HDC DC, int Item, TRect Rect, bool Selected);
+  void __fastcall DrawTabItem(HDC DC, int Item, TRect Rect, bool Selected, bool Shadowed);
   void __fastcall DrawThemesPart(HDC DC, int PartId, int StateId, LPCWSTR PartNameID, LPRECT Rect);
   void __fastcall InvalidateTab(int Index);
 

+ 6 - 1
source/components/UnixDirView.cpp

@@ -127,11 +127,16 @@ __fastcall TUnixDirView::~TUnixDirView()
 void __fastcall TUnixDirView::DisplayContextMenu(const TPoint &Where)
 {
   bool Handled = false;
-  if (OnContextPopup) OnContextPopup(this, ScreenToClient(Where), Handled);
+  if (OnContextPopup)
+  {
+    OnContextPopup(this, ScreenToClient(Where), Handled);
+  }
   if (!Handled)
   {
     if (PopupMenu && !PopupMenu->AutoPopup)
+    {
       PopupMenu->Popup(Where.x, Where.y);
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 36 - 30
source/components/UnixDriveView.cpp

@@ -441,58 +441,59 @@ void __fastcall TCustomUnixDriveView::Delete(TTreeNode * Node)
 void __fastcall TCustomUnixDriveView::Change(TTreeNode * Node)
 {
   #ifndef DESIGN_ONLY
+  bool Expand = false;
   try
   {
     // During D&D Selected is set to NULL and then back to previous selection,
     // prevent actually changing directory in such case
     if (Reading || ControlState.Contains(csRecreating) ||
-        FIgnoreChange || (Node == NULL) || (Node == FPrevSelected))
+        (Node == NULL) || (Node == FPrevSelected))
     {
       TCustomDriveView::Change(Node);
     }
     else
     {
-      if (FDirView != NULL)
-      {
-        // remember current directory, so it gets selected if we move to parent
-        // directory
-        FDirView->ContinueSession(true);
-      }
-
       // if previous node is child to newly selected one, do not expand it.
       // it is either already expanded and it is even being collapsed.
-      bool Expand = (FPrevSelected == NULL) || !FPrevSelected->HasAsParent(Node);
-      FDirectoryLoaded = false;
-      try
+      Expand = (FPrevSelected == NULL) || !FPrevSelected->HasAsParent(Node);
+      if (FIgnoreChange)
       {
-        APPLICATION_EXCEPTION_HACK_BEGIN
-        {
-          Terminal->ChangeDirectory(NodePathName(Node));
-        }
-        APPLICATION_EXCEPTION_HACK_END;
         TCustomDriveView::Change(Node);
       }
-      __finally
+      else
       {
-        if (FDirectoryLoaded)
+        if (FDirView != NULL)
         {
-          FPrevSelected = Selected;
-          if (Expand)
-          {
-            Selected->Expand(false);
-          }
+          // remember current directory, so it gets selected if we move to parent
+          // directory
+          FDirView->ContinueSession(true);
         }
-        else
+
+        FDirectoryLoaded = false;
+        try
         {
-          assert(!FIgnoreChange);
-          FIgnoreChange = true;
-          try
+          APPLICATION_EXCEPTION_HACK_BEGIN
           {
-            Selected = FPrevSelected;
+            Terminal->ChangeDirectory(NodePathName(Node));
           }
-          __finally
+          APPLICATION_EXCEPTION_HACK_END;
+          TCustomDriveView::Change(Node);
+        }
+        __finally
+        {
+          if (!FDirectoryLoaded)
           {
-            FIgnoreChange = false;
+            assert(!FIgnoreChange);
+            Expand = false;
+            FIgnoreChange = true;
+            try
+            {
+              Selected = FPrevSelected;
+            }
+            __finally
+            {
+              FIgnoreChange = false;
+            }
           }
         }
       }
@@ -500,6 +501,11 @@ void __fastcall TCustomUnixDriveView::Change(TTreeNode * Node)
   }
   __finally
   {
+    FPrevSelected = Selected;
+    if (Expand)
+    {
+      Selected->Expand(false);
+    }
     CheckPendingDeletes();
   }
   #else

+ 156 - 76
source/core/Common.cpp

@@ -11,6 +11,7 @@
 #include <DateUtils.hpp>
 #include <math.h>
 #include <shlobj.h>
+#include <limits>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -283,6 +284,44 @@ UnicodeString ExceptionLogString(Exception *E)
   }
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall MainInstructions(const UnicodeString & S)
+{
+  UnicodeString MainMsgTag = LoadStr(MAIN_MSG_TAG);
+  return MainMsgTag + S + MainMsgTag;
+}
+//---------------------------------------------------------------------------
+bool ExtractMainInstructions(UnicodeString & S, UnicodeString & MainInstructions)
+{
+  bool Result = false;
+  UnicodeString MainMsgTag = LoadStr(MAIN_MSG_TAG);
+  if (StartsStr(MainMsgTag, S))
+  {
+    int EndTagPos =
+      S.SubString(MainMsgTag.Length() + 1, S.Length() - MainMsgTag.Length()).Pos(MainMsgTag);
+    if (EndTagPos > 0)
+    {
+      MainInstructions = S.SubString(MainMsgTag.Length() + 1, EndTagPos - 1);
+      S.Delete(1, EndTagPos + (2 * MainMsgTag.Length()) - 1);
+      Result = true;
+    }
+  }
+
+  assert(MainInstructions.Pos(MainMsgTag) == 0);
+  assert(S.Pos(MainMsgTag) == 0);
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+UnicodeString UnformatMessage(UnicodeString S)
+{
+  UnicodeString MainInstruction;
+  if (ExtractMainInstructions(S, MainInstruction))
+  {
+    S = MainInstruction + S;
+  }
+  return S;
+}
+//---------------------------------------------------------------------------
 bool IsNumber(const UnicodeString Str)
 {
   int Value;
@@ -460,6 +499,17 @@ UnicodeString __fastcall ExtractProgram(UnicodeString Command)
   return Program;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall ExtractProgramName(UnicodeString Command)
+{
+  UnicodeString Name = ExtractFileName(ExtractProgram(Command));
+  int Dot = Name.LastDelimiter(L".");
+  if (Dot > 0)
+  {
+    Name = Name.SubString(1, Dot - 1);
+  }
+  return Name;
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall FormatCommand(UnicodeString Program, UnicodeString Params)
 {
   Program = Program.Trim();
@@ -740,6 +790,21 @@ unsigned char __fastcall HexToByte(const UnicodeString Hex)
     static_cast<unsigned char>(((P1 <= 0) || (P2 <= 0)) ? 0 : (((P1 - 1) << 4) + (P2 - 1)));
 }
 //---------------------------------------------------------------------------
+bool __fastcall IsLowerCaseLetter(wchar_t Ch)
+{
+  return (Ch >= 'a') && (Ch <= 'z');
+}
+//---------------------------------------------------------------------------
+bool __fastcall IsUpperCaseLetter(wchar_t Ch)
+{
+  return (Ch >= 'A') && (Ch <= 'Z');
+}
+//---------------------------------------------------------------------------
+bool __fastcall IsLetter(wchar_t Ch)
+{
+  return IsLowerCaseLetter(Ch) || IsUpperCaseLetter(Ch);
+}
+//---------------------------------------------------------------------------
 bool __fastcall IsDigit(wchar_t Ch)
 {
   return (Ch >= '0') && (Ch <= '9');
@@ -846,6 +911,19 @@ TDateTime __fastcall EncodeTimeVerbose(Word Hour, Word Min, Word Sec, Word MSec)
   }
 }
 //---------------------------------------------------------------------------
+TDateTime __fastcall SystemTimeToDateTimeVerbose(const SYSTEMTIME & SystemTime)
+{
+  try
+  {
+    TDateTime DateTime = SystemTimeToDateTime(SystemTime);
+    return DateTime;
+  }
+  catch (EConvertError & E)
+  {
+    throw EConvertError(FORMAT(L"%s [%d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%3.3d]", (E.Message, int(SystemTime.wYear), int(SystemTime.wMonth), int(SystemTime.wDay), int(SystemTime.wHour), int(SystemTime.wMinute), int(SystemTime.wSecond), int(SystemTime.wMilliseconds))));
+  }
+}
+//---------------------------------------------------------------------------
 struct TDateTimeParams
 {
   TDateTime UnixEpoch;
@@ -870,7 +948,7 @@ struct TDateTimeParams
 };
 typedef std::map<int, TDateTimeParams> TYearlyDateTimeParams;
 static TYearlyDateTimeParams YearlyDateTimeParams;
-static std::auto_ptr<TCriticalSection> DateTimeParamsSection(new TCriticalSection());
+static std::unique_ptr<TCriticalSection> DateTimeParamsSection(new TCriticalSection());
 static void __fastcall EncodeDSTMargin(const SYSTEMTIME & Date, unsigned short Year,
   TDateTime & Result);
 //---------------------------------------------------------------------------
@@ -967,7 +1045,7 @@ static const TDateTimeParams * __fastcall GetDateTimeParams(unsigned short Year)
     }
     Result->SummerDST = (Result->DaylightDate < Result->StandardDate);
 
-    Result->DaylightHack = !IsWin7() || IsExactly2008R2();
+    Result->DaylightHack = !IsWin7();
   }
 
   return Result;
@@ -1165,20 +1243,30 @@ FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime,
 TDateTime __fastcall FileTimeToDateTime(const FILETIME & FileTime)
 {
   // duplicated in DirView.pas
-  SYSTEMTIME SysTime;
-  if (!UsesDaylightHack())
+  TDateTime Result;
+  // The 0xFFF... is sometime seen for invalid timestamps,
+  // it would cause failure in SystemTimeToDateTime below
+  if (FileTime.dwLowDateTime == std::numeric_limits<DWORD>::max())
   {
-    SYSTEMTIME UniverzalSysTime;
-    FileTimeToSystemTime(&FileTime, &UniverzalSysTime);
-    SystemTimeToTzSpecificLocalTime(NULL, &UniverzalSysTime, &SysTime);
+    Result = MinDateTime;
   }
   else
   {
-    FILETIME LocalFileTime;
-    FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
-    FileTimeToSystemTime(&LocalFileTime, &SysTime);
+    SYSTEMTIME SysTime;
+    if (!UsesDaylightHack())
+    {
+      SYSTEMTIME UniverzalSysTime;
+      FileTimeToSystemTime(&FileTime, &UniverzalSysTime);
+      SystemTimeToTzSpecificLocalTime(NULL, &UniverzalSysTime, &SysTime);
+    }
+    else
+    {
+      FILETIME LocalFileTime;
+      FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
+      FileTimeToSystemTime(&LocalFileTime, &SysTime);
+    }
+    Result = SystemTimeToDateTimeVerbose(SysTime);
   }
-  TDateTime Result = SystemTimeToDateTime(SysTime);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -1195,7 +1283,7 @@ __int64 __fastcall ConvertTimestampToUnix(const FILETIME & FileTime,
       SYSTEMTIME SystemTime;
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
-      TDateTime DateTime = SystemTimeToDateTime(SystemTime);
+      TDateTime DateTime = SystemTimeToDateTimeVerbose(SystemTime);
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       Result += (IsDateInDST(DateTime) ?
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
@@ -1215,7 +1303,7 @@ __int64 __fastcall ConvertTimestampToUnix(const FILETIME & FileTime,
       SYSTEMTIME SystemTime;
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
-      TDateTime DateTime = SystemTimeToDateTime(SystemTime);
+      TDateTime DateTime = SystemTimeToDateTimeVerbose(SystemTime);
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       Result -= (IsDateInDST(DateTime) ?
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
@@ -1395,7 +1483,7 @@ UnicodeString __fastcall GetTimeZoneLogString()
   const TDateTimeParams * Params = GetDateTimeParams(0);
 
   UnicodeString Result =
-    FORMAT("Current: GMT%s, Standard: GMT%s, DST: GMT%s, DST Start: %s, DST End: %s",
+    FORMAT(L"Current: GMT%s, Standard: GMT%s, DST: GMT%s, DST Start: %s, DST End: %s",
       (FormatTimeZone(Params->CurrentDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->StandardDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->DaylightDifferenceSec),
@@ -1404,6 +1492,39 @@ UnicodeString __fastcall GetTimeZoneLogString()
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall AdjustClockForDSTEnabled()
+{
+  // Windows XP deletes the DisableAutoDaylightTimeSet value when it is off
+  // (the later versions set it to DynamicDaylightTimeDisabled to 0)
+  bool DynamicDaylightTimeDisabled = false;
+  TRegistry * Registry = new TRegistry(KEY_READ);
+  try
+  {
+    Registry->RootKey = HKEY_LOCAL_MACHINE;
+    if (Registry->OpenKey(L"SYSTEM", false) &&
+        Registry->OpenKey(L"CurrentControlSet", false) &&
+        Registry->OpenKey(L"Control", false) &&
+        Registry->OpenKey(L"TimeZoneInformation", false))
+    {
+      if (Registry->ValueExists(L"DynamicDaylightTimeDisabled"))
+      {
+        DynamicDaylightTimeDisabled = Registry->ReadBool(L"DynamicDaylightTimeDisabled");
+      }
+      // WORKAROUND
+      // Windows XP equivalent
+      else if (Registry->ValueExists(L"DisableAutoDaylightTimeSet"))
+      {
+        DynamicDaylightTimeDisabled = Registry->ReadBool(L"DisableAutoDaylightTimeSet");
+      }
+    }
+    delete Registry;
+  }
+  catch(...)
+  {
+  }
+  return !DynamicDaylightTimeDisabled;
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall StandardTimestamp(const TDateTime & DateTime)
 {
   return FormatDateTime(L"yyyy'-'mm'-'dd'T'hh':'nn':'ss'.'zzz'Z'", ConvertTimestampToUTC(DateTime));
@@ -1624,13 +1745,21 @@ UnicodeString __fastcall DecodeUrlChars(UnicodeString S)
         break;
 
       case L'%':
-        if (i <= S.Length() - 2)
         {
-          unsigned char B = HexToByte(S.SubString(i + 1, 2));
-          if (B > 0)
+          UnicodeString Hex;
+          while ((i + 2 <= S.Length()) && (S[i] == L'%') &&
+                 IsHex(S[i + 1]) && IsHex(S[i + 2]))
+          {
+            Hex += S.SubString(i + 1, 2);
+            S.Delete(i, 3);
+          }
+
+          if (!Hex.IsEmpty())
           {
-            S[i] = (wchar_t)B;
-            S.Delete(i + 1, 2);
+            RawByteString Bytes = HexToBytes(Hex);
+            UTF8String UTF8(Bytes.c_str(), Bytes.Length());
+            UnicodeString Chars(UTF8);
+            S.Insert(Chars, i);
           }
         }
         break;
@@ -1677,9 +1806,8 @@ UnicodeString __fastcall NonUrlChars()
   for (unsigned int I = 0; I <= 127; I++)
   {
     wchar_t C = static_cast<wchar_t>(I);
-    if (((C >= L'a') && (C <= L'z')) ||
-        ((C >= L'A') && (C <= L'Z')) ||
-        ((C >= L'0') && (C <= L'9')) ||
+    if (IsLetter(C) ||
+        IsDigit(C) ||
         (C == L'_') || (C == L'-') || (C == L'.'))
     {
       // noop
@@ -1797,54 +1925,6 @@ bool __fastcall IsWin7()
   return CheckWin32Version(6, 1);
 }
 //---------------------------------------------------------------------------
-// Duplicated in PasTools.pas
-bool __fastcall IsExactly2008R2()
-{
-  bool Result = (Win32MajorVersion == 6) && (Win32MinorVersion == 1);
-  DWORD Type;
-  if (Result && GetWindowsProductType(Type))
-  {
-    switch (Type)
-    {
-      case 0x0008 /*PRODUCT_DATACENTER_SERVER*/:
-      case 0x000C /*PRODUCT_DATACENTER_SERVER_CORE}*/:
-      case 0x0027 /*PRODUCT_DATACENTER_SERVER_CORE_V*/:
-      case 0x0025 /*PRODUCT_DATACENTER_SERVER_V*/:
-      case 0x000A /*PRODUCT_ENTERPRISE_SERVE*/:
-      case 0x000E /*PRODUCT_ENTERPRISE_SERVER_COR*/:
-      case 0x0029 /*PRODUCT_ENTERPRISE_SERVER_CORE_*/:
-      case 0x000F /*PRODUCT_ENTERPRISE_SERVER_IA6*/:
-      case 0x0026 /*PRODUCT_ENTERPRISE_SERVER_*/:
-      case 0x002A /*PRODUCT_HYPER*/:
-      case 0x001E /*PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMEN*/:
-      case 0x0020 /*PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGIN*/:
-      case 0x001F /*PRODUCT_MEDIUMBUSINESS_SERVER_SECURIT*/:
-      case 0x0018 /*PRODUCT_SERVER_FOR_SMALLBUSINES*/:
-      case 0x0023 /*PRODUCT_SERVER_FOR_SMALLBUSINESS_*/:
-      case 0x0021 /*PRODUCT_SERVER_FOUNDATIO*/:
-      case 0x0009 /*PRODUCT_SMALLBUSINESS_SERVE*/:
-      case 0x0038 /*PRODUCT_SOLUTION_EMBEDDEDSERVE*/:
-      case 0x0007 /*PRODUCT_STANDARD_SERVE*/:
-      case 0x000D /*PRODUCT_STANDARD_SERVER_COR*/:
-      case 0x0028 /*PRODUCT_STANDARD_SERVER_CORE_*/:
-      case 0x0024 /*PRODUCT_STANDARD_SERVER_*/:
-      case 0x0017 /*PRODUCT_STORAGE_ENTERPRISE_SERVE*/:
-      case 0x0014 /*PRODUCT_STORAGE_EXPRESS_SERVE*/:
-      case 0x0015 /*PRODUCT_STORAGE_STANDARD_SERVE*/:
-      case 0x0016 /*PRODUCT_STORAGE_WORKGROUP_SERVE*/:
-      case 0x0011 /*PRODUCT_WEB_SERVE*/:
-      case 0x001D /*PRODUCT_WEB_SERVER_COR*/:
-        Result = true;
-        break;
-
-      default:
-        Result = false;
-        break;
-    }
-  }
-  return Result;
-}
-//---------------------------------------------------------------------------
 LCID __fastcall GetDefaultLCID()
 {
   return GetUserDefaultLCID();
@@ -1888,12 +1968,12 @@ UnicodeString __fastcall WindowsProductName()
   try
   {
     Registry->RootKey = HKEY_LOCAL_MACHINE;
-    if (Registry->OpenKey("SOFTWARE", false) &&
-        Registry->OpenKey("Microsoft", false) &&
-        Registry->OpenKey("Windows NT", false) &&
-        Registry->OpenKey("CurrentVersion", false))
+    if (Registry->OpenKey(L"SOFTWARE", false) &&
+        Registry->OpenKey(L"Microsoft", false) &&
+        Registry->OpenKey(L"Windows NT", false) &&
+        Registry->OpenKey(L"CurrentVersion", false))
     {
-      Result = Registry->ReadString("ProductName");
+      Result = Registry->ReadString(L"ProductName");
     }
     delete Registry;
   }
@@ -1907,7 +1987,7 @@ bool __fastcall IsDirectoryWriteable(const UnicodeString & Path)
 {
   UnicodeString FileName =
     IncludeTrailingPathDelimiter(Path) +
-    FORMAT("wscp_%s_%d.tmp", (FormatDateTime(L"nnzzz", Now()), int(GetCurrentProcessId())));
+    FORMAT(L"wscp_%s_%d.tmp", (FormatDateTime(L"nnzzz", Now()), int(GetCurrentProcessId())));
   HANDLE Handle = CreateFile(FileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
     CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 0);
   bool Result = (Handle != INVALID_HANDLE_VALUE);

+ 10 - 1
source/core/Common.h

@@ -6,6 +6,7 @@
 #define THROWOSIFFALSE(C) { if (!(C)) RaiseLastOSError(); }
 #define SAFE_DESTROY_EX(CLASS, OBJ) { CLASS * PObj = OBJ; OBJ = NULL; delete PObj; }
 #define SAFE_DESTROY(OBJ) SAFE_DESTROY_EX(TObject, OBJ)
+#define NULL_TERMINATE(S) S[LENOF(S) - 1] = L'\0'
 #define ASCOPY(dest, source) \
   { \
     AnsiString CopyBuf = source; \
@@ -44,6 +45,9 @@ UnicodeString CopyToChars(const UnicodeString & Str, int & From, UnicodeString C
 UnicodeString DelimitStr(UnicodeString Str, UnicodeString Chars);
 UnicodeString ShellDelimitStr(UnicodeString Str, wchar_t Quote);
 UnicodeString ExceptionLogString(Exception *E);
+UnicodeString __fastcall MainInstructions(const UnicodeString & S);
+bool ExtractMainInstructions(UnicodeString & S, UnicodeString & MainInstructions);
+UnicodeString UnformatMessage(UnicodeString S);
 bool IsNumber(const UnicodeString Str);
 UnicodeString __fastcall SystemTemporaryDirectory();
 UnicodeString __fastcall GetShellFolderPath(int CSIdl);
@@ -56,6 +60,7 @@ UnicodeString __fastcall ValidLocalFileName(
   UnicodeString FileName, wchar_t InvalidCharsReplacement,
   const UnicodeString & TokenizibleChars, const UnicodeString & LocalInvalidChars);
 UnicodeString __fastcall ExtractProgram(UnicodeString Command);
+UnicodeString __fastcall ExtractProgramName(UnicodeString Command);
 UnicodeString __fastcall FormatCommand(UnicodeString Program, UnicodeString Params);
 UnicodeString __fastcall ExpandFileNameCommand(const UnicodeString Command,
   const UnicodeString FileName);
@@ -72,6 +77,9 @@ UnicodeString __fastcall BytesToHex(RawByteString Str, bool UpperCase = true, wc
 UnicodeString __fastcall CharToHex(wchar_t Ch, bool UpperCase = true);
 RawByteString __fastcall HexToBytes(const UnicodeString Hex);
 unsigned char __fastcall HexToByte(const UnicodeString Hex);
+bool __fastcall IsLowerCaseLetter(wchar_t Ch);
+bool __fastcall IsUpperCaseLetter(wchar_t Ch);
+bool __fastcall IsLetter(wchar_t Ch);
 bool __fastcall IsDigit(wchar_t Ch);
 bool __fastcall IsHex(wchar_t Ch);
 UnicodeString __fastcall DecodeUrlChars(UnicodeString S);
@@ -90,7 +98,6 @@ bool __fastcall CutToken(UnicodeString & Str, UnicodeString & Token,
 void __fastcall AddToList(UnicodeString & List, const UnicodeString & Value, const UnicodeString & Delimiter);
 bool __fastcall IsWinXPOrOlder();
 bool __fastcall IsWin7();
-bool __fastcall IsExactly2008R2();
 TLibModule * __fastcall FindModule(void * Instance);
 __int64 __fastcall Round(double Number);
 bool __fastcall TryRelativeStrToDateTime(UnicodeString S, TDateTime & DateTime);
@@ -121,6 +128,7 @@ enum TDSTMode
 bool __fastcall UsesDaylightHack();
 TDateTime __fastcall EncodeDateVerbose(Word Year, Word Month, Word Day);
 TDateTime __fastcall EncodeTimeVerbose(Word Hour, Word Min, Word Sec, Word MSec);
+TDateTime __fastcall SystemTimeToDateTimeVerbose(const SYSTEMTIME & SystemTime);
 TDateTime __fastcall UnixToDateTime(__int64 TimeStamp, TDSTMode DSTMode);
 TDateTime __fastcall ConvertTimestampToUTC(TDateTime DateTime);
 TDateTime __fastcall ConvertTimestampFromUTC(TDateTime DateTime);
@@ -136,6 +144,7 @@ UnicodeString __fastcall FixedLenDateTimeFormat(const UnicodeString & Format);
 UnicodeString __fastcall StandardTimestamp(const TDateTime & DateTime);
 UnicodeString __fastcall StandardTimestamp();
 UnicodeString __fastcall GetTimeZoneLogString();
+bool __fastcall AdjustClockForDSTEnabled();
 int __fastcall CompareFileTime(TDateTime T1, TDateTime T2);
 int __fastcall TimeToMSec(TDateTime T);
 int __fastcall TimeToMinutes(TDateTime T);

+ 1 - 6
source/core/Configuration.cpp

@@ -4,8 +4,8 @@
 
 #include <FileInfo.h>
 
-#include "Exceptions.h"
 #include "Common.h"
+#include "Exceptions.h"
 #include "Configuration.h"
 #include "PuttyIntf.h"
 #include "TextsCore.h"
@@ -958,11 +958,6 @@ UnicodeString __fastcall TConfiguration::GetRootKeyStr()
   return RootKeyToStr(HKEY_CURRENT_USER);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TConfiguration::GetGSSAPIInstalled()
-{
-  return HasGSSAPI();
-}
-//---------------------------------------------------------------------------
 void __fastcall TConfiguration::SetStorage(TStorage value)
 {
   if (FStorage != value)

+ 0 - 2
source/core/Configuration.h

@@ -100,7 +100,6 @@ private:
   void __fastcall SetIniFileStorageName(UnicodeString value);
   UnicodeString __fastcall GetPartialExt() const;
   UnicodeString __fastcall GetFileInfoString(const UnicodeString Key);
-  bool __fastcall GetGSSAPIInstalled();
   void __fastcall SetSessionReopenAuto(int value);
   void __fastcall SetSessionReopenBackground(int value);
   void __fastcall SetSessionReopenTimeout(int value);
@@ -247,7 +246,6 @@ public:
   __property bool DisablePasswordStoring = { read = FDisablePasswordStoring };
   __property bool ForceBanners = { read = FForceBanners };
   __property bool DisableAcceptingHostKeys = { read = FDisableAcceptingHostKeys };
-  __property bool GSSAPIInstalled = { read = GetGSSAPIInstalled };
 };
 //---------------------------------------------------------------------------
 class TShortCuts

+ 34 - 1
source/core/CopyParam.cpp

@@ -43,6 +43,8 @@ void __fastcall TCopyParamType::Default()
   FileMask = L"*.*";
   IncludeFileMask.Masks = L"";
   ClearArchive = false;
+  RemoveCtrlZ = false;
+  RemoveBOM = false;
   CPSLimit = 0;
   NewerOnly = false;
 }
@@ -211,6 +213,27 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     }
   }
 
+  if ((TransferMode == tmAscii) || (TransferMode == tmAutomatic))
+  {
+    if (RemoveBOM != Defaults.RemoveBOM)
+    {
+      if (ALWAYS_TRUE(RemoveBOM))
+      {
+        ADD(LoadStr(COPY_INFO_REMOVE_BOM),
+          cpaIncludeMaskOnly | cpaNoRemoveBOM | cpaNoTransferMode);
+      }
+    }
+
+    if (RemoveCtrlZ != Defaults.RemoveCtrlZ)
+    {
+      if (ALWAYS_TRUE(RemoveCtrlZ))
+      {
+        ADD(LoadStr(COPY_INFO_REMOVE_CTRLZ),
+          cpaIncludeMaskOnly | cpaNoRemoveCtrlZ | cpaNoTransferMode);
+      }
+    }
+  }
+
   if (!(IncludeFileMask == Defaults.IncludeFileMask))
   {
     ADD(FORMAT(LoadStr(COPY_INFO_FILE_MASK), (IncludeFileMask.Masks)),
@@ -264,6 +287,8 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
   COPY(FileMask);
   COPY(IncludeFileMask);
   COPY(ClearArchive);
+  COPY(RemoveCtrlZ);
+  COPY(RemoveBOM);
   COPY(CPSLimit);
   COPY(NewerOnly);
   #undef COPY
@@ -421,7 +446,7 @@ UnicodeString __fastcall TCopyParamType::GetLogStr() const
   return FORMAT(
     L"  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s (%s); FnCs: %s; RIC: %s; "
        "Resume: %s (%d); CalcS: %s; Mask: %s\n"
-     "  TM: %s; ClAr: %s; CPS: %u; NewerOnly: %s; InclM: %s\n"
+     "  TM: %s; ClAr: %s; RemEOF: %s; RemBOM: %s; CPS: %u; NewerOnly: %s; InclM: %s\n"
      "  AscM: %s\n",
     (BooleanToEngStr(PreserveTime),
      BooleanToEngStr(PreserveReadOnly),
@@ -436,6 +461,8 @@ UnicodeString __fastcall TCopyParamType::GetLogStr() const
      FileMask,
      ModeC[TransferMode],
      BooleanToEngStr(ClearArchive),
+     BooleanToEngStr(RemoveCtrlZ),
+     BooleanToEngStr(RemoveBOM),
      int(CPSLimit),
      BooleanToEngStr(NewerOnly),
      IncludeFileMask.Masks,
@@ -519,6 +546,8 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
     }
   }
   ClearArchive = Storage->ReadBool(L"ClearArchive", ClearArchive);
+  RemoveCtrlZ = Storage->ReadBool(L"RemoveCtrlZ", RemoveCtrlZ);
+  RemoveBOM = Storage->ReadBool(L"RemoveBOM", RemoveBOM);
   CPSLimit = Storage->ReadInteger(L"CPSLimit", CPSLimit);
   NewerOnly = Storage->ReadBool(L"NewerOnly", NewerOnly);
 }
@@ -543,6 +572,8 @@ void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage) const
   Storage->DeleteValue(L"ExcludeFileMask"); // obsolete
   Storage->DeleteValue(L"NegativeExclude"); // obsolete
   Storage->WriteBool(L"ClearArchive", ClearArchive);
+  Storage->WriteBool(L"RemoveCtrlZ", RemoveCtrlZ);
+  Storage->WriteBool(L"RemoveBOM", RemoveBOM);
   Storage->WriteInteger(L"CPSLimit", CPSLimit);
   Storage->WriteBool(L"NewerOnly", NewerOnly);
 }
@@ -567,6 +598,8 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
     C(CalculateSize) &&
     C(IncludeFileMask) &&
     C(ClearArchive) &&
+    C(RemoveCtrlZ) &&
+    C(RemoveBOM) &&
     C(CPSLimit) &&
     C(NewerOnly) &&
     true;

+ 6 - 0
source/core/CopyParam.h

@@ -21,6 +21,8 @@ const int cpaNoRights =        0x20;
 const int cpaNoPreserveReadOnly = 0x40;
 const int cpaNoIgnorePermErrors = 0x80;
 const int cpaNoNewerOnly        = 0x100;
+const int cpaNoRemoveCtrlZ      = 0x200;
+const int cpaNoRemoveBOM        = 0x400;
 //---------------------------------------------------------------------------
 struct TUsableCopyParamAttrs
 {
@@ -51,6 +53,8 @@ private:
   UnicodeString FFileMask;
   TFileMasks FIncludeFileMask;
   bool FClearArchive;
+  bool FRemoveCtrlZ;
+  bool FRemoveBOM;
   unsigned long FCPSLimit;
   bool FNewerOnly;
   static const wchar_t TokenPrefix = L'%';
@@ -110,6 +114,8 @@ public:
   __property UnicodeString FileMask = { read = FFileMask, write = FFileMask };
   __property TFileMasks IncludeFileMask = { read = FIncludeFileMask, write = FIncludeFileMask };
   __property bool ClearArchive = { read = FClearArchive, write = FClearArchive };
+  __property bool RemoveCtrlZ = { read = FRemoveCtrlZ, write = FRemoveCtrlZ };
+  __property bool RemoveBOM = { read = FRemoveBOM, write = FRemoveBOM };
   __property unsigned long CPSLimit = { read = FCPSLimit, write = FCPSLimit };
   __property bool NewerOnly = { read = FNewerOnly, write = FNewerOnly };
 };

+ 3 - 3
source/core/Cryptography.cpp

@@ -613,15 +613,15 @@ int __fastcall IsValidPassword(UnicodeString Password)
     int D = 0;
     for (int Index = 1; Index <= Password.Length(); Index++)
     {
-      if ((Password[Index] >= L'a') && (Password[Index] <= L'z'))
+      if (IsLowerCaseLetter(Password[Index]))
       {
         A = 1;
       }
-      else if ((Password[Index] >= L'A') && (Password[Index] <= L'Z'))
+      else if (IsUpperCaseLetter(Password[Index]))
       {
         B = 1;
       }
-      else if ((Password[Index] >= L'0') && (Password[Index] <= L'9'))
+      else if (IsDigit(Password[Index]))
       {
         C = 1;
       }

+ 22 - 5
source/core/Exceptions.cpp

@@ -16,7 +16,7 @@ static bool __fastcall WellKnownException(
 {
   UnicodeString Message;
   const wchar_t * CounterName;
-  std::auto_ptr<Exception> Clone;
+  std::unique_ptr<Exception> Clone;
 
   bool Result = true;
 
@@ -91,7 +91,7 @@ static bool __fastcall WellKnownException(
 }
 //---------------------------------------------------------------------------
 static bool __fastcall ExceptionMessage(Exception * E, bool Count,
-  UnicodeString & Message, bool & InternalError)
+  bool Formatted, UnicodeString & Message, bool & InternalError)
 {
   bool Result = true;
   const wchar_t * CounterName = NULL;
@@ -115,6 +115,11 @@ static bool __fastcall ExceptionMessage(Exception * E, bool Count,
     Message = E->Message;
   }
 
+  if (!Formatted)
+  {
+    Message = UnformatMessage(Message);
+  }
+
   if (InternalError)
   {
     Message = FMTLOAD(REPORT_ERROR, (Message));
@@ -131,7 +136,19 @@ static bool __fastcall ExceptionMessage(Exception * E, bool Count,
 bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message)
 {
   bool InternalError;
-  return ExceptionMessage(E, true, Message, InternalError);
+  return ExceptionMessage(E, true, false, Message, InternalError);
+}
+//---------------------------------------------------------------------------
+bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message)
+{
+  bool InternalError;
+  return ExceptionMessage(E, true, true, Message, InternalError);
+}
+//---------------------------------------------------------------------------
+bool __fastcall ShouldDisplayException(Exception * E)
+{
+  UnicodeString Message;
+  return ExceptionMessageFormatted(E, Message);
 }
 //---------------------------------------------------------------------------
 TStrings * __fastcall ExceptionToMoreMessages(Exception * E)
@@ -161,7 +178,7 @@ UnicodeString __fastcall GetExceptionHelpKeyword(Exception * E)
   {
     HelpKeyword = ExtE->HelpKeyword;
   }
-  else if ((E != NULL) && ExceptionMessage(E, false, Message, InternalError) &&
+  else if ((E != NULL) && ExceptionMessage(E, false, false, Message, InternalError) &&
            InternalError)
   {
     HelpKeyword = HELP_INTERNAL_ERROR;
@@ -275,7 +292,7 @@ void __fastcall ExtException::AddMoreMessages(Exception* E)
     }
 
     UnicodeString Msg;
-    ExceptionMessage(E, Msg);
+    ExceptionMessageFormatted(E, Msg);
 
     // new exception does not have own message, this is in fact duplication of
     // the exception data, but the exception class may being changed

+ 75 - 19
source/core/Exceptions.h

@@ -7,7 +7,9 @@
 #include <SysInit.hpp>
 #include <System.hpp>
 //---------------------------------------------------------------------------
+bool __fastcall ShouldDisplayException(Exception * E);
 bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message);
+bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message);
 UnicodeString __fastcall LastSysErrorMessage();
 TStrings * __fastcall ExceptionToMoreMessages(Exception * E);
 //---------------------------------------------------------------------------
@@ -26,12 +28,30 @@ public:
   __property TStrings* MoreMessages = {read=FMoreMessages};
   __property UnicodeString HelpKeyword = {read=FHelpKeyword};
 
-  inline __fastcall ExtException(const UnicodeString Msg, const TVarRec * Args, const int Args_Size) : Sysutils::Exception(Msg, Args, Args_Size) { }
-  inline __fastcall ExtException(int Ident, const TVarRec * Args, const int Args_Size)/* overload */ : Sysutils::Exception(Ident, Args, Args_Size) { }
-  inline __fastcall ExtException(const UnicodeString Msg, int AHelpContext) : Sysutils::Exception(Msg, AHelpContext) { }
-  inline __fastcall ExtException(const UnicodeString Msg, const TVarRec * Args, const int Args_Size, int AHelpContext) : Sysutils::Exception(Msg, Args, Args_Size, AHelpContext) { }
-  inline __fastcall ExtException(int Ident, int AHelpContext)/* overload */ : Exception(Ident, AHelpContext) { }
-  inline __fastcall ExtException(PResStringRec ResStringRec, const TVarRec * Args, const int Args_Size, int AHelpContext)/* overload */ : Sysutils::Exception(ResStringRec, Args, Args_Size, AHelpContext) { }
+  inline __fastcall ExtException(const UnicodeString Msg, const TVarRec * Args, const int Args_Size) :
+    Sysutils::Exception(Msg, Args, Args_Size)
+  {
+  }
+  inline __fastcall ExtException(int Ident, const TVarRec * Args, const int Args_Size)/* overload */ :
+    Sysutils::Exception(Ident, Args, Args_Size)
+  {
+  }
+  inline __fastcall ExtException(const UnicodeString Msg, int AHelpContext) :
+    Sysutils::Exception(Msg, AHelpContext)
+  {
+  }
+  inline __fastcall ExtException(const UnicodeString Msg, const TVarRec * Args, const int Args_Size, int AHelpContext) :
+    Sysutils::Exception(Msg, Args, Args_Size, AHelpContext)
+  {
+  }
+  inline __fastcall ExtException(int Ident, int AHelpContext)/* overload */ :
+    Exception(Ident, AHelpContext)
+  {
+  }
+  inline __fastcall ExtException(PResStringRec ResStringRec, const TVarRec * Args, const int Args_Size, int AHelpContext)/* overload */ :
+    Sysutils::Exception(ResStringRec, Args, Args_Size, AHelpContext)
+  {
+  }
 
   virtual ExtException * __fastcall Clone();
 
@@ -47,16 +67,45 @@ private:
   class NAME : public BASE \
   { \
   public: \
-    inline __fastcall NAME(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword = L"") : BASE(E, Msg, HelpKeyword) { } \
-    inline __fastcall NAME(Exception* E, int Ident) : BASE(E, Ident) { } \
-    inline __fastcall virtual ~NAME(void) { } \
-    inline __fastcall NAME(const UnicodeString Msg, const TVarRec * Args, const int Args_Size) : BASE(Msg, Args, Args_Size) { } \
-    inline __fastcall NAME(int Ident, const TVarRec * Args, const int Args_Size) : BASE(Ident, Args, Args_Size) { } \
-    inline __fastcall NAME(const UnicodeString Msg, int AHelpContext) : BASE(Msg, AHelpContext) { } \
-    inline __fastcall NAME(const UnicodeString Msg, const TVarRec * Args, const int Args_Size, int AHelpContext) : BASE(Msg, Args, Args_Size, AHelpContext) { } \
-    inline __fastcall NAME(int Ident, int AHelpContext) : BASE(Ident, AHelpContext) { } \
-    inline __fastcall NAME(PResStringRec ResStringRec, const TVarRec * Args, const int Args_Size, int AHelpContext) : BASE(ResStringRec, Args, Args_Size, AHelpContext) { } \
-    virtual ExtException * __fastcall Clone() { return new NAME(this, L""); } \
+    inline __fastcall NAME(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword = L"") : \
+      BASE(E, Msg, HelpKeyword) \
+    { \
+    } \
+    inline __fastcall NAME(Exception* E, int Ident) : \
+      BASE(E, Ident) \
+    { \
+    } \
+    inline __fastcall virtual ~NAME(void) \
+    { \
+    } \
+    inline __fastcall NAME(const UnicodeString Msg, const TVarRec * Args, const int Args_Size) : \
+      BASE(Msg, Args, Args_Size) \
+    { \
+    } \
+    inline __fastcall NAME(int Ident, const TVarRec * Args, const int Args_Size) : \
+      BASE(Ident, Args, Args_Size) \
+    { \
+    } \
+    inline __fastcall NAME(const UnicodeString Msg, int AHelpContext) : \
+      BASE(Msg, AHelpContext) \
+    { \
+    } \
+    inline __fastcall NAME(const UnicodeString Msg, const TVarRec * Args, const int Args_Size, int AHelpContext) : \
+      BASE(Msg, Args, Args_Size, AHelpContext) \
+    { \
+    } \
+    inline __fastcall NAME(int Ident, int AHelpContext) : \
+      BASE(Ident, AHelpContext) \
+    { \
+    } \
+    inline __fastcall NAME(PResStringRec ResStringRec, const TVarRec * Args, const int Args_Size, int AHelpContext) : \
+      BASE(ResStringRec, Args, Args_Size, AHelpContext) \
+    { \
+    } \
+    virtual ExtException * __fastcall Clone() \
+    { \
+      return new NAME(this, L""); \
+    } \
   };
 //---------------------------------------------------------------------------
 DERIVE_EXT_EXCEPTION(ESsh, ExtException);
@@ -91,8 +140,14 @@ private:
   class NAME : public BASE \
   { \
   public: \
-    inline __fastcall NAME(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword = "") : BASE(E, Msg, HelpKeyword) { } \
-    virtual ExtException * __fastcall Clone() { return new NAME(this, L""); } \
+    inline __fastcall NAME(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword = "") : \
+      BASE(E, Msg, HelpKeyword) \
+    { \
+    } \
+    virtual ExtException * __fastcall Clone() \
+    { \
+      return new NAME(this, L""); \
+    } \
   };
 //---------------------------------------------------------------------------
 DERIVE_FATAL_EXCEPTION(ESshFatal, EFatal);
@@ -105,7 +160,8 @@ public:
   inline __fastcall ESshTerminate(Exception* E, UnicodeString Msg, TOnceDoneOperation AOperation) :
     EFatal(E, Msg),
     Operation(AOperation)
-  { }
+  {
+  }
 
   virtual ExtException * __fastcall Clone();
 

+ 12 - 8
source/core/FileBuffer.cpp

@@ -124,26 +124,30 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params,
 
     for (int Index = 0; Index < Size; Index++)
     {
-      // EOL already in wanted format, make sure to pass unmodified
+      // EOL already in destination format, make sure to pass it unmodified
       if ((Index < Size - 1) && (*Ptr == Dest[0]) && (*(Ptr+1) == Dest[1]))
       {
         Index++;
         Ptr++;
       }
-      // last buffer ended with the first char of wanted EOL format,
-      // which got expanded to wanted format.
+      // last buffer ended with the first char of destination 2-char EOL format,
+      // which got expanded to full destination format.
       // now we got the second char, so get rid of it.
       else if ((Index == 0) && PrevToken && (*Ptr == Dest[1]))
       {
         Delete(Index, 1);
       }
+      // we are ending with the first char of destination 2-char EOL format,
+      // append the second char and make sure we strip it from the next buffer, if any
+      else if ((*Ptr == Dest[0]) && (Index == Size - 1) && Dest[1])
+      {
+        Token = true;
+        Insert(Index+1, Dest+1, 1);
+        Index++;
+        Ptr = Data + Index;
+      }
       else if (*Ptr == Source[0])
       {
-        if ((*Ptr == Dest[0]) && (Index == Size - 1))
-        {
-          Token = true;
-        }
-
         *Ptr = Dest[0];
         if (Dest[1])
         {

+ 12 - 10
source/core/FileMasks.cpp

@@ -392,7 +392,7 @@ bool __fastcall TFileMasks::MatchesMasks(const UnicodeString FileName, bool Dire
   if (!Result && Directory && !IsUnixRootPath(Path) && Recurse)
   {
     UnicodeString ParentFileName = UnixExtractFileName(Path);
-    UnicodeString ParentPath = UnixExcludeTrailingBackslash(UnixExtractFilePath(Path));
+    UnicodeString ParentPath = SimpleUnixExcludeTrailingBackslash(UnixExtractFilePath(Path));
     // Pass Params down or not?
     // Currently it includes Size/Time only, what is not used for directories.
     // So it depends of future use. Possibly we should make a copy
@@ -449,7 +449,7 @@ bool __fastcall TFileMasks::Matches(const UnicodeString FileName, bool Local,
   else
   {
     Result = Matches(UnixExtractFileName(FileName), Directory,
-      UnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)), Params,
+      SimpleUnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)), Params,
       ImplicitMatch);
   }
   return Result;
@@ -638,7 +638,7 @@ void __fastcall TFileMasks::CreateMask(
       {
         // make sure sole "/" (root dir) is preserved as is
         CreateMaskMask(
-          UnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))),
+          SimpleUnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))),
           PartStart, PartStart + D - 1, false,
           Mask.DirectoryMask);
         CreateMaskMask(
@@ -972,7 +972,8 @@ void __fastcall TInteractiveCustomCommand::Execute(
 int __fastcall TInteractiveCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 {
   int Len;
-  switch (Command[Index + 1])
+  wchar_t PatternCmd = (Index < Command.Length()) ? Command[Index + 1] : L'\0';
+  switch (PatternCmd)
   {
     case L'?':
       {
@@ -1055,20 +1056,20 @@ __fastcall TCustomCommandData::TCustomCommandData()
 //---------------------------------------------------------------------------
 __fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal)
 {
-  Init(Terminal->SessionData, Terminal->Password);
+  Init(Terminal->SessionData, Terminal->UserName, Terminal->Password);
 }
 //---------------------------------------------------------------------------
 __fastcall TCustomCommandData::TCustomCommandData(
-  TSessionData * SessionData, const UnicodeString & Password)
+  TSessionData * SessionData, const UnicodeString & UserName, const UnicodeString & Password)
 {
-  Init(SessionData, Password);
+  Init(SessionData, UserName, Password);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomCommandData::Init(
-  TSessionData * SessionData, const UnicodeString & APassword)
+  TSessionData * SessionData, const UnicodeString & AUserName, const UnicodeString & APassword)
 {
   HostName = SessionData->HostNameExpanded;
-  UserName = SessionData->UserNameExpanded;
+  UserName = AUserName;
   Password = APassword;
 }
 //---------------------------------------------------------------------------
@@ -1098,7 +1099,8 @@ TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
 int __fastcall TFileCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 {
   int Len;
-  switch (toupper(Command[Index + 1]))
+  wchar_t PatternCmd = (Index < Command.Length()) ? Command[Index + 1] : L'\0';
+  switch (PatternCmd)
   {
     case L'@':
     case L'U':

+ 6 - 2
source/core/FileMasks.h

@@ -179,14 +179,18 @@ struct TCustomCommandData
 {
   __fastcall TCustomCommandData();
   __fastcall TCustomCommandData(TTerminal * Terminal);
-  __fastcall TCustomCommandData(TSessionData * SessionData, const UnicodeString & Password);
+  __fastcall TCustomCommandData(
+    TSessionData * SessionData, const UnicodeString & AUserName,
+    const UnicodeString & Password);
 
   UnicodeString HostName;
   UnicodeString UserName;
   UnicodeString Password;
 
 private:
-  void __fastcall Init(TSessionData * SessionData, const UnicodeString & Password);
+  void __fastcall Init(
+    TSessionData * SessionData, const UnicodeString & AUserName,
+    const UnicodeString & Password);
 };
 //---------------------------------------------------------------------------
 class TFileCustomCommand : public TCustomCommand

+ 1 - 0
source/core/FileSystems.h

@@ -33,6 +33,7 @@ public:
   virtual void __fastcall Open() = 0;
   virtual void __fastcall Close() = 0;
   virtual bool __fastcall GetActive() = 0;
+  virtual void __fastcall CollectUsage() = 0;
   virtual void __fastcall Idle() = 0;
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local) = 0;
   virtual void __fastcall AnyCommand(const UnicodeString Command,

+ 28 - 3
source/core/FtpFileSystem.cpp

@@ -528,6 +528,29 @@ bool __fastcall TFTPFileSystem::GetActive()
   return FActive;
 }
 //---------------------------------------------------------------------------
+void __fastcall TFTPFileSystem::CollectUsage()
+{
+  if (FFileZillaIntf->UsingMlsd())
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPMLSD");
+  }
+  if (FFileZillaIntf->UsingUtf8())
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPUTF8");
+  }
+  if (!CurrentDirectory.IsEmpty() && (CurrentDirectory[1] != L'/'))
+  {
+    if (IsUnixStyleWindowsPath(CurrentDirectory))
+    {
+      FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPWindowsPath");
+    }
+    else
+    {
+      FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPOtherPath");
+    }
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::Idle()
 {
   if (FActive && !FWaitingForReply)
@@ -579,7 +602,7 @@ void __fastcall TFTPFileSystem::Discard()
 UnicodeString __fastcall TFTPFileSystem::AbsolutePath(UnicodeString Path, bool /*Local*/)
 {
   // TODO: improve (handle .. etc.)
-  if (TTerminal::IsAbsolutePath(Path))
+  if (UnixIsAbsolutePath(Path))
   {
     return Path;
   }
@@ -1749,6 +1772,8 @@ bool __fastcall TFTPFileSystem::IsCapable(int Capability) const
     case fcNativeTextMode:
     case fcTimestampChanging:
     case fcIgnorePermErrors:
+    case fcRemoveCtrlZUpload:
+    case fcRemoveBOMUpload:
       return false;
 
     default:
@@ -1965,7 +1990,7 @@ void __fastcall TFTPFileSystem::ReadFile(const UnicodeString FileName,
     // cache the file list for future
     if ((FFileListCache != NULL) &&
         UnixComparePaths(Path, FFileListCache->Directory) &&
-        (TTerminal::IsAbsolutePath(FFileListCache->Directory) ||
+        (UnixIsAbsolutePath(FFileListCache->Directory) ||
         (FFileListCachePath == CurrentDirectory)))
     {
       AFile = FFileListCache->FindFile(NameOnly);
@@ -3276,7 +3301,7 @@ bool __fastcall TFTPFileSystem::HandleAsynchRequestVerifyCertificate(
       Params.Aliases = Aliases;
       Params.AliasesCount = LENOF(Aliases);
       unsigned int Answer = FTerminal->QueryUser(
-        FMTLOAD(VERIFY_CERT_PROMPT2, (FSessionInfo.Certificate)),
+        FMTLOAD(VERIFY_CERT_PROMPT3, (FSessionInfo.Certificate)),
         NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
 
       switch (Answer)

+ 1 - 0
source/core/FtpFileSystem.h

@@ -29,6 +29,7 @@ public:
   virtual void __fastcall Open();
   virtual void __fastcall Close();
   virtual bool __fastcall GetActive();
+  virtual void __fastcall CollectUsage();
   virtual void __fastcall Idle();
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual void __fastcall AnyCommand(const UnicodeString Command,

+ 1 - 1
source/core/Option.cpp

@@ -42,7 +42,7 @@ void __fastcall TOptions::Add(UnicodeString Value)
           break;
         }
         // this is to treat /home/martin as parameter, not as switch
-        else if ((Value[Index] != L'?') && ((UpCase(Value[Index]) < L'A') || (UpCase(Value[Index]) > L'Z')))
+        else if ((Value[Index] != L'?') && !IsLetter(Value[Index]))
         {
           Switch = false;
           break;

+ 85 - 22
source/core/PuttyIntf.cpp

@@ -9,10 +9,11 @@
 #include "Exceptions.h"
 #include "CoreMain.h"
 #include "TextsCore.h"
+#include <StrUtils.hpp>
 //---------------------------------------------------------------------------
 char sshver[50];
 const int platform_uses_x11_unix_by_default = TRUE;
-CRITICAL_SECTION noise_section;
+CRITICAL_SECTION putty_section;
 bool SaveRandomSeed;
 char appname_[50];
 const char *const appname = appname_;
@@ -30,7 +31,7 @@ void __fastcall PuttyInitialize()
 {
   SaveRandomSeed = true;
 
-  InitializeCriticalSection(&noise_section);
+  InitializeCriticalSection(&putty_section);
 
   // make sure random generator is initialised, so random_save_seed()
   // in destructor can proceed
@@ -58,7 +59,7 @@ void __fastcall PuttyFinalize()
 
   sk_cleanup();
   win_misc_cleanup();
-  DeleteCriticalSection(&noise_section);
+  DeleteCriticalSection(&putty_section);
 }
 //---------------------------------------------------------------------------
 void __fastcall DontSaveRandomSeed()
@@ -123,6 +124,11 @@ int from_backend_untrusted(void * /*frontend*/, const char * /*data*/, int /*len
   return 0;
 }
 //---------------------------------------------------------------------------
+int from_backend_eof(void * /*frontend*/)
+{
+  return FALSE;
+}
+//---------------------------------------------------------------------------
 int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
 {
   assert(p != NULL);
@@ -138,7 +144,8 @@ int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
     {
       prompt_t * Prompt = p->prompts[Index];
       Prompts->AddObject(Prompt->prompt, (TObject *)(FLAGMASK(Prompt->echo, pupEcho)));
-      Results->AddObject(L"", (TObject *)Prompt->result_len);
+      assert(Prompt->resultsize == 0);
+      Results->Add(L"");
     }
 
     if (SecureShell->PromptUser(p->to_server, p->name, p->name_reqd,
@@ -147,8 +154,7 @@ int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
       for (int Index = 0; Index < int(p->n_prompts); Index++)
       {
         prompt_t * Prompt = p->prompts[Index];
-        strncpy(Prompt->result, AnsiString(Results->Strings[Index]).c_str(), Prompt->result_len);
-        Prompt->result[Prompt->result_len - 1] = '\0';
+        prompt_set_result(Prompt, AnsiString(Results->Strings[Index]).c_str());
       }
       Result = 1;
     }
@@ -256,12 +262,20 @@ void modalfatalbox(char * fmt, ...)
   va_end(Param);
 }
 //---------------------------------------------------------------------------
+void nonfatal(char * fmt, ...)
+{
+  va_list Param;
+  va_start(Param, fmt);
+  SSHFatalError(fmt, Param);
+  va_end(Param);
+}
+//---------------------------------------------------------------------------
 void cleanup_exit(int /*code*/)
 {
   throw ESshFatal(NULL, "");
 }
 //---------------------------------------------------------------------------
-int askappend(void * /*frontend*/, Filename /*filename*/,
+int askappend(void * /*frontend*/, Filename * /*filename*/,
   void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
 {
   // this is called from logging.c of putty, which is never used with WinSCP
@@ -295,8 +309,7 @@ void update_specials_menu(void * /*frontend*/)
   // nothing
 }
 //---------------------------------------------------------------------------
-typedef void (*timer_fn_t)(void *ctx, long now);
-long schedule_timer(int ticks, timer_fn_t /*fn*/, void * /*ctx*/)
+unsigned long schedule_timer(int ticks, timer_fn_t /*fn*/, void * /*ctx*/)
 {
   return ticks + GetTickCount();
 }
@@ -306,12 +319,12 @@ void expire_timer_context(void * /*ctx*/)
   // nothing
 }
 //---------------------------------------------------------------------------
-Pinger pinger_new(Config * /*cfg*/, Backend * /*back*/, void * /*backhandle*/)
+Pinger pinger_new(Conf * /*conf*/, Backend * /*back*/, void * /*backhandle*/)
 {
   return NULL;
 }
 //---------------------------------------------------------------------------
-void pinger_reconfig(Pinger /*pinger*/, Config * /*oldcfg*/, Config * /*newcfg*/)
+void pinger_reconfig(Pinger /*pinger*/, Conf * /*oldconf*/, Conf * /*newconf*/)
 {
   // nothing
 }
@@ -326,23 +339,25 @@ void set_busy_status(void * /*frontend*/, int /*status*/)
   // nothing
 }
 //---------------------------------------------------------------------------
-void platform_get_x11_auth(struct X11Display * /*display*/, const Config * /*cfg*/)
+void platform_get_x11_auth(struct X11Display * /*display*/, Conf * /*conf*/)
 {
   // nothing, therefore no auth.
 }
 //---------------------------------------------------------------------------
-int get_remote_username(Config * cfg, char *user, size_t len)
+// Based on PuTTY's settings.c
+char * get_remote_username(Conf * conf)
 {
-  if (*cfg->username)
+  char * username = conf_get_str(conf, CONF_username);
+  char * result;
+  if (*username)
   {
-    strncpy(user, cfg->username, len);
-    user[len-1] = '\0';
+    result = dupstr(username);
   }
   else
   {
-    *user = '\0';
+    result = NULL;
   }
-  return (*user != '\0');
+  return result;
 }
 //---------------------------------------------------------------------------
 static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
@@ -498,16 +513,19 @@ __int64 __fastcall ParseSize(UnicodeString SizeStr)
   return parse_blocksize(AnsiSizeStr.c_str());
 }
 //---------------------------------------------------------------------------
-bool __fastcall HasGSSAPI()
+bool __fastcall HasGSSAPI(UnicodeString CustomPath)
 {
   static int has = -1;
   if (has < 0)
   {
-    Config cfg;
-    memset(&cfg, 0, sizeof(cfg));
-    ssh_gss_liblist * List = ssh_gss_setup(&cfg);
+    Conf * conf = conf_new();
+    ssh_gss_liblist * List = NULL;
     try
     {
+      Filename * filename = filename_from_str(AnsiString(CustomPath).c_str());
+      conf_set_filename(conf, CONF_ssh_gss_custom, filename);
+      filename_free(filename);
+      List = ssh_gss_setup(conf);
       for (int Index = 0; (has <= 0) && (Index < List->nlibraries); Index++)
       {
         ssh_gss_library * library = &List->libraries[Index];
@@ -521,6 +539,7 @@ bool __fastcall HasGSSAPI()
     __finally
     {
       ssh_gss_cleanup(List);
+      conf_free(conf);
     }
 
     if (has < 0)
@@ -531,3 +550,47 @@ bool __fastcall HasGSSAPI()
   return (has > 0);
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall NormalizeFingerprint(UnicodeString Fingerprint)
+{
+  UnicodeString DssName = UnicodeString(ssh_dss.name) + L" ";
+  UnicodeString RsaName = UnicodeString(ssh_rsa.name) + L" ";
+
+  bool IsFingerprint = false;
+  int LenStart;
+  if (StartsStr(DssName, Fingerprint))
+  {
+    LenStart = DssName.Length() + 1;
+    IsFingerprint = true;
+  }
+  else if (StartsStr(RsaName, Fingerprint))
+  {
+    LenStart = RsaName.Length() + 1;
+    IsFingerprint = true;
+  }
+
+  if (IsFingerprint)
+  {
+    Fingerprint[LenStart - 1] = L'-';
+    int Space = Fingerprint.Pos(L" ");
+    assert(IsNumber(Fingerprint.SubString(LenStart, Space - LenStart)));
+    Fingerprint.Delete(LenStart, Space - LenStart + 1);
+    Fingerprint = ReplaceChar(Fingerprint, L':', L'-');
+  }
+  return Fingerprint;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall KeyTypeFromFingerprint(UnicodeString Fingerprint)
+{
+  Fingerprint = NormalizeFingerprint(Fingerprint);
+  UnicodeString Type;
+  if (StartsStr(UnicodeString(ssh_dss.name) + L"-", Fingerprint))
+  {
+    Type = ssh_dss.keytype;
+  }
+  else if (StartsStr(UnicodeString(ssh_rsa.name) + L"-", Fingerprint))
+  {
+    Type = ssh_rsa.keytype;
+  }
+  return Type;
+}
+//---------------------------------------------------------------------------

+ 4 - 1
source/core/PuttyTools.h

@@ -8,9 +8,12 @@ UnicodeString KeyTypeName(TKeyType KeyType);
 //---------------------------------------------------------------------------
 __int64 __fastcall ParseSize(UnicodeString SizeStr);
 //---------------------------------------------------------------------------
-bool __fastcall HasGSSAPI();
+bool __fastcall HasGSSAPI(UnicodeString CustomPath);
 //---------------------------------------------------------------------------
 void __fastcall AES256EncodeWithMAC(char * Data, size_t Len, const char * Password,
   size_t PasswordLen, const char * Salt);
 //---------------------------------------------------------------------------
+UnicodeString __fastcall NormalizeFingerprint(UnicodeString Fingerprint);
+UnicodeString __fastcall KeyTypeFromFingerprint(UnicodeString Fingerprint);
+//---------------------------------------------------------------------------
 #endif

+ 2 - 3
source/core/Queue.cpp

@@ -1225,7 +1225,7 @@ void __fastcall TTerminalItem::ProcessEvent()
   catch(Exception & E)
   {
     UnicodeString Message;
-    if (ExceptionMessage(&E, Message))
+    if (ExceptionMessageFormatted(&E, Message))
     {
       // do not show error messages, if task was cancelled anyway
       // (for example if transfer is cancelled during reconnection attempts)
@@ -1440,9 +1440,8 @@ void __fastcall TTerminalItem::TerminalShowExtendedException(
   USEDPARAM(Arg);
   assert(Arg == NULL);
 
-  UnicodeString Message; // not used
   if ((FItem != NULL) &&
-      ExceptionMessage(E, Message))
+      ShouldDisplayException(E))
   {
     TShowExtendedExceptionAction Action(FQueue->OnShowExtendedException);
     Action.Terminal = Terminal;

+ 33 - 7
source/core/RemoteFiles.cpp

@@ -15,6 +15,19 @@
 #include "HelpCore.h"
 /* TODO 1 : Path class instead of UnicodeString (handle relativity...) */
 //---------------------------------------------------------------------------
+bool __fastcall IsUnixStyleWindowsPath(const UnicodeString & Path)
+{
+  return (Path.Length() >= 3) && IsLetter(Path[1]) && (Path[2] == L':') && (Path[3] == L'/');
+}
+//---------------------------------------------------------------------------
+bool __fastcall UnixIsAbsolutePath(const UnicodeString & Path)
+{
+  return
+    ((Path.Length() >= 1) && (Path[1] == L'/')) ||
+    // we need this for FTP only, but this is unfortunately used in a static context
+    IsUnixStyleWindowsPath(Path);
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall UnixIncludeTrailingBackslash(const UnicodeString Path)
 {
   // it used to return "/" when input path was empty
@@ -29,11 +42,24 @@ UnicodeString __fastcall UnixIncludeTrailingBackslash(const UnicodeString Path)
 }
 //---------------------------------------------------------------------------
 // Keeps "/" for root path
-UnicodeString __fastcall UnixExcludeTrailingBackslash(const UnicodeString Path)
+UnicodeString __fastcall UnixExcludeTrailingBackslash(const UnicodeString Path, bool Simple)
+{
+  if (Path.IsEmpty() ||
+      (Path == L"/") ||
+      !Path.IsDelimiter(L"/", Path.Length()) ||
+      (!Simple && ((Path.Length() == 3) && IsUnixStyleWindowsPath(Path))))
+  {
+    return Path;
+  }
+  else
+  {
+    return Path.SubString(1, Path.Length() - 1);
+  }
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall SimpleUnixExcludeTrailingBackslash(const UnicodeString Path)
 {
-  if ((Path.Length() > 1) && Path.IsDelimiter(L"/", Path.Length()))
-      return Path.SubString(1, Path.Length() - 1);
-    else return Path;
+  return UnixExcludeTrailingBackslash(Path, true);
 }
 //---------------------------------------------------------------------------
 Boolean __fastcall UnixComparePaths(const UnicodeString Path1, const UnicodeString Path2)
@@ -171,6 +197,7 @@ bool __fastcall IsUnixHiddenFile(const UnicodeString FileName)
 //---------------------------------------------------------------------------
 UnicodeString __fastcall AbsolutePath(const UnicodeString & Base, const UnicodeString & Path)
 {
+  // There's a duplicate implementation in TTerminal::ExpandFileName()
   UnicodeString Result;
   if (Path.IsEmpty())
   {
@@ -427,8 +454,7 @@ int __fastcall FakeFileImageIndex(UnicodeString FileName, unsigned long Attrs,
   TSHFileInfoW SHFileInfo;
   // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
   if ((FileName == L"..") ||
-      ((FileName.Length() == 2) && (FileName[2] == L':') &&
-       (towlower(FileName[1]) >= L'a') && (towlower(FileName[1]) <= L'z')) ||
+      ((FileName.Length() == 2) && (FileName[2] == L':') && IsLetter(FileName[1])) ||
       IsReservedName(FileName))
   {
     FileName = L"dumb";
@@ -1865,7 +1891,7 @@ bool __fastcall TRemoteDirectoryChangesCache::DirectoryChangeKey(
   bool Result = !Change.IsEmpty();
   if (Result)
   {
-    bool Absolute = TTerminal::IsAbsolutePath(Change);
+    bool Absolute = UnixIsAbsolutePath(Change);
     Result = !SourceDir.IsEmpty() || Absolute;
     if (Result)
     {

+ 4 - 1
source/core/RemoteFiles.h

@@ -425,8 +425,11 @@ public:
     const TRemoteProperties & OriginalProperties, TRemoteProperties NewProperties);
 };
 //---------------------------------------------------------------------------
+bool __fastcall IsUnixStyleWindowsPath(const UnicodeString & Path);
+bool __fastcall UnixIsAbsolutePath(const UnicodeString & Path);
 UnicodeString __fastcall UnixIncludeTrailingBackslash(const UnicodeString Path);
-UnicodeString __fastcall UnixExcludeTrailingBackslash(const UnicodeString Path);
+UnicodeString __fastcall UnixExcludeTrailingBackslash(const UnicodeString Path, bool Simple = false);
+UnicodeString __fastcall SimpleUnixExcludeTrailingBackslash(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFileDir(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFilePath(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFileName(const UnicodeString Path);

+ 13 - 1
source/core/ScpFileSystem.cpp

@@ -315,6 +315,7 @@ __fastcall TSCPFileSystem::~TSCPFileSystem()
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::Open()
 {
+  // this is used for reconnects only
   FSecureShell->Open();
 }
 //---------------------------------------------------------------------------
@@ -328,6 +329,11 @@ bool __fastcall TSCPFileSystem::GetActive()
   return FSecureShell->Active;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::CollectUsage()
+{
+  FSecureShell->CollectUsage();
+}
+//---------------------------------------------------------------------------
 const TSessionInfo & __fastcall TSCPFileSystem::GetSessionInfo()
 {
   return FSecureShell->GetSessionInfo();
@@ -440,6 +446,8 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
     case fcRename:
     case fcRemoteMove:
     case fcRemoteCopy:
+    case fcRemoveCtrlZUpload:
+    case fcRemoveBOMUpload:
       return true;
 
     case fcTextMode:
@@ -1682,8 +1690,12 @@ void __fastcall TSCPFileSystem::SCPSource(const UnicodeString FileName,
           // Than we add current block to file buffer
           if (OperationProgress->AsciiTransfer)
           {
+            int ConvertParams =
+              FLAGMASK(CopyParam->RemoveCtrlZ, cpRemoveCtrlZ) |
+              FLAGMASK(CopyParam->RemoveBOM, cpRemoveBOM);
             BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-              FTerminal->SessionData->EOLType, cpRemoveCtrlZ | cpRemoveBOM, ConvertToken);
+              FTerminal->SessionData->EOLType,
+              ConvertParams, ConvertToken);
             BlockBuf.Memory->Seek(0, soFromBeginning);
             AsciiBuf.ReadStream(BlockBuf.Memory, BlockBuf.Size, true);
             // We don't need it any more

+ 1 - 0
source/core/ScpFileSystem.h

@@ -18,6 +18,7 @@ public:
   virtual void __fastcall Open();
   virtual void __fastcall Close();
   virtual bool __fastcall GetActive();
+  virtual void __fastcall CollectUsage();
   virtual void __fastcall Idle();
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual void __fastcall AnyCommand(const UnicodeString Command,

+ 2 - 2
source/core/Script.cpp

@@ -2090,7 +2090,7 @@ UnicodeString __fastcall TManagementScript::GetLogCmd(const UnicodeString & Full
   if (SameText(FCommands->ResolveCommand(Command), L"open"))
   {
     UnicodeString AParams = Params;
-    std::auto_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
+    std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
 
     UnicodeString MaskedParams;
     UnicodeString Param;
@@ -2111,7 +2111,7 @@ UnicodeString __fastcall TManagementScript::GetLogCmd(const UnicodeString & Full
       UnicodeString MaskedUrl;
       bool DefaultsOnly;
 
-      std::auto_ptr<TSessionData> Data(
+      std::unique_ptr<TSessionData> Data(
         FStoredSessions->ParseUrl(Session, Parameters.get(), DefaultsOnly, NULL, NULL, &MaskedUrl));
       if (Session != MaskedUrl)
       {

+ 189 - 147
source/core/SecureShell.cpp

@@ -2,13 +2,13 @@
 #include <vcl.h>
 #pragma hdrstop
 
+#include "Common.h"
 #include "PuttyIntf.h"
 #include "Exceptions.h"
 #include "Interface.h"
 #include "SecureShell.h"
 #include "TextsCore.h"
 #include "HelpCore.h"
-#include "Common.h"
 #include "CoreMain.h"
 
 #ifndef AUTO_WINSOCK
@@ -55,8 +55,6 @@ __fastcall TSecureShell::TSecureShell(TSessionUI* UI,
   ResetConnection();
   FOnCaptureOutput = NULL;
   FOnReceive = NULL;
-  FConfig = new Config();
-  memset(FConfig, 0, sizeof(*FConfig));
   FSocket = INVALID_SOCKET;
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FFrozen = false;
@@ -71,9 +69,6 @@ __fastcall TSecureShell::~TSecureShell()
   Active = false;
   ResetConnection();
   CloseHandle(FSocketEvent);
-  ClearConfig(FConfig);
-  delete FConfig;
-  FConfig = NULL;
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::ResetConnection()
@@ -137,32 +132,51 @@ const TSessionInfo & __fastcall TSecureShell::GetSessionInfo()
   return FSessionInfo;
 }
 //---------------------------------------------------------------------
-void __fastcall TSecureShell::ClearConfig(Config * cfg)
-{
-  AnsiStrDispose(cfg->remote_cmd_ptr);
-  AnsiStrDispose(cfg->remote_cmd_ptr2);
-  // clear all
-  memset(cfg, 0, sizeof(*cfg));
-}
-//---------------------------------------------------------------------
-void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg, bool Simple)
-{
-  ClearConfig(cfg);
+Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
+{
+  Conf * conf = conf_new();
+
+  assert((asOn == FORCE_ON) && (asOff == FORCE_OFF) && (asAuto == AUTO));
+
+  #define CONF_ssh_cipherlist_MAX CIPHER_MAX
+  #define CONF_DEF_INT_NONE(KEY) conf_set_int(conf, KEY, 0);
+  #define CONF_DEF_STR_NONE(KEY) conf_set_str(conf, KEY, "");
+  // noop, used only for these and we set the first three explicitly below and latter two are not used in our code
+  #define CONF_DEF_INT_INT(KEY) assert((KEY == CONF_ssh_cipherlist) || (KEY == CONF_ssh_kexlist) || (KEY == CONF_ssh_gsslist) || (KEY == CONF_colours) || (KEY == CONF_wordness));
+  // noop, used only for these three and all thay all can handle undef value
+  #define CONF_DEF_STR_STR(KEY) assert((KEY == CONF_ttymodes) || (KEY == CONF_portfwd) || (KEY == CONF_environmt));
+  // noop, not used in our code
+  #define CONF_DEF_FONT_NONE(KEY) assert((KEY == CONF_font) || (KEY == CONF_boldfont) || (KEY == CONF_widefont) || (KEY == CONF_wideboldfont));
+  #define CONF_DEF_FILENAME_NONE(KEY) \
+    { \
+      Filename * filename = filename_from_str(""); \
+      conf_set_filename(conf, KEY, filename); \
+      filename_free(filename); \
+    }
+  #define CONF_SET_DEFAULT(VALTYPE, KEYTYPE, KEYWORD) CONF_DEF_ ## VALTYPE ## _ ## KEYTYPE(CONF_ ## KEYWORD);
+  CONFIG_OPTIONS(CONF_SET_DEFAULT);
+  #undef CONF_SET_DEFAULT
+  #undef CONF_DEF_FILENAME_NONE
+  #undef CONF_DEF_FONT_NONE
+  #undef CONF_DEF_STR_STR
+  #undef CONF_DEF_INT_INT
+  #undef CONF_DEF_STR_NONE
+  #undef CONF_DEF_INT_NONE
 
   // user-configurable settings
-  ASCOPY(cfg->host, Data->HostNameExpanded);
-  ASCOPY(cfg->username, Data->UserNameExpanded);
-  cfg->port = Data->PortNumber;
-  cfg->protocol = PROT_SSH;
+  conf_set_str(conf, CONF_host, AnsiString(Data->HostNameExpanded).c_str());
+  conf_set_str(conf, CONF_username, AnsiString(Data->UserNameExpanded).c_str());
+  conf_set_int(conf, CONF_port, Data->PortNumber);
+  conf_set_int(conf, CONF_protocol, PROT_SSH);
   // always set 0, as we will handle keepalives ourselves to avoid
   // multi-threaded issues in putty timer list
-  cfg->ping_interval = 0;
-  cfg->compression = Data->Compression;
-  cfg->tryagent = Data->TryAgent;
-  cfg->agentfwd = Data->AgentFwd;
-  cfg->addressfamily = Data->AddressFamily;
-  ASCOPY(cfg->ssh_rekey_data, Data->RekeyData);
-  cfg->ssh_rekey_time = Data->RekeyTime;
+  conf_set_int(conf, CONF_ping_interval, 0);
+  conf_set_int(conf, CONF_compression, Data->Compression);
+  conf_set_int(conf, CONF_tryagent, Data->TryAgent);
+  conf_set_int(conf, CONF_agentfwd, Data->AgentFwd);
+  conf_set_int(conf, CONF_addressfamily, Data->AddressFamily);
+  conf_set_str(conf, CONF_ssh_rekey_data, AnsiString(Data->RekeyData).c_str());
+  conf_set_int(conf, CONF_ssh_rekey_time, Data->RekeyTime);
 
   for (int c = 0; c < CIPHER_COUNT; c++)
   {
@@ -176,7 +190,7 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg, b
       case cipArcfour: pcipher = CIPHER_ARCFOUR; break;
       default: assert(false);
     }
-    cfg->ssh_cipherlist[c] = pcipher;
+    conf_set_int_int(conf, CONF_ssh_cipherlist, c, pcipher);
   }
 
   for (int k = 0; k < KEX_COUNT; k++)
@@ -190,131 +204,135 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg, b
       case kexRSA: pkex = KEX_RSA; break;
       default: assert(false);
     }
-    cfg->ssh_kexlist[k] = pkex;
+    conf_set_int_int(conf, CONF_ssh_kexlist, k, pkex);
   }
 
   UnicodeString SPublicKeyFile = Data->PublicKeyFile;
   if (SPublicKeyFile.IsEmpty()) SPublicKeyFile = Configuration->DefaultKeyFile;
   SPublicKeyFile = StripPathQuotes(ExpandEnvironmentVariables(SPublicKeyFile));
-  ASCOPY(cfg->keyfile.path, SPublicKeyFile);
-  cfg->sshprot = Data->SshProt;
-  cfg->ssh2_des_cbc = Data->Ssh2DES;
-  cfg->ssh_no_userauth = Data->SshNoUserAuth;
-  cfg->try_tis_auth = Data->AuthTIS;
-  cfg->try_ki_auth = Data->AuthKI;
-  cfg->try_gssapi_auth = Data->AuthGSSAPI;
-  cfg->gssapifwd = Data->GSSAPIFwdTGT;
-  cfg->change_username = Data->ChangeUsername;
-
-  cfg->proxy_type = Data->ProxyMethod;
-  ASCOPY(cfg->proxy_host, Data->ProxyHost);
-  cfg->proxy_port = Data->ProxyPort;
-  ASCOPY(cfg->proxy_username, Data->ProxyUsername);
-  ASCOPY(cfg->proxy_password, Data->ProxyPassword);
+  Filename * KeyFileFileName = filename_from_str(AnsiString(SPublicKeyFile).c_str());
+  conf_set_filename(conf, CONF_keyfile, KeyFileFileName);
+  filename_free(KeyFileFileName);
+
+  conf_set_int(conf, CONF_sshprot, Data->SshProt);
+  conf_set_int(conf, CONF_ssh2_des_cbc, Data->Ssh2DES);
+  conf_set_int(conf, CONF_ssh_no_userauth, Data->SshNoUserAuth);
+  conf_set_int(conf, CONF_try_tis_auth, Data->AuthTIS);
+  conf_set_int(conf, CONF_try_ki_auth, Data->AuthKI);
+  conf_set_int(conf, CONF_try_gssapi_auth, Data->AuthGSSAPI);
+  conf_set_int(conf, CONF_gssapifwd, Data->GSSAPIFwdTGT);
+  conf_set_int(conf, CONF_change_username, Data->ChangeUsername);
+
+  conf_set_int(conf, CONF_proxy_type, Data->ProxyMethod);
+  conf_set_str(conf, CONF_proxy_host, AnsiString(Data->ProxyHost).c_str());
+  conf_set_int(conf, CONF_proxy_port, Data->ProxyPort);
+  conf_set_str(conf, CONF_proxy_username, AnsiString(Data->ProxyUsername).c_str());
+  conf_set_str(conf, CONF_proxy_password, AnsiString(Data->ProxyPassword).c_str());
   if (Data->ProxyMethod == pmCmd)
   {
-    ASCOPY(cfg->proxy_telnet_command, Data->ProxyLocalCommand);
+    conf_set_str(conf, CONF_proxy_telnet_command, AnsiString(Data->ProxyLocalCommand).c_str());
   }
   else
   {
-    ASCOPY(cfg->proxy_telnet_command, Data->ProxyTelnetCommand);
-  }
-  cfg->proxy_dns = Data->ProxyDNS;
-  cfg->even_proxy_localhost = Data->ProxyLocalhost;
-
-  #pragma option push -w-eas
-  // after 0.53b values were reversed, however putty still stores
-  // settings to registry in same way as before
-  cfg->sshbug_ignore1 = Data->Bug[sbIgnore1];
-  cfg->sshbug_plainpw1 = Data->Bug[sbPlainPW1];
-  cfg->sshbug_rsa1 = Data->Bug[sbRSA1];
-  cfg->sshbug_hmac2 = Data->Bug[sbHMAC2];
-  cfg->sshbug_derivekey2 = Data->Bug[sbDeriveKey2];
-  cfg->sshbug_rsapad2 = Data->Bug[sbRSAPad2];
-  cfg->sshbug_rekey2 = Data->Bug[sbRekey2];
-  // new after 0.53b
-  cfg->sshbug_pksessid2 = Data->Bug[sbPKSessID2];
-  cfg->sshbug_maxpkt2 = Data->Bug[sbMaxPkt2];
-  cfg->sshbug_ignore2 = Data->Bug[sbIgnore2];
-  #pragma option pop
+    conf_set_str(conf, CONF_proxy_telnet_command, AnsiString(Data->ProxyTelnetCommand).c_str());
+  }
+  conf_set_int(conf, CONF_proxy_dns, Data->ProxyDNS);
+  conf_set_int(conf, CONF_even_proxy_localhost, Data->ProxyLocalhost);
+
+  conf_set_int(conf, CONF_sshbug_ignore1, Data->Bug[sbIgnore1]);
+  conf_set_int(conf, CONF_sshbug_plainpw1, Data->Bug[sbPlainPW1]);
+  conf_set_int(conf, CONF_sshbug_rsa1, Data->Bug[sbRSA1]);
+  conf_set_int(conf, CONF_sshbug_hmac2, Data->Bug[sbHMAC2]);
+  conf_set_int(conf, CONF_sshbug_derivekey2, Data->Bug[sbDeriveKey2]);
+  conf_set_int(conf, CONF_sshbug_rsapad2, Data->Bug[sbRSAPad2]);
+  conf_set_int(conf, CONF_sshbug_rekey2, Data->Bug[sbRekey2]);
+  conf_set_int(conf, CONF_sshbug_pksessid2, Data->Bug[sbPKSessID2]);
+  conf_set_int(conf, CONF_sshbug_maxpkt2, Data->Bug[sbMaxPkt2]);
+  conf_set_int(conf, CONF_sshbug_ignore2, Data->Bug[sbIgnore2]);
+  conf_set_int(conf, CONF_sshbug_winadj, FORCE_OFF);
 
   if (!Data->TunnelPortFwd.IsEmpty())
   {
     assert(!Simple);
-    ASCOPY(cfg->portfwd, Data->TunnelPortFwd);
+    conf_set_str_str(conf, CONF_portfwd, 0, AnsiString(Data->TunnelPortFwd).c_str());
     // when setting up a tunnel, do not open shell/sftp
-    cfg->ssh_no_shell = TRUE;
+    conf_set_int(conf, CONF_ssh_no_shell, TRUE);
   }
   else
   {
     assert(Simple);
-    cfg->ssh_simple = Data->SshSimple && Simple;
+    conf_set_int(conf, CONF_ssh_simple, Data->SshSimple && Simple);
 
     if (Data->FSProtocol == fsSCPonly)
     {
-      cfg->ssh_subsys = FALSE;
+      conf_set_int(conf, CONF_ssh_subsys, FALSE);
       if (Data->Shell.IsEmpty())
       {
         // Following forces Putty to open default shell
         // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
-        cfg->remote_cmd[0] = L'\0';
+        conf_set_str(conf, CONF_remote_cmd, "");
       }
       else
       {
-        cfg->remote_cmd_ptr = AnsiStrNew(Data->Shell.c_str());
+        conf_set_str(conf, CONF_remote_cmd, AnsiString(Data->Shell).c_str());
       }
     }
     else
     {
       if (Data->SftpServer.IsEmpty())
       {
-        cfg->ssh_subsys = TRUE;
-        strcpy(cfg->remote_cmd, "sftp");
+        conf_set_int(conf, CONF_ssh_subsys, TRUE);
+        conf_set_str(conf, CONF_remote_cmd, "sftp");
       }
       else
       {
-        cfg->ssh_subsys = FALSE;
-        cfg->remote_cmd_ptr = AnsiStrNew(Data->SftpServer.c_str());
+        conf_set_int(conf, CONF_ssh_subsys, FALSE);
+        conf_set_str(conf, CONF_remote_cmd, AnsiString(Data->SftpServer).c_str());
       }
 
       if (Data->FSProtocol != fsSFTPonly)
       {
-        cfg->ssh_subsys2 = FALSE;
+        conf_set_int(conf, CONF_ssh_subsys2, FALSE);
         if (Data->Shell.IsEmpty())
         {
           // Following forces Putty to open default shell
           // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
-          cfg->remote_cmd_ptr2 = AnsiStrNew(L"\0");
+          conf_set_str(conf, CONF_remote_cmd2, "");
+          // PuTTY ignores CONF_remote_cmd2 set to "",
+          // so we have to enforce it
+          // (CONF_force_remote_cmd2 is our config option)
+          conf_set_int(conf, CONF_force_remote_cmd2, 1);
         }
         else
         {
-          cfg->remote_cmd_ptr2 = AnsiStrNew(Data->Shell.c_str());
+          conf_set_str(conf, CONF_remote_cmd2, AnsiString(Data->Shell).c_str());
         }
       }
 
       if ((Data->FSProtocol == fsSFTPonly) && Data->SftpServer.IsEmpty())
       {
         // see psftp_connect() from psftp.c
-        cfg->ssh_subsys2 = FALSE;
-        cfg->remote_cmd_ptr2 = AnsiStrNew(
-          L"test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n"
-           "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n"
-           "exec sftp-server");
+        conf_set_int(conf, CONF_ssh_subsys2, FALSE);
+        conf_set_str(conf, CONF_remote_cmd2,
+          "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n"
+          "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n"
+          "exec sftp-server");
       }
     }
   }
 
-  cfg->connect_timeout = Data->Timeout * MSecsPerSec;
-  cfg->sndbuf = Data->SendBuf;
+  conf_set_int(conf, CONF_connect_timeout, Data->Timeout * MSecsPerSec);
+  conf_set_int(conf, CONF_sndbuf, Data->SendBuf);
 
   // permanent settings
-  cfg->nopty = TRUE;
-  cfg->tcp_keepalives = 0;
-  cfg->ssh_show_banner = TRUE;
+  conf_set_int(conf, CONF_nopty, TRUE);
+  conf_set_int(conf, CONF_tcp_keepalives, 0);
+  conf_set_int(conf, CONF_ssh_show_banner, TRUE);
   for (int Index = 0; Index < ngsslibs; Index++)
   {
-    cfg->ssh_gsslist[Index] = gsslibkeywords[Index].v;
+    conf_set_int_int(conf, CONF_ssh_gsslist, Index, gsslibkeywords[Index].v);
   }
+  return conf;
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::Open()
@@ -330,15 +348,23 @@ void __fastcall TSecureShell::Open()
   FAuthenticationLog = L"";
   FNoConnectionResponse = false;
   FUI->Information(LoadStr(STATUS_LOOKUPHOST), true);
-  StoreToConfig(FSessionData, FConfig, Simple);
 
   try
   {
     char * RealHost;
     FreeBackend(); // in case we are reconnecting
-    const char * InitError = FBackend->init(this, &FBackendHandle, FConfig,
-      AnsiString(FSessionData->HostNameExpanded).c_str(), FSessionData->PortNumber, &RealHost, 0,
-      FConfig->tcp_keepalives);
+    const char * InitError;
+    Conf * conf = StoreToConfig(FSessionData, Simple);
+    try
+    {
+      InitError = FBackend->init(this, &FBackendHandle, conf,
+        AnsiString(FSessionData->HostNameExpanded).c_str(), FSessionData->PortNumber, &RealHost, 0,
+        conf_get_int(conf, CONF_tcp_keepalives));
+    }
+    __finally
+    {
+      conf_free(conf);
+    }
     sfree(RealHost);
     if (InitError)
     {
@@ -981,7 +1007,7 @@ unsigned int __fastcall TSecureShell::TimeoutPrompt(TQueryParamsTimerEvent PoolE
       Params.Timeout = FConfiguration->SessionReopenAutoStall;
       Params.TimeoutAnswer = qaAbort;
     }
-    Answer = FUI->QueryUser(FMTLOAD(CONFIRM_PROLONG_TIMEOUT3, (FSessionData->Timeout)),
+    Answer = FUI->QueryUser(MainInstructions(FMTLOAD(CONFIRM_PROLONG_TIMEOUT3, (FSessionData->Timeout))),
       NULL, qaRetry | qaAbort, &Params);
   }
   __finally
@@ -1163,12 +1189,9 @@ int __fastcall TSecureShell::TranslateAuthenticationMessage(
 
   int Result = TranslatePuttyMessage(Translation, LENOF(Translation), Message, HelpKeyword);
 
-  if (FCollectPrivateKeyUsage &&
-      ((Result == 2) || (Result == 3) || (Result == 4)))
+  if ((Result == 2) || (Result == 3) || (Result == 4))
   {
-    Configuration->Usage->Inc(L"OpenedSessionsPrivateKey2");
-    // once only
-    FCollectPrivateKeyUsage = false;
+    FCollectPrivateKeyUsage = true;
   }
 
   return Result;
@@ -1435,6 +1458,8 @@ void inline __fastcall TSecureShell::CheckConnection(int Message)
       HelpKeyword = HELP_NOT_CONNECTED;
     }
 
+    Str = MainInstructions(Str);
+
     int ExitCode = get_ssh_exitcode(FBackendHandle);
     if (ExitCode >= 0)
     {
@@ -1664,7 +1689,12 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
     {
       Handles = sresize(Handles, HandleCount + 1, HANDLE);
       Handles[HandleCount] = FSocketEvent;
-      unsigned int WaitResult = WaitForMultipleObjects(HandleCount + 1, Handles, FALSE, MSec);
+      unsigned int Timeout = MSec;
+      if (toplevel_callback_pending())
+      {
+        Timeout = 0;
+      }
+      unsigned int WaitResult = WaitForMultipleObjects(HandleCount + 1, Handles, FALSE, Timeout);
       if (WaitResult < WAIT_OBJECT_0 + HandleCount)
       {
         if (handle_got_event(Handles[WaitResult - WAIT_OBJECT_0]))
@@ -1727,6 +1757,8 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
       sfree(Handles);
     }
 
+    run_toplevel_callbacks();
+
     unsigned int TicksAfter = GetTickCount();
     // ticks wraps once in 49.7 days
     if (TicksBefore < TicksAfter)
@@ -1889,7 +1921,7 @@ UnicodeString __fastcall TSecureShell::FormatKeyStr(UnicodeString KeyStr)
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::VerifyHostKey(UnicodeString Host, int Port,
-  const UnicodeString KeyType, UnicodeString KeyStr, const UnicodeString Fingerprint)
+  const UnicodeString KeyType, UnicodeString KeyStr, UnicodeString Fingerprint)
 {
   LogEvent(FORMAT(L"Verifying host key %s %s with fingerprint %s", (KeyType, FormatKeyStr(KeyStr), Fingerprint)));
 
@@ -1905,58 +1937,65 @@ void __fastcall TSecureShell::VerifyHostKey(UnicodeString Host, int Port,
   }
 
   FSessionInfo.HostKeyFingerprint = Fingerprint;
+  UnicodeString NormalizedFingerprint = NormalizeFingerprint(Fingerprint);
 
   bool Result = false;
 
-  UnicodeString Buf = FSessionData->HostKey;
-  while (!Result && !Buf.IsEmpty())
-  {
-    UnicodeString ExpectedKey = CutToChar(Buf, Delimiter, false);
-    if (ExpectedKey == L"*")
-    {
-      UnicodeString Message = LoadStr(ANY_HOSTKEY);
-      FUI->Information(Message, true);
-      FLog->Add(llException, Message);
-      Result = true;
-    }
-    else if (ExpectedKey == Fingerprint)
-    {
-      LogEvent(L"Host key matches configured key");
-      Result = true;
-    }
-    else
-    {
-      LogEvent(FORMAT(L"Host key does not match configured key %s", (ExpectedKey)));
+  UnicodeString StoredKeys;
+  AnsiString AnsiStoredKeys;
+  AnsiStoredKeys.SetLength(10240);
+  if (retrieve_host_key(AnsiString(Host).c_str(), Port, AnsiString(KeyType).c_str(),
+        AnsiStoredKeys.c_str(), AnsiStoredKeys.Length()) == 0)
+  {
+    StoredKeys = AnsiStoredKeys.c_str();
+    UnicodeString Buf = StoredKeys;
+    while (!Result && !Buf.IsEmpty())
+    {
+      UnicodeString StoredKey = CutToChar(Buf, Delimiter, false);
+      bool Fingerprint = (StoredKey.SubString(1, 2) != L"0x");
+      // its probably a fingerprint (stored by TSessionData::CacheHostKey)
+      UnicodeString NormalizedExpectedKey;
+      if (Fingerprint)
+      {
+        NormalizedExpectedKey = NormalizeFingerprint(StoredKey);
+      }
+      if ((!Fingerprint && (StoredKey == KeyStr)) ||
+          (Fingerprint && (NormalizedExpectedKey == NormalizedFingerprint)))
+      {
+        LogEvent(L"Host key matches cached key");
+        Result = true;
+      }
+      else
+      {
+        UnicodeString FormattedKey = Fingerprint ? StoredKey : FormatKeyStr(StoredKey);
+        LogEvent(FORMAT(L"Host key does not match cached key %s", (FormattedKey)));
+      }
     }
   }
 
-  UnicodeString StoredKeys;
-  if (!Result)
+  if (!Result && (StoredKeys.IsEmpty() || FSessionData->OverrideCachedHostKey))
   {
-    AnsiString AnsiStoredKeys;
-    AnsiStoredKeys.SetLength(10240);
-    if (retrieve_host_key(AnsiString(Host).c_str(), Port, AnsiString(KeyType).c_str(),
-          AnsiStoredKeys.c_str(), AnsiStoredKeys.Length()) == 0)
+    UnicodeString Buf = FSessionData->HostKey;
+    while (!Result && !Buf.IsEmpty())
     {
-      StoredKeys = AnsiStoredKeys.c_str();
-      UnicodeString Buf = StoredKeys;
-      while (!Result && !Buf.IsEmpty())
+      UnicodeString ExpectedKey = CutToChar(Buf, Delimiter, false);
+      UnicodeString NormalizedExpectedKey = NormalizeFingerprint(ExpectedKey);
+      if (ExpectedKey == L"*")
       {
-        UnicodeString StoredKey = CutToChar(Buf, Delimiter, false);
-        if (StoredKey == KeyStr)
-        {
-          LogEvent(L"Host key matches cached key");
-          Result = true;
-        }
-        else
-        {
-          LogEvent(FORMAT(L"Host key does not match cached key %s", (FormatKeyStr(StoredKey))));
-        }
+        UnicodeString Message = LoadStr(ANY_HOSTKEY);
+        FUI->Information(Message, true);
+        FLog->Add(llException, Message);
+        Result = true;
+      }
+      else if (NormalizedExpectedKey == NormalizedFingerprint)
+      {
+        LogEvent(L"Host key matches configured key");
+        Result = true;
+      }
+      else
+      {
+        LogEvent(FORMAT(L"Host key does not match configured key %s", (ExpectedKey)));
       }
-    }
-    else
-    {
-      StoredKeys = L"";
     }
   }
 
@@ -2002,7 +2041,7 @@ void __fastcall TSecureShell::VerifyHostKey(UnicodeString Host, int Port,
       Params.Aliases = Aliases;
       Params.AliasesCount = AliasesCount;
       unsigned int R = FUI->QueryUser(
-        FMTLOAD((Unknown ? UNKNOWN_KEY2 : DIFFERENT_KEY3), (KeyType, Fingerprint)),
+        FMTLOAD((Unknown ? UNKNOWN_KEY3 : DIFFERENT_KEY4), (KeyType, Fingerprint)),
         NULL, Answers, &Params, qtWarning);
 
       switch (R) {
@@ -2098,7 +2137,10 @@ bool __fastcall TSecureShell::GetReady()
   return FOpened && (FWaiting == 0);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::EnableUsage()
+void __fastcall TSecureShell::CollectUsage()
 {
-  FCollectPrivateKeyUsage = true;
+  if (FCollectPrivateKeyUsage)
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsPrivateKey2");
+  }
 }

+ 4 - 6
source/core/SecureShell.h

@@ -9,7 +9,7 @@
 //---------------------------------------------------------------------------
 #ifndef PuttyIntfH
 struct Backend;
-struct Config;
+struct Conf;
 #endif
 //---------------------------------------------------------------------------
 struct _WSANETWORKEVENTS;
@@ -35,7 +35,6 @@ private:
   Backend * FBackend;
   void * FBackendHandle;
   const unsigned int * FMaxPacketSize;
-  Config * FConfig;
   TNotifyEvent FOnReceive;
   bool FFrozen;
   bool FDataWhileFrozen;
@@ -105,8 +104,7 @@ protected:
   void __fastcall inline LogEvent(const UnicodeString & Str);
   void __fastcall FatalError(UnicodeString Error, UnicodeString HelpKeyword = L"");
   UnicodeString __fastcall FormatKeyStr(UnicodeString KeyStr);
-  static void __fastcall ClearConfig(Config * cfg);
-  static void __fastcall StoreToConfig(TSessionData * Data, Config * cfg, bool Simple);
+  static Conf * __fastcall StoreToConfig(TSessionData * Data, bool Simple);
 
 public:
   __fastcall TSecureShell(TSessionUI * UI, TSessionData * SessionData,
@@ -131,7 +129,7 @@ public:
   unsigned long __fastcall MaxPacketSize();
   void __fastcall ClearStdError();
   bool __fastcall GetStoredCredentialsTried();
-  void __fastcall EnableUsage();
+  void __fastcall CollectUsage();
 
   void __fastcall RegisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall UnregisterReceiveHandler(TNotifyEvent Handler);
@@ -148,7 +146,7 @@ public:
   void __fastcall CWrite(const char * Data, int Length);
   const UnicodeString & __fastcall GetStdError();
   void __fastcall VerifyHostKey(UnicodeString Host, int Port,
-    const UnicodeString KeyType, UnicodeString KeyStr, const UnicodeString Fingerprint);
+    const UnicodeString KeyType, UnicodeString KeyStr, UnicodeString Fingerprint);
   void __fastcall AskAlg(const UnicodeString AlgType, const UnicodeString AlgName);
   void __fastcall DisplayBanner(const UnicodeString & Banner);
   void __fastcall OldKeyfileWarning();

+ 180 - 77
source/core/SessionData.cpp

@@ -41,8 +41,7 @@ const UnicodeString PuttyTelnetProtocol(L"telnet");
 //---------------------------------------------------------------------
 TDateTime __fastcall SecToDateTime(int Sec)
 {
-  return TDateTime((unsigned short)(Sec/SecsPerHour),
-    (unsigned short)(Sec/SecsPerMin%MinsPerHour), (unsigned short)(Sec%SecsPerMin), 0);
+  return TDateTime(double(Sec) / SecsPerDay);
 }
 //--- TSessionData ----------------------------------------------------
 __fastcall TSessionData::TSessionData(UnicodeString aName):
@@ -93,6 +92,7 @@ void __fastcall TSessionData::Default()
   SendBuf = DefaultSendBuf;
   SshSimple = true;
   HostKey = L"";
+  FOverrideCachedHostKey = true;
 
   ProxyMethod = ::pmNone;
   ProxyHost = L"proxy";
@@ -194,6 +194,7 @@ void __fastcall TSessionData::Default()
   Selected = false;
   FModified = false;
   FSource = ::ssNone;
+  FSaveOnly = false;
 
   // add also to TSessionLog::AddStartupInfo()
 }
@@ -214,6 +215,8 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(Ftps); \
   PROPERTY(LocalDirectory); \
   PROPERTY(RemoteDirectory); \
+  PROPERTY(Color); \
+  PROPERTY(SynchronizeBrowsing);
 //---------------------------------------------------------------------
 #define ADVANCED_PROPERTIES \
   PROPERTY(PingInterval); \
@@ -234,7 +237,6 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(RekeyTime); \
   PROPERTY(HostKey); \
   \
-  PROPERTY(SynchronizeBrowsing); \
   PROPERTY(UpdateDirectories); \
   PROPERTY(CacheDirectories); \
   PROPERTY(CacheDirectoryChanges); \
@@ -298,8 +300,6 @@ void __fastcall TSessionData::NonPersistant()
     PROPERTY(SFTPBug[(TSftpBug)Index]); \
   } \
   \
-  PROPERTY(Color); \
-  \
   PROPERTY(Tunnel); \
   PROPERTY(TunnelHostName); \
   PROPERTY(TunnelPortNumber); \
@@ -324,23 +324,28 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(MinTlsVersion); \
   PROPERTY(MaxTlsVersion); \
   \
-  PROPERTY(IsWorkspace); \
-  PROPERTY(Link); \
-  \
   PROPERTY(CustomParam1); \
   PROPERTY(CustomParam2);
+#define META_PROPERTIES \
+  PROPERTY(IsWorkspace); \
+  PROPERTY(Link);
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Assign(TPersistent * Source)
 {
   if (Source && Source->InheritsFrom(__classid(TSessionData)))
   {
-    #define PROPERTY(P) P = ((TSessionData *)Source)->P
+    TSessionData * SourceData = (TSessionData *)Source;
+
+    #define PROPERTY(P) P = SourceData->P
     PROPERTY(Name);
     BASE_PROPERTIES;
     ADVANCED_PROPERTIES;
+    META_PROPERTIES;
     #undef PROPERTY
-    FModified = ((TSessionData *)Source)->Modified;
-    FSource = ((TSessionData *)Source)->FSource;
+    FOverrideCachedHostKey = SourceData->FOverrideCachedHostKey;
+    FModified = SourceData->Modified;
+    FSource = SourceData->FSource;
+    FSaveOnly = SourceData->FSaveOnly;
   }
   else
   {
@@ -348,16 +353,41 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
   }
 }
 //---------------------------------------------------------------------
-bool __fastcall TSessionData::IsSame(const TSessionData * Default, bool AdvancedOnly)
+bool __fastcall TSessionData::IsSame(const TSessionData * Default, bool AdvancedOnly, TStrings * DifferentProperties)
 {
-  #define PROPERTY(P) if (P != Default->P) return false;
+  bool Result = true;
+  #define PROPERTY(P) \
+    if (P != Default->P) \
+    { \
+      if (DifferentProperties != NULL) \
+      { \
+        DifferentProperties->Add(#P); \
+      } \
+      Result = false; \
+    }
+
   if (!AdvancedOnly)
   {
     BASE_PROPERTIES;
+    META_PROPERTIES;
   }
   ADVANCED_PROPERTIES;
   #undef PROPERTY
-  return true;
+  return Result;
+}
+//---------------------------------------------------------------------
+bool __fastcall TSessionData::IsSame(const TSessionData * Default, bool AdvancedOnly)
+{
+  return IsSame(Default, AdvancedOnly, NULL);
+}
+//---------------------------------------------------------------------
+bool __fastcall TSessionData::IsSameSite(const TSessionData * Other)
+{
+  return
+      (FSProtocol == Other->FSProtocol) &&
+      (HostName == Other->HostName) &&
+      (PortNumber == Other->PortNumber) &&
+      (UserName == Other->UserName);
 }
 //---------------------------------------------------------------------
 bool __fastcall TSessionData::IsInFolderOrWorkspace(UnicodeString AFolder)
@@ -367,6 +397,15 @@ bool __fastcall TSessionData::IsInFolderOrWorkspace(UnicodeString AFolder)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & RewritePassword)
 {
+  // In case we are re-loading, reset passwords, to avoid pointless
+  // re-cryption, while loading username/hostname. And moreover, when
+  // the password is wrongly encrypted (using a different master password),
+  // this breaks sites reload and consequently an overal operation,
+  // such as opening Sites menu
+  FPassword = L"";
+  FProxyPassword = L"";
+  FTunnelPassword = L"";
+
   PortNumber = Storage->ReadInteger(L"PortNumber", PortNumber);
   UserName = Storage->ReadString(L"UserName", UserName);
   // must be loaded after UserName, because HostName may be in format user@host
@@ -1132,6 +1171,26 @@ void __fastcall TSessionData::Remove()
   }
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::CacheHostKeyIfNotCached()
+{
+  UnicodeString KeyType = KeyTypeFromFingerprint(HostKey);
+
+  UnicodeString TargetKey = Configuration->RegistryStorageKey + L"\\" + Configuration->SshHostKeysSubKey;
+  std::unique_ptr<TRegistryStorage> Storage(new TRegistryStorage(TargetKey));
+  Storage->AccessMode = smReadWrite;
+  if (Storage->OpenRootKey(true))
+  {
+    UnicodeString HostKeyName = PuttyMungeStr(FORMAT(L"%s@%d:%s", (KeyType, PortNumber, HostName)));
+    if (!Storage->ValueExists(HostKeyName))
+    {
+      // we do not want to implement translating fingerprint to formatted key,
+      // so we store fingerprint and TSecureShell::VerifyHostKey was
+      // modified to accept also fingerprint
+      Storage->WriteString(HostKeyName, HostKey);
+    }
+  }
+}
+//---------------------------------------------------------------------
 inline void __fastcall MoveStr(UnicodeString & Source, UnicodeString * Dest, int Count)
 {
   if (Dest != NULL)
@@ -1312,12 +1371,39 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         Ftps = AFtps;
       }
 
+      UnicodeString UserInfoWithoutConnectionParams = CutToChar(UserInfo, L';', false);
+      UnicodeString ConnectionParams = UserInfo;
+      UserInfo = UserInfoWithoutConnectionParams;
+
+      while (!ConnectionParams.IsEmpty())
+      {
+        UnicodeString ConnectionParam = CutToChar(ConnectionParams, L';', false);
+        UnicodeString ConnectionParamName = CutToChar(ConnectionParam, L'=', false);
+        if (AnsiSameText(ConnectionParamName, L"fingerprint"))
+        {
+          HostKey = ConnectionParam;
+          FOverrideCachedHostKey = false;
+        }
+      }
+
       UnicodeString RawUserName = CutToChar(UserInfo, L':', false);
       UserName = DecodeUrlChars(RawUserName);
 
       Password = DecodeUrlChars(UserInfo);
 
-      ARemoteDirectory = Url.SubString(PSlash, Url.Length() - PSlash + 1);
+      UnicodeString RemoteDirectoryWithSessionParams = Url.SubString(PSlash, Url.Length() - PSlash + 1);
+      ARemoteDirectory = CutToChar(RemoteDirectoryWithSessionParams, L';', false);
+      UnicodeString SessionParams = RemoteDirectoryWithSessionParams;
+
+      while (!SessionParams.IsEmpty())
+      {
+        UnicodeString SessionParam = CutToChar(SessionParams, L';', false);
+        UnicodeString SessionParamName = CutToChar(SessionParam, L'=', false);
+        if (AnsiSameText(SessionParamName, L"save"))
+        {
+          FSaveOnly = (StrToIntDef(SessionParam, 1) != 0);
+        }
+      }
 
       if (MaskedUrl != NULL)
       {
@@ -1373,6 +1459,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         Options->FindSwitch(L"certificate", Value))
     {
       HostKey = Value;
+      FOverrideCachedHostKey = true;
     }
     FtpPasvMode = Options->SwitchValue(L"passive", FtpPasvMode);
     if (Options->FindSwitch(L"implicit"))
@@ -1582,11 +1669,15 @@ void __fastcall TSessionData::SetUnsetNationalVars(bool value)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetUserName(UnicodeString value)
 {
-  // UserName is key for password encryption
-  UnicodeString XPassword = Password;
-  SET_SESSION_PROPERTY(UserName);
-  Password = XPassword;
-  Shred(XPassword);
+  // Avoid password recryption (what may popup master password prompt)
+  if (FUserName != value)
+  {
+    // UserName is key for password encryption
+    UnicodeString XPassword = Password;
+    SET_SESSION_PROPERTY(UserName);
+    Password = XPassword;
+    Shred(XPassword);
+  }
 }
 //---------------------------------------------------------------------
 UnicodeString __fastcall TSessionData::GetUserNameExpanded()
@@ -2241,11 +2332,15 @@ void __fastcall TSessionData::SetTunnelPortNumber(int value)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetTunnelUserName(UnicodeString value)
 {
-  // TunnelUserName is key for password encryption
-  UnicodeString XTunnelPassword = TunnelPassword;
-  SET_SESSION_PROPERTY(TunnelUserName);
-  TunnelPassword = XTunnelPassword;
-  Shred(XTunnelPassword);
+  // Avoid password recryption (what may popup master password prompt)
+  if (FTunnelUserName != value)
+  {
+    // TunnelUserName is key for password encryption
+    UnicodeString XTunnelPassword = TunnelPassword;
+    SET_SESSION_PROPERTY(TunnelUserName);
+    TunnelPassword = XTunnelPassword;
+    Shred(XTunnelPassword);
+  }
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetTunnelPassword(UnicodeString avalue)
@@ -2634,7 +2729,7 @@ void __fastcall TStoredSessionList::ImportLevelFromFilezilla(_di_IXMLNode Node,
     _di_IXMLNode ChildNode = Node->ChildNodes->Get(Index);
     if (ChildNode->NodeName == L"Server")
     {
-      std::auto_ptr<TSessionData> SessionData(new TSessionData(L""));
+      std::unique_ptr<TSessionData> SessionData(new TSessionData(L""));
       SessionData->Assign(DefaultSettings);
       SessionData->ImportFromFilezilla(ChildNode, Path);
       Add(SessionData.release());
@@ -2761,66 +2856,72 @@ void __fastcall TStoredSessionList::UpdateStaticUsage()
   int Color = 0;
   bool Folders = false;
   bool Workspaces = false;
-  std::auto_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
+  std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
+  std::unique_ptr<TStringList> DifferentAdvancedProperties(new TStringList(L""));
+  DifferentAdvancedProperties->Sorted = true;
+  DifferentAdvancedProperties->Duplicates = dupIgnore;
   for (int Index = 0; Index < Count; Index++)
   {
     TSessionData * Data = Sessions[Index];
-    switch (Data->FSProtocol)
+    if (Data->IsWorkspace)
     {
-      case fsSCPonly:
-        SCP++;
-        break;
+      Workspaces = true;
+    }
+    else
+    {
+      switch (Data->FSProtocol)
+      {
+        case fsSCPonly:
+          SCP++;
+          break;
 
-      case fsSFTP:
-      case fsSFTPonly:
-        SFTP++;
-        break;
+        case fsSFTP:
+        case fsSFTPonly:
+          SFTP++;
+          break;
 
-      case fsFTP:
-        if (Data->Ftps == ftpsNone)
-        {
-          FTP++;
-        }
-        else
-        {
-          FTPS++;
-        }
-        break;
+        case fsFTP:
+          if (Data->Ftps == ftpsNone)
+          {
+            FTP++;
+          }
+          else
+          {
+            FTPS++;
+          }
+          break;
 
-      case fsWebDAV:
-        if (Data->Ftps == ftpsNone)
-        {
-          WebDAV++;
-        }
-        else
-        {
-          WebDAVS++;
-        }
-        break;
-    }
+        case fsWebDAV:
+          if (Data->Ftps == ftpsNone)
+          {
+            WebDAV++;
+          }
+          else
+          {
+            WebDAVS++;
+          }
+          break;
+      }
 
-    if (Data->HasAnyPassword())
-    {
-      Password++;
-    }
+      if (Data->HasAnyPassword())
+      {
+        Password++;
+      }
 
-    if (Data->Color != 0)
-    {
-      Color++;
-    }
+      if (Data->Color != 0)
+      {
+        Color++;
+      }
 
-    if (!Data->IsSame(FactoryDefaults.get(), true))
-    {
-      Advanced++;
-    }
+      if (!Data->IsSame(FactoryDefaults.get(), true, DifferentAdvancedProperties.get()))
+      {
+        Advanced++;
+      }
 
-    if (Data->IsWorkspace)
-    {
-      Workspaces = true;
-    }
-    else if (!Data->FolderName.IsEmpty())
-    {
-      Folders = true;
+      if (!Data->FolderName.IsEmpty())
+      {
+        Folders = true;
+      }
     }
   }
 
@@ -2833,6 +2934,8 @@ void __fastcall TStoredSessionList::UpdateStaticUsage()
   Configuration->Usage->Set(L"StoredSessionsCountPassword", Password);
   Configuration->Usage->Set(L"StoredSessionsCountColor", Color);
   Configuration->Usage->Set(L"StoredSessionsCountAdvanced", Advanced);
+  DifferentAdvancedProperties->Delimiter = L',';
+  Configuration->Usage->Set(L"StoredSessionsAdvancedSettings", DifferentAdvancedProperties->DelimitedText);
 
   // actually default might be true, see below for when the default is actually used
   bool CustomDefaultStoredSession = false;
@@ -3034,7 +3137,7 @@ void __fastcall TStoredSessionList::GetFolderOrWorkspace(const UnicodeString & N
 TStrings * __fastcall TStoredSessionList::GetFolderOrWorkspaceList(
   const UnicodeString & Name)
 {
-  std::auto_ptr<TStringList> Result(new TStringList());
+  std::unique_ptr<TStringList> Result(new TStringList());
 
   for (int Index = 0; (Index < Count); Index++)
   {
@@ -3052,7 +3155,7 @@ TStrings * __fastcall TStoredSessionList::GetFolderOrWorkspaceList(
 //---------------------------------------------------------------------------
 TStrings * __fastcall TStoredSessionList::GetWorkspaces()
 {
-  std::auto_ptr<TStringList> Result(new TStringList());
+  std::unique_ptr<TStringList> Result(new TStringList());
   Result->Sorted = true;
   Result->Duplicates = dupIgnore;
   Result->CaseSensitive = false;

+ 7 - 0
source/core/SessionData.h

@@ -164,11 +164,13 @@ private:
   bool FIsWorkspace;
   UnicodeString FLink;
   UnicodeString FHostKey;
+  bool FOverrideCachedHostKey;
 
   UnicodeString FOrigHostName;
   int FOrigPortNumber;
   TProxyMethod FOrigProxyMethod;
   TSessionSource FSource;
+  bool FSaveOnly;
 
   void __fastcall SetHostName(UnicodeString value);
   UnicodeString __fastcall GetHostNameExpanded();
@@ -316,6 +318,7 @@ private:
   void __fastcall DoLoad(THierarchicalStorage * Storage, bool & RewritePassword);
   UnicodeString __fastcall ReadXmlNode(_di_IXMLNode Node, const UnicodeString & Name, const UnicodeString & Default);
   int __fastcall ReadXmlNode(_di_IXMLNode Node, const UnicodeString & Name, int Default);
+  bool __fastcall IsSame(const TSessionData * Default, bool AdvancedOnly, TStrings * DifferentProperties);
   static RawByteString __fastcall EncryptPassword(const UnicodeString & Password, UnicodeString Key);
   static UnicodeString __fastcall DecryptPassword(const RawByteString & Password, UnicodeString Key);
   static RawByteString __fastcall StronglyRecryptPassword(const RawByteString & Password, UnicodeString Key);
@@ -336,6 +339,7 @@ public:
   bool __fastcall HasPassword();
   bool __fastcall HasAnyPassword();
   void __fastcall Remove();
+  void __fastcall CacheHostKeyIfNotCached();
   virtual void __fastcall Assign(TPersistent * Source);
   bool __fastcall ParseUrl(UnicodeString Url, TOptions * Options,
     TStoredSessionList * StoredSessions, bool & DefaultsOnly,
@@ -345,6 +349,7 @@ public:
   void __fastcall RollbackTunnel();
   void __fastcall ExpandEnvironmentVariables();
   bool __fastcall IsSame(const TSessionData * Default, bool AdvancedOnly);
+  bool __fastcall IsSameSite(const TSessionData * Default);
   bool __fastcall IsInFolderOrWorkspace(UnicodeString Name);
   static void __fastcall ValidatePath(const UnicodeString Path);
   static void __fastcall ValidateName(const UnicodeString Name);
@@ -475,12 +480,14 @@ public:
   __property bool IsWorkspace = { read = FIsWorkspace, write = SetIsWorkspace };
   __property UnicodeString Link = { read = FLink, write = SetLink };
   __property UnicodeString HostKey = { read = FHostKey, write = SetHostKey };
+  __property bool OverrideCachedHostKey = { read = FOverrideCachedHostKey };
   __property UnicodeString StorageKey = { read = GetStorageKey };
   __property UnicodeString OrigHostName = { read = FOrigHostName };
   __property int OrigPortNumber = { read = FOrigPortNumber };
   __property UnicodeString LocalName = { read = GetLocalName };
   __property UnicodeString FolderName = { read = GetFolderName };
   __property UnicodeString Source = { read = GetSource };
+  __property bool SaveOnly = { read = FSaveOnly };
 };
 //---------------------------------------------------------------------------
 class TStoredSessionList : public TNamedObjectList

+ 9 - 1
source/core/SessionInfo.cpp

@@ -893,7 +893,8 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
   BeginUpdate();
   try
   {
-    #define ADF(S, F) DoAdd(llMessage, FORMAT(S, F), DoAddToSelf);
+    #define ADSTR(S) DoAdd(llMessage, S, DoAddToSelf);
+    #define ADF(S, F) ADSTR(FORMAT(S, F));
     if (Data == NULL)
     {
       AddSeparator();
@@ -919,6 +920,10 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       ADF(L"Process ID: %d", (int(GetCurrentProcessId())));
       ADF(L"Command-line: %s", (CmdLine));
       ADF(L"Time zone: %s", (GetTimeZoneLogString()));
+      if (!AdjustClockForDSTEnabled())
+      {
+        ADSTR(L"Warning: System option \"Automatically adjust clock for Daylight Saving Time\" is disabled, timestamps will not be represented correctly");
+      }
       ADF(L"Login time: %s", (FormatDateTime(L"dddddd tt", Now())));
       AddSeparator();
     }
@@ -969,6 +974,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
           ADF(L"Local command: %s", (Data->ProxyLocalCommand));
         }
       }
+      ADF(L"Send buffer: %d", (Data->SendBuf));
       wchar_t const * BugFlags = L"+-A";
       if (Data->UsesSsh)
       {
@@ -992,6 +998,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
           Bugs += UnicodeString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?L",":L"");
         }
         ADF(L"SSH Bugs: %s", (Bugs));
+        ADF(L"Simple channel: %s", (BooleanToEngStr(Data->SshSimple)));
         ADF(L"Return code variable: %s; Lookup user groups: %s",
           ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
            BugFlags[Data->LookupUserGroups]));
@@ -1069,6 +1076,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
     }
 
     #undef ADF
+    #undef ADSTR
   }
   __finally
   {

+ 1 - 1
source/core/SessionInfo.h

@@ -36,7 +36,7 @@ enum TFSCapability { fcUserGroupListing, fcModeChanging, fcGroupChanging,
   fcTimestampChanging, fcRemoteMove, fcLoadingAdditionalProperties,
   fcCheckingSpaceAvailable, fcIgnorePermErrors, fcCalculatingChecksum,
   fcModeChangingUpload, fcPreservingTimestampUpload, fcShellAnyCommand,
-  fcSecondaryShell, fcCount };
+  fcSecondaryShell, fcRemoveCtrlZUpload, fcRemoveBOMUpload, fcCount };
 //---------------------------------------------------------------------------
 struct TFileSystemInfo
 {

+ 55 - 23
source/core/SftpFileSystem.cpp

@@ -1372,13 +1372,15 @@ public:
 
   bool __fastcall Init(const UnicodeString AFileName,
     HANDLE AFile, TFileOperationProgressType * AOperationProgress,
-    const RawByteString AHandle, __int64 ATransfered)
+    const RawByteString AHandle, __int64 ATransfered,
+    int ConvertParams)
   {
     FFileName = AFileName;
     FStream = new TSafeHandleStream((THandle)AFile);
     OperationProgress = AOperationProgress;
     FHandle = AHandle;
     FTransfered = ATransfered;
+    FConvertParams = ConvertParams;
 
     return TSFTPAsynchronousQueue::Init();
   }
@@ -1410,7 +1412,7 @@ protected:
         {
           __int64 PrevBufSize = BlockBuf.Size;
           BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-            FFileSystem->GetEOL(), cpRemoveCtrlZ | cpRemoveBOM, FConvertToken);
+            FFileSystem->GetEOL(), FConvertParams, FConvertToken);
           // update transfer size with difference arised from EOL conversion
           OperationProgress->ChangeTransferSize(OperationProgress->TransferSize -
             PrevBufSize + BlockBuf.Size);
@@ -1471,6 +1473,7 @@ private:
   __int64 FTransfered;
   RawByteString FHandle;
   bool FConvertToken;
+  int FConvertParams;
 };
 //---------------------------------------------------------------------------
 class TSFTPLoadFilesPropertiesQueue : public TSFTPFixedLenQueue
@@ -1693,7 +1696,6 @@ __fastcall TSFTPFileSystem::TSFTPFileSystem(TTerminal * ATerminal,
   FBusy = 0;
   FAvoidBusy = false;
   FUtfStrings = false;
-  FUtfNever = false;
   FSignedTS = false;
   FSupport = new TSFTPSupport();
   FExtensions = new TStringList();
@@ -1713,6 +1715,7 @@ __fastcall TSFTPFileSystem::~TSFTPFileSystem()
 //---------------------------------------------------------------------------
 void __fastcall TSFTPFileSystem::Open()
 {
+  // this is used for reconnects only
   FSecureShell->Open();
 }
 //---------------------------------------------------------------------------
@@ -1726,6 +1729,35 @@ bool __fastcall TSFTPFileSystem::GetActive()
   return FSecureShell->Active;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSFTPFileSystem::CollectUsage()
+{
+  FSecureShell->CollectUsage();
+
+  UnicodeString VersionCounter;
+  switch (FVersion)
+  {
+    case 0:
+      VersionCounter = L"OpenedSessionsSFTP0";
+      break;
+    case 1:
+      VersionCounter = L"OpenedSessionsSFTP1";
+      break;
+    case 2:
+      VersionCounter = L"OpenedSessionsSFTP2";
+      break;
+    case 3:
+      VersionCounter = L"OpenedSessionsSFTP3";
+      break;
+    case 4:
+      VersionCounter = L"OpenedSessionsSFTP4";
+      break;
+    case 5:
+      VersionCounter = L"OpenedSessionsSFTP5";
+      break;
+  }
+  FTerminal->Configuration->Usage->Inc(VersionCounter);
+}
+//---------------------------------------------------------------------------
 const TSessionInfo & __fastcall TSFTPFileSystem::GetSessionInfo()
 {
   return FSecureShell->GetSessionInfo();
@@ -1846,6 +1878,8 @@ bool __fastcall TSFTPFileSystem::IsCapable(int Capability) const
     case fcIgnorePermErrors:
     case fcPreservingTimestampUpload:
     case fcSecondaryShell:
+    case fcRemoveCtrlZUpload:
+    case fcRemoveBOMUpload:
       return true;
 
     case fcRename:
@@ -2103,7 +2137,7 @@ unsigned long __fastcall TSFTPFileSystem::GotStatusPacket(TSFTPPacket * Packet,
       // message is in UTF only since SFTP specification 01 (specification 00
       // is also version 3)
       // (in other words, always use UTF unless server is known to be buggy)
-      ServerMessage = Packet->GetString(!FUtfNever);
+      ServerMessage = Packet->GetString(FUtfStrings);
       // SSH-2.0-Maverick_SSHD and SSH-2.0-CIGNA SFTP Server Ready! omit the language tag
       // and I believe I've seen one more server doing the same.
       if (Packet->RemainingLength > 0)
@@ -2440,7 +2474,7 @@ UnicodeString __fastcall TSFTPFileSystem::RealPath(const UnicodeString Path,
 {
   UnicodeString APath;
 
-  if (TTerminal::IsAbsolutePath(Path))
+  if (UnixIsAbsolutePath(Path))
   {
     APath = Path;
   }
@@ -2464,7 +2498,7 @@ UnicodeString __fastcall TSFTPFileSystem::RealPath(const UnicodeString Path,
 UnicodeString __fastcall TSFTPFileSystem::LocalCanonify(const UnicodeString & Path)
 {
   // TODO: improve (handle .. etc.)
-  if (TTerminal::IsAbsolutePath(Path) ||
+  if (UnixIsAbsolutePath(Path) ||
       (!FCurrentDirectory.IsEmpty() && UnixComparePaths(FCurrentDirectory, Path)))
   {
     return Path;
@@ -2809,25 +2843,19 @@ void __fastcall TSFTPFileSystem::DoStartup()
   }
 
   // use UTF when forced or ...
-  // when "auto" and version is at least 4 and the server is not know not to use UTF
-  FUtfNever = (GetSessionInfo().SshImplementation.Pos(L"Foxit-WAC-Server") == 1) ||
-    (FTerminal->SessionData->NotUtf == asOn);
+  // when "auto" and the server is not known not to use UTF
+  bool BuggyUtf = (GetSessionInfo().SshImplementation.Pos(L"Foxit-WAC-Server") == 1);
   FUtfStrings =
     (FTerminal->SessionData->NotUtf == asOff) ||
-    ((FTerminal->SessionData->NotUtf == asAuto) &&
-      (FVersion >= 4) && !FUtfNever);
+    ((FTerminal->SessionData->NotUtf == asAuto) && !BuggyUtf);
 
   if (FUtfStrings)
   {
     FTerminal->LogEvent(L"We will use UTF-8 strings when appropriate");
   }
-  else if (FUtfNever)
-  {
-    FTerminal->LogEvent(L"We will never use UTF-8 strings");
-  }
   else
   {
-    FTerminal->LogEvent(L"We will use UTF-8 strings for status messages only");
+    FTerminal->LogEvent(L"We will never use UTF-8 strings");
   }
 
   FOpenSSH =
@@ -2907,7 +2935,7 @@ void __fastcall TSFTPFileSystem::LookupUsersGroups()
       List.Clear();
       for (unsigned long Item = 0; Item < Count; Item++)
       {
-        TRemoteToken Token(Packet->GetString(!FUtfNever));
+        TRemoteToken Token(Packet->GetString(FUtfStrings));
         List.Add(Token);
         if (&List == &FTerminal->FGroups)
         {
@@ -3787,7 +3815,7 @@ void __fastcall TSFTPFileSystem::SFTPConfirmOverwrite(UnicodeString & FileName,
       TQueryParams Params(0, HELP_APPEND_OR_RESUME);
       SUSPEND_OPERATION
       (
-        Answer = FTerminal->QueryUser(FORMAT(LoadStr(APPEND_OR_RESUME), (FileName)),
+        Answer = FTerminal->QueryUser(FORMAT(LoadStr(APPEND_OR_RESUME2), (FileName)),
           NULL, qaYes | qaNo | qaNoToAll | qaCancel, &Params);
       );
 
@@ -3887,7 +3915,7 @@ bool TSFTPFileSystem::SFTPConfirmResume(const UnicodeString DestFileName,
         HELP_RESUME_TRANSFER);
       // "abort" replaced with "cancel" to unify with "append/resume" query
       Answer = FTerminal->QueryUser(
-        FMTLOAD(RESUME_TRANSFER, (DestFileName)), NULL, qaYes | qaNo | qaCancel,
+        FMTLOAD(RESUME_TRANSFER2, (DestFileName)), NULL, qaYes | qaNo | qaCancel,
         &Params);
     );
 
@@ -4220,9 +4248,13 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
         TSFTPUploadQueue Queue(this);
         try
         {
+          int ConvertParams =
+            FLAGMASK(CopyParam->RemoveCtrlZ, cpRemoveCtrlZ) |
+            FLAGMASK(CopyParam->RemoveBOM, cpRemoveBOM);
           Queue.Init(FileName, File, OperationProgress,
             OpenParams.RemoteFileHandle,
-            DestWriteOffset + OperationProgress->TransferedSize);
+            DestWriteOffset + OperationProgress->TransferedSize,
+            ConvertParams);
 
           while (Queue.Continue())
           {
@@ -4308,7 +4340,7 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
 
       if (SetProperties)
       {
-        std::auto_ptr<TTouchSessionAction> TouchAction;
+        std::unique_ptr<TTouchSessionAction> TouchAction;
         if (CopyParam->PreserveTime)
         {
           TDateTime MDateTime = UnixToDateTime(MTime, FTerminal->SessionData->DSTMode);
@@ -4317,7 +4349,7 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
           TouchAction.reset(new TTouchSessionAction(FTerminal->ActionLog, DestFullName,
             MDateTime));
         }
-        std::auto_ptr<TChmodSessionAction> ChmodAction;
+        std::unique_ptr<TChmodSessionAction> ChmodAction;
         // do record chmod only if it was explicitly requested,
         // not when it was implicitly performed to apply timestamp
         // of overwritten file to new file
@@ -4333,7 +4365,7 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
             SendPacket(&PropertiesRequest);
           }
           bool Resend = false;
-          FILE_OPERATION_LOOP_CUSTOM(FTerminal, true, FMTLOAD(PRESERVE_TIME_PERM_ERROR2, (DestFileName)),
+          FILE_OPERATION_LOOP_CUSTOM(FTerminal, true, FMTLOAD(PRESERVE_TIME_PERM_ERROR3, (DestFileName)),
             try
             {
               TSFTPPacket DummyResponse;

+ 1 - 2
source/core/SftpFileSystem.h

@@ -28,6 +28,7 @@ public:
   virtual void __fastcall Open();
   virtual void __fastcall Close();
   virtual bool __fastcall GetActive();
+  virtual void __fastcall CollectUsage();
   virtual void __fastcall Idle();
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual void __fastcall AnyCommand(const UnicodeString Command,
@@ -98,7 +99,6 @@ protected:
   TStrings * FExtensions;
   TSFTPSupport * FSupport;
   bool FUtfStrings;
-  bool FUtfNever;
   bool FSignedTS;
   bool FOpenSSH;
   TStrings * FFixedPaths;
@@ -112,7 +112,6 @@ protected:
   virtual UnicodeString __fastcall GetCurrentDirectory();
   UnicodeString __fastcall GetHomeDirectory();
   unsigned long __fastcall GotStatusPacket(TSFTPPacket * Packet, int AllowStatus);
-  bool __fastcall inline IsAbsolutePath(const UnicodeString Path);
   bool __fastcall RemoteFileExists(const UnicodeString FullPath, TRemoteFile ** File = NULL);
   TRemoteFile * __fastcall LoadFile(TSFTPPacket * Packet,
     TRemoteFile * ALinkedByFile, const UnicodeString FileName,

+ 120 - 51
source/core/Terminal.cpp

@@ -508,7 +508,6 @@ __fastcall TTerminal::TTerminal(TSessionData * SessionData,
   FTunnelUI = NULL;
   FTunnelOpening = false;
   FCallbackGuard = NULL;
-  FEnableSecureShellUsage = false;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminal::~TTerminal()
@@ -604,16 +603,12 @@ void __fastcall TTerminal::RecryptPasswords()
   FTunnelPassword = EncryptPassword(DecryptPassword(FTunnelPassword));
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::IsAbsolutePath(const UnicodeString Path)
-{
-  return !Path.IsEmpty() && Path[1] == L'/';
-}
-//---------------------------------------------------------------------------
 UnicodeString __fastcall TTerminal::ExpandFileName(UnicodeString Path,
   const UnicodeString BasePath)
 {
+  // replace this by AbsolutePath()
   Path = UnixExcludeTrailingBackslash(Path);
-  if (!IsAbsolutePath(Path) && !BasePath.IsEmpty())
+  if (!UnixIsAbsolutePath(Path) && !BasePath.IsEmpty())
   {
     // TODO: Handle more complicated cases like "../../xxx"
     if (Path == L"..")
@@ -732,14 +727,6 @@ void __fastcall TTerminal::Open()
                 FSecureShell = new TSecureShell(this, FSessionData, Log, Configuration);
                 try
                 {
-                  if (FEnableSecureShellUsage)
-                  {
-                    // only on the first connect,
-                    // this is not ideal as it may prevent usage from being collected,
-                    // e.g. when connection fails on the first try
-                    FSecureShell->EnableUsage();
-                    FEnableSecureShellUsage = false;
-                  }
                   // there will be only one channel in this session
                   FSecureShell->Simple = true;
                   FSecureShell->Open();
@@ -811,6 +798,12 @@ void __fastcall TTerminal::Open()
 
         DoStartup();
 
+        if (FCollectFileSystemUsage)
+        {
+          FFileSystem->CollectUsage();
+          FCollectFileSystemUsage = false;
+        }
+
         DoInformation(LoadStr(STATUS_READY), true);
         FStatus = ssOpened;
       }
@@ -1115,7 +1108,7 @@ unsigned int __fastcall TTerminal::QueryUserException(const UnicodeString Query,
     {
       if (!ExMessage.IsEmpty() && !Query.IsEmpty())
       {
-        MoreMessages->Add(ExMessage);
+        MoreMessages->Add(UnformatMessage(ExMessage));
       }
 
       ExtException * EE = dynamic_cast<ExtException*>(E);
@@ -2824,10 +2817,12 @@ TUsableCopyParamAttrs __fastcall TTerminal::UsableCopyParamAttrs(int Params)
     FLAGMASK(FLAGSET(Params, cpDelete), cpaNoClearArchive) |
     FLAGMASK(!IsCapable[fcIgnorePermErrors], cpaNoIgnorePermErrors);
   Result.Download = Result.General | cpaNoClearArchive | cpaNoRights |
-    cpaNoIgnorePermErrors;
+    cpaNoIgnorePermErrors | cpaNoRemoveCtrlZ | cpaNoRemoveBOM;
   Result.Upload = Result.General | cpaNoPreserveReadOnly |
     FLAGMASK(!IsCapable[fcModeChangingUpload], cpaNoRights) |
-    FLAGMASK(!IsCapable[fcPreservingTimestampUpload], cpaNoPreserveTime);
+    FLAGMASK(!IsCapable[fcPreservingTimestampUpload], cpaNoPreserveTime) |
+    FLAGMASK(!IsCapable[fcRemoveCtrlZUpload], cpaNoRemoveCtrlZ) |
+    FLAGMASK(!IsCapable[fcRemoveBOMUpload], cpaNoRemoveBOM);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -2930,6 +2925,10 @@ bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, int Params)
 void __fastcall TTerminal::DeleteLocalFile(UnicodeString FileName,
   const TRemoteFile * /*File*/, void * Params)
 {
+  if ((OperationProgress != NULL) && (OperationProgress->Operation == foDelete))
+  {
+    OperationProgress->SetFile(FileName);
+  }
   if (OnDeleteLocalFile == NULL)
   {
     if (!RecursiveDeleteFile(FileName, false))
@@ -3174,9 +3173,16 @@ void __fastcall TTerminal::CalculateFileSize(UnicodeString FileName,
     {
       if (!File->IsSymLink)
       {
-        LogEvent(FORMAT(L"Getting size of directory \"%s\"", (FileName)));
-        // pass in full path so we get it back in file list for AllowTransfer() exclusion
-        DoCalculateDirectorySize(File->FullFileName, File, AParams);
+        if (!AParams->AllowDirs)
+        {
+          AParams->Result = false;
+        }
+        else
+        {
+          LogEvent(FORMAT(L"Getting size of directory \"%s\"", (FileName)));
+          // pass in full path so we get it back in file list for AllowTransfer() exclusion
+          DoCalculateDirectorySize(File->FullFileName, File, AParams);
+        }
       }
       else
       {
@@ -3231,17 +3237,20 @@ void __fastcall TTerminal::DoCalculateDirectorySize(const UnicodeString FileName
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::CalculateFilesSize(TStrings * FileList,
+bool __fastcall TTerminal::CalculateFilesSize(TStrings * FileList,
   __int64 & Size, int Params, const TCopyParamType * CopyParam,
-  TCalculateSizeStats * Stats)
+  bool AllowDirs, TCalculateSizeStats * Stats)
 {
   TCalculateSizeParams Param;
   Param.Size = 0;
   Param.Params = Params;
   Param.CopyParam = CopyParam;
   Param.Stats = Stats;
+  Param.AllowDirs = AllowDirs;
+  Param.Result = true;
   ProcessFiles(FileList, foCalculateSize, CalculateFileSize, &Param);
   Size = Param.Size;
+  return Param.Result;
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::CalculateFilesChecksum(const UnicodeString & Alg,
@@ -3282,7 +3291,8 @@ void __fastcall TTerminal::RenameFile(const TRemoteFile * File,
         QuestionFmt = LoadStr(FILE_OVERWRITE);
       }
       TQueryParams Params(qpNeverAskAgainCheck);
-      unsigned int Result = QueryUser(FORMAT(QuestionFmt, (NewName)), NULL,
+      UnicodeString Question = MainInstructions(FORMAT(QuestionFmt, (NewName)));
+      unsigned int Result = QueryUser(Question, NULL,
         qaYes | qaNo, &Params);
       if (Result == qaNeverAskAgain)
       {
@@ -3769,7 +3779,7 @@ bool __fastcall TTerminal::DoCreateLocalFile(const UnicodeString FileName,
             SUSPEND_OPERATION
             (
               Answer = QueryUser(
-                FMTLOAD(READ_ONLY_OVERWRITE, (FileName)), NULL,
+                MainInstructions(FMTLOAD(READ_ONLY_OVERWRITE, (FileName))), NULL,
                 qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll, 0);
             );
             switch (Answer) {
@@ -4017,9 +4027,10 @@ void __fastcall TTerminal::CalculateLocalFileSize(const UnicodeString FileName,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
-  __int64 & Size, const TCopyParamType * CopyParam)
+bool __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
+  __int64 & Size, const TCopyParamType * CopyParam, bool AllowDirs)
 {
+  bool Result = true;
   TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
   TOnceDoneOperation OnceDoneOperation = odoIdle;
   OperationProgress.Start(foCalculateSize, osLocal, FileList->Count);
@@ -4032,14 +4043,21 @@ void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
 
     assert(!FOperationProgress);
     FOperationProgress = &OperationProgress;
-    TSearchRec Rec;
-    for (int Index = 0; Index < FileList->Count; Index++)
+    for (int Index = 0; Result && (Index < FileList->Count); Index++)
     {
       UnicodeString FileName = FileList->Strings[Index];
+      TSearchRec Rec;
       if (FileSearchRec(FileName, Rec))
       {
-        CalculateLocalFileSize(FileName, Rec, &Params);
-        OperationProgress.Finish(FileName, true, OnceDoneOperation);
+        if (FLAGSET(Rec.Attr, faDirectory) && !AllowDirs)
+        {
+          Result = false;
+        }
+        else
+        {
+          CalculateLocalFileSize(FileName, Rec, &Params);
+          OperationProgress.Finish(FileName, true, OnceDoneOperation);
+        }
       }
     }
 
@@ -4055,6 +4073,7 @@ void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
   {
     CloseOnCompletion(OnceDoneOperation);
   }
+  return Result;
 }
 //---------------------------------------------------------------------------
 struct TSynchronizeFileData
@@ -4968,14 +4987,13 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
 
   try
   {
-
     __int64 Size;
-    if (CopyParam->CalculateSize)
-    {
-      // dirty trick: when moving, do not pass copy param to avoid exclude mask
-      CalculateLocalFilesSize(FilesToCopy, Size,
-        (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL));
-    }
+    // dirty trick: when moving, do not pass copy param to avoid exclude mask
+    bool CalculatedSize =
+      CalculateLocalFilesSize(
+        FilesToCopy, Size,
+        (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL),
+        CopyParam->CalculateSize);
 
     TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
@@ -4984,7 +5002,7 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
     FOperationProgress = &OperationProgress;
     try
     {
-      if (CopyParam->CalculateSize)
+      if (CalculatedSize)
       {
         OperationProgress.SetTotalSize(Size);
       }
@@ -5063,20 +5081,21 @@ bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
       bool TotalSizeKnown = false;
       TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
 
-      if (CopyParam->CalculateSize)
+      ExceptionOnFail = true;
+      try
       {
-        ExceptionOnFail = true;
-        try
+        // dirty trick: when moving, do not pass copy param to avoid exclude mask
+        if (CalculateFilesSize(
+             FilesToCopy, TotalSize, csIgnoreErrors,
+             (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL),
+             CopyParam->CalculateSize, NULL))
         {
-          // dirty trick: when moving, do not pass copy param to avoid exclude mask
-          CalculateFilesSize(FilesToCopy, TotalSize, csIgnoreErrors,
-            (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL));
           TotalSizeKnown = true;
         }
-        __finally
-        {
-          ExceptionOnFail = false;
-        }
+      }
+      __finally
+      {
+        ExceptionOnFail = false;
       }
 
       OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
@@ -5152,9 +5171,59 @@ void __fastcall TTerminal::ReflectSettings()
   // also FTunnelLog ?
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::EnableUsage()
+void __fastcall TTerminal::CollectUsage()
 {
-  FEnableSecureShellUsage = true;
+  switch (SessionData->FSProtocol)
+  {
+    case fsSCPonly:
+      Configuration->Usage->Inc(L"OpenedSessionsSCP");
+      break;
+
+    case fsSFTP:
+    case fsSFTPonly:
+      Configuration->Usage->Inc(L"OpenedSessionsSFTP");
+      break;
+
+    case fsFTP:
+      if (SessionData->Ftps == ftpsNone)
+      {
+        Configuration->Usage->Inc(L"OpenedSessionsFTP");
+      }
+      else
+      {
+        Configuration->Usage->Inc(L"OpenedSessionsFTPS");
+      }
+      break;
+
+    case fsWebDAV:
+      if (SessionData->Ftps == ftpsNone)
+      {
+        Configuration->Usage->Inc(L"OpenedSessionsWebDAV");
+      }
+      else
+      {
+        Configuration->Usage->Inc(L"OpenedSessionsWebDAVS");
+      }
+      break;
+  }
+
+  if (Configuration->Logging && Configuration->LogToFile)
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsLogToFile2");
+  }
+
+  if (Configuration->LogActions)
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsXmlLog");
+  }
+
+  std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
+  if (!SessionData->IsSame(FactoryDefaults.get(), true))
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsAdvanced");
+  }
+
+  FCollectFileSystemUsage = true;
 }
 //---------------------------------------------------------------------------
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,

+ 9 - 6
source/core/Terminal.h

@@ -201,6 +201,7 @@ private:
   TCallbackGuard * FCallbackGuard;
   TFindingFileEvent FOnFindingFile;
   bool FEnableSecureShellUsage;
+  bool FCollectFileSystemUsage;
 
   void __fastcall CommandError(Exception * E, const UnicodeString Msg);
   unsigned int __fastcall CommandError(Exception * E, const UnicodeString Msg,
@@ -283,8 +284,8 @@ protected:
     const TRemoteFile * File, TCalculateSizeParams * Params);
   void __fastcall CalculateLocalFileSize(const UnicodeString FileName,
     const TSearchRec Rec, /*__int64*/ void * Size);
-  void __fastcall CalculateLocalFilesSize(TStrings * FileList, __int64 & Size,
-    const TCopyParamType * CopyParam = NULL);
+  bool __fastcall CalculateLocalFilesSize(TStrings * FileList, __int64 & Size,
+    const TCopyParamType * CopyParam, bool AllowDirs);
   TBatchOverwrite __fastcall EffectiveBatchOverwrite(
     const TCopyParamType * CopyParam, int Params,
     TFileOperationProgressType * OperationProgress, bool Special);
@@ -419,8 +420,9 @@ public:
     /*const TMoveFileParams*/ void * Param);
   bool __fastcall CopyFiles(TStrings * FileList, const UnicodeString Target,
     const UnicodeString FileMask);
-  void __fastcall CalculateFilesSize(TStrings * FileList, __int64 & Size,
-    int Params, const TCopyParamType * CopyParam = NULL, TCalculateSizeStats * Stats = NULL);
+  bool __fastcall CalculateFilesSize(TStrings * FileList, __int64 & Size,
+    int Params, const TCopyParamType * CopyParam, bool AllowDirs,
+    TCalculateSizeStats * Stats);
   void __fastcall CalculateFilesChecksum(const UnicodeString & Alg, TStrings * FileList,
     TStrings * Checksums, TCalculatedChecksumEvent OnCalculatedChecksum);
   void __fastcall ClearCaches();
@@ -449,13 +451,12 @@ public:
   UnicodeString __fastcall PeekCurrentDirectory();
   void __fastcall FatalAbort();
   void __fastcall ReflectSettings();
-  void __fastcall EnableUsage();
+  void __fastcall CollectUsage();
 
   const TSessionInfo & __fastcall GetSessionInfo();
   const TFileSystemInfo & __fastcall GetFileSystemInfo(bool Retrieve = false);
   void __fastcall inline LogEvent(const UnicodeString & Str);
 
-  static bool __fastcall IsAbsolutePath(const UnicodeString Path);
   static UnicodeString __fastcall ExpandFileName(UnicodeString Path,
     const UnicodeString BasePath);
 
@@ -568,6 +569,8 @@ struct TCalculateSizeParams
   int Params;
   const TCopyParamType * CopyParam;
   TCalculateSizeStats * Stats;
+  bool AllowDirs;
+  bool Result;
 };
 //---------------------------------------------------------------------------
 struct TOverwriteFileParams

+ 19 - 17
source/core/WebDAVFileSystem.cpp

@@ -3126,7 +3126,7 @@ config_read_auth_data(
   THierarchicalStorage * Storage = NULL;
   WEBDAV_ERR(fs->CreateStorage(Storage));
   assert(Storage);
-  std::auto_ptr<THierarchicalStorage> StoragePtr;
+  std::unique_ptr<THierarchicalStorage> StoragePtr;
   StoragePtr.reset(Storage);
   Storage->AccessMode = smRead;
   if (!Storage->OpenSubKey(UnicodeString(subkey), false))
@@ -3168,7 +3168,7 @@ config_write_auth_data(
   THierarchicalStorage * Storage = NULL;
   WEBDAV_ERR(fs->CreateStorage(Storage));
   assert(Storage);
-  std::auto_ptr<THierarchicalStorage> StoragePtr;
+  std::unique_ptr<THierarchicalStorage> StoragePtr;
   StoragePtr.reset(Storage);
   Storage->AccessMode = smReadWrite;
 
@@ -5366,7 +5366,7 @@ typedef enum path_type_t
 static char
 canonicalize_to_lower(char c)
 {
-  if (c < 'A' || c > 'Z')
+  if (!IsUpperCaseLetter(c))
     return c;
   else
     return c - 'A' + 'a';
@@ -5377,7 +5377,7 @@ canonicalize_to_lower(char c)
 static char
 canonicalize_to_upper(char c)
 {
-  if (c < 'a' || c > 'z')
+  if (!IsLowerCaseLetter(c))
     return c;
   else
     return c - 'a' + 'A';
@@ -5519,8 +5519,7 @@ canonicalize(
     // On Windows the first segment can be a drive letter, which we normalize
     // to upper case.
     else if ((type == type_dirent) &&
-            ((*src >= 'a' && *src <= 'z') ||
-             (*src >= 'A' && *src <= 'Z')) &&
+            IsLetter(*src) &&
             (src[1] == ':'))
     {
       *(dst++) = canonicalize_to_upper(*(src++));
@@ -5565,7 +5564,7 @@ canonicalize(
     // windows drive letter, convert the drive letter to upper case.
     else if (url && (canon_segments == 1) && (seglen == 2) &&
             (strncmp(canon, "file:", 5) == 0) &&
-            (src[0] >= 'a') && (src[0] <= 'z') && (src[1] == ':'))
+            IsLowerCaseLetter(src[0]) && (src[1] == ':'))
     {
       *(dst++) = canonicalize_to_upper(src[0]);
       *(dst++) = ':';
@@ -5798,8 +5797,7 @@ dirent_is_root(
   // are also root directories
   if ((len == 2 || ((len == 3) && (dirent[2] == '/'))) &&
       (dirent[1] == ':') &&
-      ((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
-       (dirent[0] >= 'a' && dirent[0] <= 'z')))
+      IsLetter(dirent[0]))
     return TRUE;
 
   // On Windows and Cygwin //server/share is a root directory,
@@ -5928,8 +5926,7 @@ dirent_canonicalize(
 
   // Handle a specific case on Windows where path == "X:/". Here we have to
   // append the final '/', as path_canonicalize will chop this of.
-  if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
-      (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
+  if (IsLetter(dirent[0]) &&
       (dirent[1] == ':') && (dirent[2] == '/') &&
       (dst[3] == '\0'))
   {
@@ -5963,11 +5960,11 @@ dirent_is_canonical(
       return (strcmp(dirent, dirent_canonicalize(dirent, pool)) == 0);
     }
   }
-  else if (((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) &&
+  else if (IsLetter(*ptr) &&
           (ptr[1] == ':'))
   {
     // The only canonical drive names are "A:"..."Z:", no lower case
-    if (*ptr < 'A' || *ptr > 'Z')
+    if (!IsUpperCaseLetter(*ptr))
       return FALSE;
 
     ptr += 2;
@@ -6052,8 +6049,7 @@ dirent_is_rooted(
 
   // On Windows, dirent is also absolute when it starts with 'H:' or 'H:/'
   // where 'H' is any letter.
-  if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
-      (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
+  if (IsLetter(dirent[0]) &&
       (dirent[1] == ':'))
   {
     return TRUE;
@@ -6180,7 +6176,7 @@ dirent_is_absolute(
   }
   // On Windows, dirent is also absolute when it starts with 'H:/'
   // where 'H' is any letter.
-  if (((dirent[0] >= 'A' && dirent[0] <= 'Z')) &&
+  if (IsUpperCaseLetter(dirent[0]) &&
       (dirent[1] == ':') && (dirent[2] == '/'))
   {
     return TRUE;
@@ -12249,6 +12245,10 @@ bool __fastcall TWebDAVFileSystem::GetActive()
   return FActive;
 }
 //---------------------------------------------------------------------------
+void __fastcall TWebDAVFileSystem::CollectUsage()
+{
+}
+//---------------------------------------------------------------------------
 const TSessionInfo & __fastcall TWebDAVFileSystem::GetSessionInfo()
 {
   return FSessionInfo;
@@ -12317,6 +12317,8 @@ bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
     case fcCalculatingChecksum:
     case fcSecondaryShell: // has fcShellAnyCommand
     case fcGroupOwnerChangingByID: // by name
+    case fcRemoveCtrlZUpload:
+    case fcRemoveBOMUpload:
       return false;
 
     default:
@@ -14089,7 +14091,7 @@ webdav::error_t TWebDAVFileSystem::VerifyCertificate(
   Params.Aliases = Aliases;
   Params.AliasesCount = LENOF(Aliases);
   unsigned int Answer = FTerminal->QueryUser(
-    FMTLOAD(VERIFY_CERT_PROMPT2, (UnicodeString(Prompt).c_str())),
+    FMTLOAD(VERIFY_CERT_PROMPT3, (UnicodeString(Prompt).c_str())),
     NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
   RequestResult = Answer;
   switch (RequestResult)

+ 1 - 0
source/core/WebDAVFileSystem.h

@@ -27,6 +27,7 @@ public:
   virtual void __fastcall Open();
   virtual void __fastcall Close();
   virtual bool __fastcall GetActive();
+  virtual void __fastcall CollectUsage();
   virtual void __fastcall Idle();
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual void __fastcall AnyCommand(const UnicodeString Command,

+ 2 - 2
source/dragext/DragExt.cpp

@@ -293,7 +293,7 @@ bool RegisterServer(bool AllUsers)
   DWORD Unused;
   wchar_t ClassID[CLSID_SIZE];
 
-  StringFromGUID2(CLSID_ShellExtension, ClassID, CLSID_SIZE);
+  StringFromGUID2(CLSID_ShellExtension, ClassID, LENOF(ClassID));
 
   if ((RegOpenKeyEx(RootKey, L"Software\\Classes", 0, KEY_WRITE, &HKey) ==
          ERROR_SUCCESS) &&
@@ -391,7 +391,7 @@ bool UnregisterServer(bool AllUsers)
   bool Result = false;
   wchar_t ClassID[CLSID_SIZE];
 
-  StringFromGUID2(CLSID_ShellExtension, ClassID, CLSID_SIZE);
+  StringFromGUID2(CLSID_ShellExtension, ClassID, LENOF(ClassID));
 
   HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
   HKEY HKey;

+ 8 - 20
source/filezilla/AsyncSocketEx.cpp

@@ -288,11 +288,13 @@ public:
 	//Processes event notifications sent by the sockets or the layers
 	static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 	{
+		//Verify parameters
+		ASSERT(hWnd);
+		if (!hWnd)
+			return 0;
+		CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
 		if (message>=WM_SOCKETEX_NOTIFY)
 		{
-			//Verify parameters
-			ASSERT(hWnd);
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
 			ASSERT(pWnd);
 			
 			if (message<static_cast<UINT>(WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize)) //Index is within socket storage
@@ -499,10 +501,6 @@ public:
 #ifndef NOLAYERS
 		else if (message == WM_USER) //Notification event sent by a layer
 		{
-			//Verify parameters, lookup socket and notification message
-			//Verify parameters
-			ASSERT(hWnd);
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
 			ASSERT(pWnd);
 			
 			if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
@@ -642,6 +640,7 @@ public:
 #endif //NOLAYERS
 		else if (message == WM_USER+1)
 		{
+			ASSERT(pWnd);
 			// WSAAsyncGetHostByName reply
 
 			// Verify parameters
@@ -686,15 +685,7 @@ public:
 		}
 		else if (message == WM_USER + 2)
 		{
-			//Verify parameters, lookup socket and notification message
-			//Verify parameters
-			if (!hWnd)
-				return 0;
-
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
-			if (!pWnd)
-				return 0;
-
+			ASSERT(pWnd);
 			if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
 				return 0;
 			
@@ -709,12 +700,9 @@ public:
 		}
 		else if (message == WM_TIMER)
 		{
+			ASSERT(pWnd);
 			if (wParam != 1)
 				return 0;
-			
-			ASSERT(hWnd);
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
-			ASSERT(pWnd);
 
 			if (pWnd->m_pThreadData->layerCloseNotify.empty())
 			{

+ 73 - 17
source/filezilla/AsyncSslSocketLayer.cpp

@@ -589,9 +589,10 @@ void CAsyncSslSocketLayer::OnReceive(int nErrorCode)
 
 		if (!m_nShutDown && pSSL_get_shutdown(m_ssl))
 		{
-			if (pBIO_ctrl_pending(m_sslbio) <= 0)
+			size_t pending = pBIO_ctrl_pending(m_sslbio);
+			if (pending <= 0)
 			{
-				if (ShutDown() || GetLastError() != WSAEWOULDBLOCK)
+				if (ShutDown() || GetLastError() == WSAEWOULDBLOCK)
 				{
 					if (ShutDownComplete())
 						TriggerEvent(FD_CLOSE, 0, TRUE);
@@ -616,7 +617,9 @@ void CAsyncSslSocketLayer::OnReceive(int nErrorCode)
 		TriggerEvents();
 	}
 	else
+	{
 		TriggerEvent(FD_READ, nErrorCode, TRUE);
+	}
 }
 
 void CAsyncSslSocketLayer::OnSend(int nErrorCode)
@@ -660,7 +663,7 @@ void CAsyncSslSocketLayer::OnSend(int nErrorCode)
 
 		//Send the data waiting in the network bio
 		char buffer[16384];
-		int len = pBIO_ctrl_pending(m_nbio);
+		size_t len = pBIO_ctrl_pending(m_nbio);
 		int numread = pBIO_read(m_nbio, buffer, len);
 		if (numread <= 0)
 			m_mayTriggerWrite = true;
@@ -862,7 +865,8 @@ int CAsyncSslSocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags)
 		}
 		if (m_nNetworkError)
 		{
-			if (pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL) && !m_nShutDown)
+			size_t pending = pBIO_ctrl_pending(m_sslbio);
+			if (pending && !m_nShutDown)
 			{
 				m_mayTriggerReadUp = true;
 				TriggerEvents();
@@ -880,7 +884,8 @@ int CAsyncSslSocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags)
 		{
 			return 0;
 		}
-		if (!pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL))
+		size_t pending = pBIO_ctrl_pending(m_sslbio);
+		if (!pending)
 		{
 			if (GetLayerState() == closed)
 			{
@@ -1077,7 +1082,11 @@ int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode,
 		{
 			USES_CONVERSION;
 			pSSL_CTX_set_verify(m_ssl_ctx, SSL_VERIFY_PEER, verify_callback);
-			pSSL_CTX_load_verify_locations(m_ssl_ctx, T2CA(m_CertStorage), 0);
+			CFileStatus Dummy;
+			if (CFile::GetStatus((LPCTSTR)m_CertStorage, Dummy))
+			{
+				pSSL_CTX_load_verify_locations(m_ssl_ctx, T2CA(m_CertStorage), 0);
+			}
 		}
 	}
 
@@ -1119,6 +1128,9 @@ int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode,
 		MASK_TLS_VERSION(SSL_VERSION_TLS12, SSL_OP_NO_TLSv1_2);
 	pSSL_ctrl(m_ssl, SSL_CTRL_OPTIONS, options, NULL);
 
+	LogSocketMessage(FZ_LOG_INFO, _T("Loading system certificates"));
+	LoadSslWindowsSystemCertificateStore(m_ssl_ctx);
+
 	//Init SSL connection
 	void *ssl_sessionid = NULL;
 	{
@@ -1386,7 +1398,8 @@ BOOL CAsyncSslSocketLayer::ShutDownComplete()
 		numread = pBIO_read(m_sslbio, buffer, 1000);
 	} while (numread > 0);
 
-	if (pBIO_ctrl_pending(m_nbio))
+	size_t pending = pBIO_ctrl_pending(m_nbio);
+	if (pending)
 	{
 		return FALSE;
 	}
@@ -1398,6 +1411,7 @@ BOOL CAsyncSslSocketLayer::ShutDownComplete()
 
 void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int ret)
 {
+	USES_CONVERSION;
 	CAsyncSslSocketLayer *pLayer = 0;
 	m_sCriticalSection.Lock();
 	t_SslLayerList *cur = m_pSslLayerList;
@@ -1494,14 +1508,17 @@ void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int r
 		const char* desc = pSSL_alert_desc_string_long(ret);
 
 		// Don't send close notify warning
-		if (desc && strcmp(desc, "close notify"))
+		if (desc)
 		{
-			char *buffer = new char[4096];
-			sprintf(buffer, "SSL3 alert %s: %s: %s",
-					str,
-					pSSL_alert_type_string_long(ret),
-					desc);
-			pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
+			if (strcmp(desc, "close notify"))
+			{
+				char *buffer = new char[4096];
+				sprintf(buffer, "SSL3 alert %s: %s: %s",
+						str,
+						pSSL_alert_type_string_long(ret),
+						desc);
+				pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
+			}
 		}
 	}
 
@@ -2095,7 +2112,8 @@ void CAsyncSslSocketLayer::OnClose(int nErrorCode)
 	m_onCloseCalled = true;
 	if (m_bUseSSL && pBIO_ctrl)
 	{
-		if (pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL) > 0)
+		size_t pending = pBIO_ctrl_pending(m_sslbio);
+		if (pending > 0)
 		{
 			TriggerEvents();
 		}
@@ -2347,7 +2365,8 @@ int CAsyncSslSocketLayer::SendRaw(const void* lpBuf, int nBufLen, int nFlags)
 
 void CAsyncSslSocketLayer::TriggerEvents()
 {
-	if (pBIO_ctrl_pending(m_nbio) > 0)
+	size_t pending = pBIO_ctrl_pending(m_nbio);
+	if (pending > 0)
 	{
 		if (m_mayTriggerWrite)
 		{
@@ -2374,7 +2393,8 @@ void CAsyncSslSocketLayer::TriggerEvents()
 	}
 	else
 	{
-		if (pBIO_ctrl_get_write_guarantee(m_nbio) > 0 && m_mayTriggerRead)
+		int len = pBIO_ctrl_get_write_guarantee(m_nbio);
+		if (len > 0 && m_mayTriggerRead)
 		{
 			m_mayTriggerRead = false;
 			TriggerEvent(FD_READ, 0);
@@ -2406,3 +2426,39 @@ int CAsyncSslSocketLayer::pem_passwd_cb(char *buf, int size, int rwflag, void *u
 
 	return len;
 }
+//---------------------------------------------------------------------------
+#include <wincrypt.h>
+//---------------------------------------------------------------------------
+// Taken from
+// http://openssl.6102.n7.nabble.com/Get-root-certificates-from-System-Store-of-Windows-td40959.html
+void __fastcall LoadSslWindowsSystemCertificateStore(SSL_CTX * Ctx)
+{
+  HCERTSTORE CertStore = CertStore = CertOpenSystemStore(0, L"ROOT");
+  if (CertStore != NULL)
+  {
+    PCCERT_CONTEXT CertContext = NULL;
+    while ((CertContext = CertEnumCertificatesInStore(CertStore, CertContext)) != NULL)
+    {
+      #ifdef _DEBUG
+      wchar_t Buf[1024];
+      CertNameToStr(X509_ASN_ENCODING, &CertContext->pCertInfo->Subject, CERT_X500_NAME_STR, Buf, LENOF(Buf));
+      Buf[LENOF(Buf) - 1] = L'\0';
+      CertNameToStr(X509_ASN_ENCODING, &CertContext->pCertInfo->Issuer, CERT_X500_NAME_STR, Buf, LENOF(Buf));
+      Buf[LENOF(Buf) - 1] = L'\0';
+      #endif
+      X509 * x509 = d2i_X509(NULL, const_cast<const unsigned char **>(&CertContext->pbCertEncoded), CertContext->cbCertEncoded);
+      if (x509 != NULL)
+      {
+        #ifdef _DEBUG
+        int AddCertResult =
+        #endif
+        X509_STORE_add_cert(Ctx->cert_store, x509);
+        X509_free(x509);
+      }
+    }
+
+    CertFreeCertificateContext(CertContext);
+    CertCloseStore(CertStore, 0);
+  }
+}
+

+ 2 - 0
source/filezilla/AsyncSslSocketLayer.h

@@ -279,4 +279,6 @@ private:
 #define SSL_VERSION_TLS11 11
 #define SSL_VERSION_TLS12 12
 
+void __fastcall LoadSslWindowsSystemCertificateStore(SSL_CTX * Ctx);
+
 #endif // ASYNCSSLSOCKETLEAYER_INCLUDED

+ 1 - 0
source/filezilla/ControlSocket.h

@@ -115,6 +115,7 @@ public:
 
 #ifdef MPEXT
 	virtual bool UsingMlsd() = 0;
+	virtual bool UsingUtf8() = 0;
 	virtual std::string GetTlsVersionStr() = 0;
 	virtual std::string GetCipherName() = 0;
 #endif

+ 10 - 0
source/filezilla/FileZillaApi.cpp

@@ -565,6 +565,16 @@ bool CFileZillaApi::UsingMlsd()
 	return m_pMainThread->UsingMlsd();
 }
 
+bool CFileZillaApi::UsingUtf8()
+{
+	//Check if call allowed
+	if (!m_bInitialized)
+		return false;
+	if (IsConnected()==FZ_REPLY_NOTCONNECTED)
+		return false;
+	return m_pMainThread->UsingUtf8();
+}
+
 std::string CFileZillaApi::GetTlsVersionStr()
 {
 	//Check if call allowed

+ 1 - 0
source/filezilla/FileZillaApi.h

@@ -351,6 +351,7 @@ public:
 	int SetCurrentPath(CServerPath path);
 	int GetCurrentPath(CServerPath & path);
 	bool UsingMlsd();
+	bool UsingUtf8();
 	std::string GetTlsVersionStr();
 	std::string GetCipherName();
 #endif

+ 14 - 11
source/filezilla/FileZillaIntf.cpp

@@ -10,8 +10,6 @@
 #pragma comment(lib, "uafxcwd.lib")
 #endif
 //---------------------------------------------------------------------------
-#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
-//---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
 void __fastcall TFileZillaIntf::Initialize()
@@ -78,7 +76,7 @@ void __fastcall TFileZillaIntf::Destroying()
 bool __fastcall TFileZillaIntf::SetCurrentPath(const wchar_t * APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->SetCurrentPath(Path), L"setcurrentpath");
 }
 //---------------------------------------------------------------------------
@@ -173,7 +171,7 @@ bool __fastcall TFileZillaIntf::CustomCommand(const wchar_t * Command)
 bool __fastcall TFileZillaIntf::MakeDir(const wchar_t* APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->MakeDir(Path), L"makedir");
 }
 //---------------------------------------------------------------------------
@@ -181,21 +179,21 @@ bool __fastcall TFileZillaIntf::Chmod(int Value, const wchar_t* FileName,
   const wchar_t* APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->Chmod(Value, FileName, Path), L"chmod");
 }
 //---------------------------------------------------------------------------
 bool __fastcall TFileZillaIntf::Delete(const wchar_t* FileName, const wchar_t* APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->Delete(FileName, Path), L"delete");
 }
 //---------------------------------------------------------------------------
 bool __fastcall TFileZillaIntf::RemoveDir(const wchar_t* FileName, const wchar_t* APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->RemoveDir(FileName, Path), L"removedir");
 }
 //---------------------------------------------------------------------------
@@ -203,8 +201,8 @@ bool __fastcall TFileZillaIntf::Rename(const wchar_t* OldName,
   const wchar_t* NewName, const wchar_t* APath, const wchar_t* ANewPath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
-  CServerPath NewPath(ANewPath, FServer->nServerType);
+  CServerPath Path(APath);
+  CServerPath NewPath(ANewPath);
   return Check(FFileZillaApi->Rename(OldName, NewName, Path, NewPath), L"rename");
 }
 //---------------------------------------------------------------------------
@@ -217,7 +215,7 @@ bool __fastcall TFileZillaIntf::List()
 bool __fastcall TFileZillaIntf::List(const wchar_t * APath)
 {
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->List(Path), L"list");
 }
 //---------------------------------------------------------------------------
@@ -240,7 +238,7 @@ bool __fastcall TFileZillaIntf::FileTransfer(const wchar_t * LocalFile,
 
   Transfer.localfile = LocalFile;
   Transfer.remotefile = RemoteFile;
-  Transfer.remotepath = CServerPath(RemotePath, FServer->nServerType);
+  Transfer.remotepath = CServerPath(RemotePath);
   Transfer.get = Get;
   Transfer.size = Size;
   Transfer.server = *FServer;
@@ -524,6 +522,11 @@ bool __fastcall TFileZillaIntf::UsingMlsd()
   return FFileZillaApi->UsingMlsd();
 }
 //---------------------------------------------------------------------------
+bool __fastcall TFileZillaIntf::UsingUtf8()
+{
+  return FFileZillaApi->UsingUtf8();
+}
+//---------------------------------------------------------------------------
 std::string __fastcall TFileZillaIntf::GetTlsVersionStr()
 {
   return FFileZillaApi->GetTlsVersionStr();

+ 1 - 0
source/filezilla/FileZillaIntf.h

@@ -159,6 +159,7 @@ public:
   bool __fastcall GetCurrentPath(wchar_t * Path, size_t MaxLen);
 
   bool __fastcall UsingMlsd();
+  bool __fastcall UsingUtf8();
   std::string __fastcall GetTlsVersionStr();
   std::string __fastcall GetCipherName();
 

+ 8 - 4
source/filezilla/FtpControlSocket.cpp

@@ -37,7 +37,6 @@
 #include "filezillaapi.h"
 #include "misc/utf8.h"
 #ifdef MPEXT
-#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
 #endif
 
 #ifdef _DEBUG
@@ -300,10 +299,10 @@ bool CFtpControlSocket::InitConnect()
 		{
 			filename = filename.Left(pos + 1);
 			filename += _T("cacert.pem");
-			m_pSslLayer->SetCertStorage(filename);
 		}
 		else
 			filename = _MPT("cacert.pem");
+		m_pSslLayer->SetCertStorage(filename);
 	}
 #endif
 
@@ -1523,6 +1522,11 @@ bool CFtpControlSocket::UsingMlsd()
 		 (m_serverCapabilities.GetCapability(mlsd_command) == yes));
 }
 
+bool CFtpControlSocket::UsingUtf8()
+{
+	return m_bUTF8;
+}
+
 std::string CFtpControlSocket::GetTlsVersionStr()
 {
 	if (m_pSslLayer != NULL)
@@ -6304,8 +6308,8 @@ bool CFtpControlSocket::CheckForcePasvIp(CString & host)
 		default: // auto
 			if (!GetPeerName(ahost, tmpPort))
 			{
-			    // this is not failure in "auto" mode
-				LogMessage(__FILE__, __LINE__, this, FZ_LOG_WARNING, _T("Error retrieving server address, cannot test if address is routable"));
+				// this is not failure in "auto" mode
+				LogMessage(__FILE__, __LINE__, this, FZ_LOG_INFO, _T("Error retrieving server address, cannot test if address is routable"));
 			}
 			else if (!IsRoutableAddress(host) && IsRoutableAddress(ahost))
 			{

+ 1 - 0
source/filezilla/FtpControlSocket.h

@@ -88,6 +88,7 @@ public:
 
 #ifdef MPEXT
 	virtual bool UsingMlsd();
+	virtual bool UsingUtf8();
 	virtual std::string GetTlsVersionStr();
 	virtual std::string GetCipherName();
 #endif

+ 1 - 1
source/filezilla/FtpListResult.cpp

@@ -1405,7 +1405,7 @@ BOOL CFtpListResult::parseAsMlsd(const char *line, const int linelen, t_director
 
 	CString fileName;
 	copyStr(fileName, 0, str, tokenlen, true);
-	CServerPath path(fileName, m_server.nServerType);
+	CServerPath path(fileName);
 	direntry.name = path.GetLastSegment();
 	if (direntry.name.IsEmpty())
 	{

+ 7 - 0
source/filezilla/MainThread.cpp

@@ -418,6 +418,13 @@ bool CMainThread::UsingMlsd()
 	return m_pControlSocket->UsingMlsd();
 }
 
+bool CMainThread::UsingUtf8()
+{
+	if (!IsConnected())
+		return false;
+	return m_pControlSocket->UsingUtf8();
+}
+
 std::string CMainThread::GetTlsVersionStr()
 {
 	if (!IsConnected())

+ 1 - 0
source/filezilla/MainThread.h

@@ -69,6 +69,7 @@ public:
 	int GetOption(int nOption);
 #else
 	bool UsingMlsd();
+	bool UsingUtf8();
 	std::string GetTlsVersionStr();
 	std::string GetCipherName();
 #endif

+ 13 - 1
source/filezilla/TransferSocket.cpp

@@ -463,7 +463,19 @@ void CTransferSocket::OnConnect(int nErrorCode)
 			SetSockOpt(SO_SNDBUF, &value, sizeof(value));
 		}
 	}
-	if (m_nTransferState == STATE_STARTING)
+	if (m_nTransferState == STATE_WAITING)
+	{
+		// OnReceive (invoked by m_nNotifyWaiting including FD_READ)
+		// will call back to OnConnected (as we won't be connected yet).
+		// This is needed for file transfers only, where SetActive is
+		// called only after 1xx response to RETR (and similar) arrives.
+		// But we get FD_CONNECT earlier, hence we get to thisa branch.
+		// With directory listing, SetActive is called before Connect,
+		// so we are already STATE_STARTING on FD_CONNECT.
+		// It should probably behave the same in both scenarios.
+		m_nNotifyWaiting |= FD_READ;
+	}
+	else if (m_nTransferState == STATE_STARTING)
 	{
 		m_nTransferState = STATE_STARTED;
 		

+ 2 - 0
source/filezilla/stdafx.h

@@ -19,6 +19,8 @@
 #define GetOption(OPTION) GetInstanceOption(this->m_pApiLogParent, OPTION)
 #define GetOptionVal(OPTION) GetInstanceOptionVal(this->m_pApiLogParent, OPTION)
 //---------------------------------------------------------------------------
+#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
+//---------------------------------------------------------------------------
 #include <afx.h>
 #include "wtypes.h"
 #include <afxmt.h>

+ 4 - 7
source/forms/Authenticate.cpp

@@ -161,7 +161,7 @@ TLabel * __fastcall TAuthenticateForm::GenerateLabel(int Current, UnicodeString
   return Result;
 }
 //---------------------------------------------------------------------------
-TCustomEdit * __fastcall TAuthenticateForm::GenerateEdit(int Current, bool Echo, int MaxLen)
+TCustomEdit * __fastcall TAuthenticateForm::GenerateEdit(int Current, bool Echo)
 {
   TCustomEdit * Result = (Echo ? static_cast<TCustomEdit *>(new TEdit(this)) :
     static_cast<TCustomEdit *>(new TPasswordEdit(this)));
@@ -171,13 +171,12 @@ TCustomEdit * __fastcall TAuthenticateForm::GenerateEdit(int Current, bool Echo,
   Result->Top = Current;
   Result->Left = FPromptLeft;
   Result->Width = FPromptParent->ClientWidth - FPromptLeft - FPromptRight;
-  ((TEdit *)Result)->MaxLength = MaxLen;
 
   return Result;
 }
 //---------------------------------------------------------------------------
 TList * __fastcall TAuthenticateForm::GeneratePrompt(UnicodeString Instructions,
-  TStrings * Prompts, TStrings * Results)
+  TStrings * Prompts)
 {
   while (FPromptParent->ControlCount > 0)
   {
@@ -193,7 +192,6 @@ TList * __fastcall TAuthenticateForm::GeneratePrompt(UnicodeString Instructions,
     Current += Label->Height + FPromptsGap;
   }
 
-  assert(Prompts->Count == Results->Count);
   for (int Index = 0; Index < Prompts->Count; Index++)
   {
     if (Index > 0)
@@ -205,8 +203,7 @@ TList * __fastcall TAuthenticateForm::GeneratePrompt(UnicodeString Instructions,
     Current += Label->Height + FPromptEditGap;
 
     bool Echo = FLAGSET(int(Prompts->Objects[Index]), pupEcho);
-    TCustomEdit * Edit = GenerateEdit(Current, Echo,
-      int(Results->Objects[Index]));
+    TCustomEdit * Edit = GenerateEdit(Current, Echo);
     Result->Add(Edit);
     Label->FocusControl = Edit;
     Current += Edit->Height;
@@ -223,7 +220,7 @@ bool __fastcall TAuthenticateForm::PromptUser(TPromptKind Kind, UnicodeString Na
 {
 
   bool Result;
-  TList * Edits = GeneratePrompt(Instructions, Prompts, Results);
+  TList * Edits = GeneratePrompt(Instructions, Prompts);
 
   try
   {

+ 2 - 3
source/forms/Authenticate.h

@@ -65,9 +65,8 @@ protected:
   virtual void __fastcall Dispatch(void * AMessage);
   void __fastcall WMNCCreate(TWMNCCreate & Message);
   TLabel * __fastcall GenerateLabel(int Current, UnicodeString Caption);
-  TCustomEdit * __fastcall GenerateEdit(int Current, bool Echo, int MaxLen);
-  TList * __fastcall GeneratePrompt(UnicodeString Instructions, TStrings * Prompts,
-    TStrings * Results);
+  TCustomEdit * __fastcall GenerateEdit(int Current, bool Echo);
+  TList * __fastcall GeneratePrompt(UnicodeString Instructions, TStrings * Prompts);
   void __fastcall DoCancel();
   void __fastcall AdjustLogView();
 

+ 39 - 9
source/forms/Console.dfm

@@ -9,7 +9,7 @@ object ConsoleDialog: TConsoleDialog
   ClientWidth = 551
   Color = clBtnFace
   Constraints.MinHeight = 250
-  Constraints.MinWidth = 380
+  Constraints.MinWidth = 420
   ParentFont = True
   Icon.Data = {
     0000010001001010000001002000680400001600000028000000100000002000
@@ -64,7 +64,7 @@ object ConsoleDialog: TConsoleDialog
     Shape = bsBottomLine
   end
   object Label1: TLabel
-    Left = 13
+    Left = 51
     Top = 13
     Width = 78
     Height = 13
@@ -72,25 +72,25 @@ object ConsoleDialog: TConsoleDialog
     FocusControl = CommandEdit
   end
   object Label2: TLabel
-    Left = 13
+    Left = 51
     Top = 56
     Width = 87
     Height = 13
     Caption = 'Current directory:'
   end
   object Label4: TLabel
-    Left = 13
+    Left = 51
     Top = 34
-    Width = 452
+    Width = 414
     Height = 13
     Anchors = [akLeft, akTop, akRight]
     AutoSize = False
     Caption = 'Do not execute commands that require user-input or data transfer'
   end
   object DirectoryLabel: TPathLabel
-    Left = 120
+    Left = 158
     Top = 56
-    Width = 337
+    Width = 299
     Height = 13
     IndentHorizontal = 0
     IndentVertical = 0
@@ -98,6 +98,36 @@ object ConsoleDialog: TConsoleDialog
     Anchors = [akLeft, akTop, akRight]
     AutoSize = False
   end
+  object Image: TImage
+    Left = 13
+    Top = 16
+    Width = 32
+    Height = 32
+    AutoSize = True
+    Picture.Data = {
+      0954506E67496D61676589504E470D0A1A0A0000000D49484452000000200000
+      00200806000000737A7AF4000000097048597300000EC300000EC301C76FA864
+      000002644944415478DA63641860C038EA0010C1635670074829D3D9EEBB5F4E
+      4D508139E07F77470B5D6D2FADA861003A8011EE80B0F43ABA3A60D5CC265407
+      98F815D0D50167364D4075808A55385D1D70E7D84A840344B53DFEABA8EBD2D7
+      01372F33BCBEBA03E2001945F5FFC6361E7475C0D9233B189EDCBF89708081A5
+      0B5D1D70E1F81E5407E8993AD0D501974E1F407580B6912D5D1D70F5DC615407
+      68E85BD2D501372E1E477580AA8E295D1D70FBCA695407286B1AD2D50177AF9F
+      477580822AA41C28C84A623031D463983E7709C3D1136768E68007B72FA33A40
+      5649132C51579ECFE0E1EA0066EFDE7798A17FEA1C860F1F3F51DD018FEF5D47
+      7580B4BC1A588209281412E8C3909516C7C0C1CECEF0F9CB5786095366336CDD
+      B98FAA0E78FAF016AA03246494501448494A3054146733589A1983F927CF9C67
+      68EB9ECCF0ECF90BAA38E0C5937BA80E109594C3AAD0D7D395A1A6BC90819595
+      85E1EDDB770CAE7E115471C0EBE78F501D20242A85A148455991A1BEAA98414F
+      470BCCDFB47527436D5327551CF0EEF5335407080889C12559595919D2926219
+      9213A2C1EC57AF5E03837F22C3DEFD87A86239087C78F70AD501BCFC4260091D
+      2D0D86D6C61A06551525867FFFFE31AC59B789A167C254862F5FBF52CD7210F8
+      FCF11DAA03B878F8C012AB97CD0706B936C3FD070F196A1A5A19CE9CBB40558B
+      61E0DB974FA80E60E7E4024B98991A3368AAAB31AC58BD96E1E7CF5F34B11C04
+      7E7EFF86EA005656769A59860DFCFEFD13D5014C4CCC7475C0BF7F7F511CF01A
+      4889D0D5050C0C6F800E10053B40445D9D97F7172B173D6DFFCCF6FBDB9B9B37
+      3F0F8EBEE140020069430B30B1046F080000000049454E44AE426082}
+  end
   object OutputMemo: TMemo
     Left = 0
     Top = 78
@@ -125,9 +155,9 @@ object ConsoleDialog: TConsoleDialog
     TabOrder = 2
   end
   object CommandEdit: THistoryComboBox
-    Left = 120
+    Left = 158
     Top = 9
-    Width = 251
+    Width = 213
     Height = 21
     AutoComplete = False
     Anchors = [akLeft, akTop, akRight]

+ 2 - 0
source/forms/Console.h

@@ -16,6 +16,7 @@
 #include "WinInterface.h"
 #include <Terminal.h>
 #include "PngImageList.hpp"
+#include <Vcl.Imaging.pngimage.hpp>
 //----------------------------------------------------------------------------
 class TConsoleDialog : public TForm
 {
@@ -40,6 +41,7 @@ __published:
   TEditCopy *EditCopy;
   TEditSelectAll *EditSelectAll;
   TAction *AdjustWindow;
+  TImage *Image;
   void __fastcall ExecuteButtonClick(TObject *Sender);
   void __fastcall CommandEditChange(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);

+ 1 - 1
source/forms/Copy.cpp

@@ -398,7 +398,7 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
       UnicodeString Drive = ExtractFileDrive(Dir);
       if (!DirectoryExists(Dir))
       {
-        if (MessageDialog(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Dir)),
+        if (MessageDialog(MainInstructions(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Dir))),
               qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel)
         {
           if (!ForceDirectories(Dir))

+ 10 - 0
source/forms/CopyParams.cpp

@@ -85,6 +85,8 @@ void __fastcall TCopyParamsFrame::SetParams(TCopyParamType value)
 
   IncludeFileMaskCombo->Text = value.IncludeFileMask.Masks;
   ClearArchiveCheck->Checked = value.ClearArchive;
+  assert(value.RemoveCtrlZ == value.RemoveBOM);
+  RemoveCtrlZAndBOMCheck->Checked = value.RemoveCtrlZ && value.RemoveBOM;
 
   SpeedCombo->Text = SetSpeedLimit(value.CPSLimit);
 
@@ -129,6 +131,8 @@ TCopyParamType __fastcall TCopyParamsFrame::GetParams()
   Result.IncludeFileMask.Masks = IncludeFileMaskCombo->Text;
 
   Result.ClearArchive = ClearArchiveCheck->Checked;
+  Result.RemoveCtrlZ = RemoveCtrlZAndBOMCheck->Checked;
+  Result.RemoveBOM = RemoveCtrlZAndBOMCheck->Checked;
 
   Result.CPSLimit = GetSpeedLimit(SpeedCombo->Text);
 
@@ -163,6 +167,12 @@ void __fastcall TCopyParamsFrame::UpdateControls()
   EnableControl(IncludeFileMaskLabel, IncludeFileMaskCombo->Enabled);
   EnableControl(ClearArchiveCheck, FLAGCLEAR(CopyParamAttrs, cpaNoClearArchive) &&
     FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) && Enabled);
+  assert(FLAGCLEAR(CopyParamAttrs, cpaNoRemoveCtrlZ) == FLAGCLEAR(CopyParamAttrs, cpaNoRemoveBOM));
+  EnableControl(RemoveCtrlZAndBOMCheck,
+    (FLAGCLEAR(CopyParamAttrs, cpaNoRemoveCtrlZ) || FLAGCLEAR(CopyParamAttrs, cpaNoRemoveBOM)) &&
+    FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) &&
+    (TMTextButton->Checked || TMAutomaticButton->Checked) &&
+    Enabled);
   EnableControl(PreserveTimeCheck, FLAGCLEAR(CopyParamAttrs, cpaNoPreserveTime) &&
     FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) && Enabled);
   EnableControl(ChangeCaseGroup, FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) && Enabled);

+ 11 - 2
source/forms/CopyParams.dfm

@@ -125,7 +125,7 @@ object CopyParamsFrame: TCopyParamsFrame
     end
     object IgnorePermErrorsCheck: TCheckBox
       Left = 16
-      Top = 73
+      Top = 72
       Width = 173
       Height = 17
       Caption = 'Ign&ore permission errors'
@@ -136,12 +136,21 @@ object CopyParamsFrame: TCopyParamsFrame
     end
     object ClearArchiveCheck: TCheckBox
       Left = 16
-      Top = 100
+      Top = 98
       Width = 173
       Height = 17
       Caption = 'Clear '#39'Archi&ve'#39' attribute'
       TabOrder = 3
     end
+    object RemoveCtrlZAndBOMCheck: TCheckBox
+      Left = 16
+      Top = 124
+      Width = 173
+      Height = 17
+      Caption = 'Remove BOM and &EOF marks'
+      TabOrder = 4
+      OnClick = ControlChange
+    end
   end
   object ChangeCaseGroup: TGroupBox
     Left = 267

+ 1 - 0
source/forms/CopyParams.h

@@ -48,6 +48,7 @@ __published:
   THistoryComboBox *SpeedCombo;
   TButton *IncludeFileMaskButton;
   TCheckBox *NewerOnlyCheck;
+  TCheckBox *RemoveCtrlZAndBOMCheck;
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall ValidateMaskComboExit(TObject *Sender);
   void __fastcall RightsEditButtonClick(TObject *Sender);

+ 40 - 13
source/forms/Custom.cpp

@@ -12,6 +12,8 @@
 #include <HelpWin.h>
 #include <CoreMain.h>
 #include <PasTools.hpp>
+#include <ProgParams.h>
+#include <Tools.h>
 
 #include "Custom.h"
 //---------------------------------------------------------------------
@@ -189,9 +191,11 @@ void __fastcall TCustomDialog::AddButtonControl(TButtonControl * Control)
 class TSaveSessionDialog : public TCustomDialog
 {
 public:
-  __fastcall TSaveSessionDialog(bool CanSavePassword, bool NotRecommendedSavingPassword);
+  __fastcall TSaveSessionDialog(TComponent* AOwner);
+  void __fastcall Init(bool CanSavePassword, bool NotRecommendedSavingPassword);
 
-  bool __fastcall Execute(UnicodeString & SessionName, bool & SavePassword);
+  bool __fastcall Execute(UnicodeString & SessionName, bool & SavePassword,
+    bool & CreateShortcut, const UnicodeString & OriginalSessionName);
 
 protected:
   virtual void __fastcall DoValidate();
@@ -202,14 +206,19 @@ private:
   TEdit * SessionNameEdit;
   TComboBox * FolderCombo;
   TCheckBox * SavePasswordCheck;
+  TCheckBox * CreateShortcutCheck;
   UnicodeString FRootFolder;
 
   UnicodeString __fastcall GetSessionName();
 };
 //---------------------------------------------------------------------------
-__fastcall TSaveSessionDialog::TSaveSessionDialog(
-    bool CanSavePassword, bool NotRecommendedSavingPassword) :
+// Need to have an Owner argument for SafeFormCreate
+__fastcall TSaveSessionDialog::TSaveSessionDialog(TComponent* /*AOwner*/) :
   TCustomDialog(HELP_SESSION_SAVE)
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TSaveSessionDialog::Init(bool CanSavePassword, bool NotRecommendedSavingPassword)
 {
   Caption = LoadStr(SAVE_SESSION_CAPTION);
 
@@ -248,12 +257,18 @@ __fastcall TSaveSessionDialog::TSaveSessionDialog(
       (CustomWinConfiguration->UseMasterPassword ? SAVE_SESSION_PASSWORD_MASTER : SAVE_SESSION_PASSWORD_RECOMMENDED));
   AddButtonControl(SavePasswordCheck);
 
+  CreateShortcutCheck = new TCheckBox(this);
+  CreateShortcutCheck->Caption = LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT);
+  AddButtonControl(CreateShortcutCheck);
+
   EnableControl(SavePasswordCheck, CanSavePassword);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSaveSessionDialog::Execute(UnicodeString & SessionName, bool & SavePassword)
+bool __fastcall TSaveSessionDialog::Execute(
+  UnicodeString & SessionName, bool & SavePassword, bool & CreateShortcut,
+  const UnicodeString & OriginalSessionName)
 {
-  FOriginalSessionName = SessionName;
+  FOriginalSessionName = OriginalSessionName;
   SessionNameEdit->Text = TSessionData::ExtractLocalName(SessionName);
   UnicodeString Folder = TSessionData::ExtractFolderName(SessionName);
   if (Folder.IsEmpty())
@@ -265,11 +280,13 @@ bool __fastcall TSaveSessionDialog::Execute(UnicodeString & SessionName, bool &
     FolderCombo->Text = Folder;
   }
   SavePasswordCheck->Checked = SavePassword;
+  CreateShortcutCheck->Checked = CreateShortcut;
   bool Result = TCustomDialog::Execute();
   if (Result)
   {
     SessionName = GetSessionName();
     SavePassword = SavePasswordCheck->Checked;
+    CreateShortcut = CreateShortcutCheck->Checked;
   }
   return Result;
 }
@@ -336,6 +353,7 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
   UnicodeString SessionName = SessionData->SessionName;
 
   bool Result;
+  bool CreateShortcut = false;
   if (!ForceDialog && ((PSavePassword == NULL) || SavePassword))
   {
     CustomWinConfiguration->AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(SessionData);
@@ -343,11 +361,12 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
   }
   else
   {
-    TSaveSessionDialog * Dialog =
-      new TSaveSessionDialog((PSavePassword != NULL), NotRecommendedSavingPassword);
+    // This can be a standalone dialog when used with save URL (from GetLoginData)
+    TSaveSessionDialog * Dialog = SafeFormCreate<TSaveSessionDialog>();
     try
     {
-      Result = Dialog->Execute(SessionName, SavePassword);
+      Dialog->Init((PSavePassword != NULL), NotRecommendedSavingPassword);
+      Result = Dialog->Execute(SessionName, SavePassword, CreateShortcut, SessionData->Name);
     }
     __finally
     {
@@ -367,6 +386,14 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
       StoredSessions->NewSession(SessionName, SessionData);
     // modified only, explicit
     StoredSessions->Save(false, true);
+
+    if (CreateShortcut)
+    {
+      UnicodeString AdditionalParams =
+        TProgramParams::FormatSwitch(DESKTOP_SWITCH) + L" " +
+        TProgramParams::FormatSwitch(UPLOAD_IF_ANY_SWITCH);
+      CreateDesktopSessionShortCut(SessionName, L"", AdditionalParams, -1, SITE_ICON);
+    }
   }
 
   return NewSession;
@@ -386,7 +413,7 @@ void __fastcall SessionNameValidate(const UnicodeString & Text,
     Abort();
   }
   else if ((Data != NULL) && (Text != OriginalName) &&
-    MessageDialog(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text)),
+    MessageDialog(MainInstructions(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text))),
       qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
   {
     Abort();
@@ -425,7 +452,7 @@ __fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
   WorkspaceNameCombo->AutoComplete = false;
   AddComboBox(WorkspaceNameCombo, CreateLabel(LoadStr(SAVE_WORKSPACE_PROMPT)));
 
-  std::auto_ptr<TStrings> Workspaces(StoredSessions->GetWorkspaces());
+  std::unique_ptr<TStrings> Workspaces(StoredSessions->GetWorkspaces());
   WorkspaceNameCombo->Items->AddStrings(Workspaces.get());
 
   SavePasswordsCheck = new TCheckBox(this);
@@ -438,7 +465,7 @@ __fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
   EnableControl(SavePasswordsCheck, CanSavePasswords);
 
   CreateShortcutCheck = new TCheckBox(this);
-  CreateShortcutCheck->Caption = LoadStr(SAVE_WORKSPACE_SHORTCUT);
+  CreateShortcutCheck->Caption = LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT);
   AddButtonControl(CreateShortcutCheck);
 
   EnableAutoSaveCheck = new TCheckBox(this);
@@ -494,7 +521,7 @@ bool __fastcall DoSaveWorkspaceDialog(UnicodeString & WorkspaceName,
   bool * SavePasswords, bool NotRecommendedSavingPasswords,
   bool & CreateShortcut, bool & EnableAutoSave)
 {
-  std::auto_ptr<TSaveWorkspaceDialog> Dialog(
+  std::unique_ptr<TSaveWorkspaceDialog> Dialog(
     new TSaveWorkspaceDialog((SavePasswords != NULL), NotRecommendedSavingPasswords));
 
   bool Dummy = false;

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است