Martin Prikryl 12 years ago
parent
commit
4dad4a32f0
100 changed files with 15332 additions and 945 deletions
  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: AssemblyVersion("1.1.4.0")]
 [assembly: AssemblyFileVersion("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)]
 [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>
 			<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<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_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_Release>2</VerInfo_Release>
 			<VerInfo_Release>2</VerInfo_Release>

+ 1 - 1
source/DragExt.cbproj

@@ -42,7 +42,7 @@
 			<ProjectType>CppDynamicLibrary</ProjectType>
 			<ProjectType>CppDynamicLibrary</ProjectType>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<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_Locale>1033</VerInfo_Locale>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_Release>1</VerInfo_Release>
 			<VerInfo_Release>1</VerInfo_Release>

+ 2 - 2
source/DragExt64.rc

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

+ 8 - 0
source/Putty.cbproj

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

+ 9 - 3
source/WinSCP.cbproj

@@ -39,6 +39,9 @@
 			<BRCC_CodePage>65001</BRCC_CodePage>
 			<BRCC_CodePage>65001</BRCC_CodePage>
 			<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
 			<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_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>
 			<Defines>OLD_DND;STRICT;$(Defines)</Defines>
 			<Icon_MainIcon>resource\Icon256.ico</Icon_MainIcon>
 			<Icon_MainIcon>resource\Icon256.ico</Icon_MainIcon>
 			<ILINK_GenerateDRC>true</ILINK_GenerateDRC>
 			<ILINK_GenerateDRC>true</ILINK_GenerateDRC>
@@ -51,11 +54,11 @@
 			<ProjectType>CppVCLApplication</ProjectType>
 			<ProjectType>CppVCLApplication</ProjectType>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<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_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
-			<VerInfo_Release>4</VerInfo_Release>
+			<VerInfo_Release>5</VerInfo_Release>
 		</PropertyGroup>
 		</PropertyGroup>
 		<PropertyGroup Condition="'$(Cfg_1)'!=''">
 		<PropertyGroup Condition="'$(Cfg_1)'!=''">
 			<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
 			<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
@@ -82,7 +85,7 @@
 			<BCC_MonitorInlinePtrAccess>true</BCC_MonitorInlinePtrAccess>
 			<BCC_MonitorInlinePtrAccess>true</BCC_MonitorInlinePtrAccess>
 			<BCC_MonitorThis>true</BCC_MonitorThis>
 			<BCC_MonitorThis>true</BCC_MonitorThis>
 			<DCC_DebugDCUs>true</DCC_DebugDCUs>
 			<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>
 		<PropertyGroup Condition="'$(Cfg_2)'!=''">
 		<PropertyGroup Condition="'$(Cfg_2)'!=''">
 			<Defines>NDEBUG;$(Defines)</Defines>
 			<Defines>NDEBUG;$(Defines)</Defines>
@@ -176,6 +179,9 @@
 				<BuildOrder>6</BuildOrder>
 				<BuildOrder>6</BuildOrder>
 				<BuildOrder>53</BuildOrder>
 				<BuildOrder>53</BuildOrder>
 			</CppCompile>
 			</CppCompile>
+			<DelphiCompile Include="windows\Vcl.Controls.pas">
+				<BuildOrder>35</BuildOrder>
+			</DelphiCompile>
 			<CppCompile Include="windows\WinConfiguration.cpp">
 			<CppCompile Include="windows\WinConfiguration.cpp">
 				<BuildOrder>56</BuildOrder>
 				<BuildOrder>56</BuildOrder>
 				<BuildOrder>3</BuildOrder>
 				<BuildOrder>3</BuildOrder>

+ 10 - 5
source/components/ThemePageControl.cpp

@@ -4,6 +4,7 @@
 
 
 #include <Common.h>
 #include <Common.h>
 #include <vsstyle.h>
 #include <vsstyle.h>
+#include <memory>
 #include "ThemePageControl.h"
 #include "ThemePageControl.h"
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma package(smart_init)
@@ -183,7 +184,7 @@ void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
       RectMem.Bottom--;
       RectMem.Bottom--;
     }
     }
 
 
-    DrawTabItem(DCMem, Item, RectMem, (State == TIS_SELECTED));
+    DrawTabItem(DCMem, Item, RectMem, (State == TIS_SELECTED), (State == TIS_DISABLED));
   }
   }
 
 
   // Blit image to the screen
   // 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
 // 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)
   if (Selected)
   {
   {
@@ -210,7 +212,6 @@ void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, boo
 
 
   UnicodeString Text = Pages[Item]->Caption;
   UnicodeString Text = Pages[Item]->Caption;
 
 
-  int OldMode = SetBkMode(DC, TRANSPARENT);
   if ((Images != NULL) && (Pages[Item]->ImageIndex >= 0))
   if ((Images != NULL) && (Pages[Item]->ImageIndex >= 0))
   {
   {
     int Left;
     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;
       Left = (Rect.Right - Images->Width - Rect.Left) / 2;
     }
     }
     int Y = ((Rect.Top + Rect.Bottom - Images->Height) / 2) - 1 + (Selected ? 0 : -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;
     Rect.Left += Images->Width + 3;
   }
   }
   else
   else
@@ -232,6 +236,7 @@ void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, boo
     Rect.Left -= 2;
     Rect.Left -= 2;
   }
   }
 
 
+  int OldMode = SetBkMode(DC, TRANSPARENT);
   if (!Text.IsEmpty())
   if (!Text.IsEmpty())
   {
   {
     HFONT OldFont = (HFONT)SelectObject(DC, Font->Handle);
     HFONT OldFont = (HFONT)SelectObject(DC, Font->Handle);

+ 1 - 1
source/components/ThemePageControl.h

@@ -32,7 +32,7 @@ protected:
 
 
 private:
 private:
   void __fastcall DrawThemesXpTabItem(HDC DC, int Item, const TRect & Rect, bool Body, int State);
   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 DrawThemesPart(HDC DC, int PartId, int StateId, LPCWSTR PartNameID, LPRECT Rect);
   void __fastcall InvalidateTab(int Index);
   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)
 void __fastcall TUnixDirView::DisplayContextMenu(const TPoint &Where)
 {
 {
   bool Handled = false;
   bool Handled = false;
-  if (OnContextPopup) OnContextPopup(this, ScreenToClient(Where), Handled);
+  if (OnContextPopup)
+  {
+    OnContextPopup(this, ScreenToClient(Where), Handled);
+  }
   if (!Handled)
   if (!Handled)
   {
   {
     if (PopupMenu && !PopupMenu->AutoPopup)
     if (PopupMenu && !PopupMenu->AutoPopup)
+    {
       PopupMenu->Popup(Where.x, Where.y);
       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)
 void __fastcall TCustomUnixDriveView::Change(TTreeNode * Node)
 {
 {
   #ifndef DESIGN_ONLY
   #ifndef DESIGN_ONLY
+  bool Expand = false;
   try
   try
   {
   {
     // During D&D Selected is set to NULL and then back to previous selection,
     // During D&D Selected is set to NULL and then back to previous selection,
     // prevent actually changing directory in such case
     // prevent actually changing directory in such case
     if (Reading || ControlState.Contains(csRecreating) ||
     if (Reading || ControlState.Contains(csRecreating) ||
-        FIgnoreChange || (Node == NULL) || (Node == FPrevSelected))
+        (Node == NULL) || (Node == FPrevSelected))
     {
     {
       TCustomDriveView::Change(Node);
       TCustomDriveView::Change(Node);
     }
     }
     else
     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.
       // if previous node is child to newly selected one, do not expand it.
       // it is either already expanded and it is even being collapsed.
       // 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);
         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
   __finally
   {
   {
+    FPrevSelected = Selected;
+    if (Expand)
+    {
+      Selected->Expand(false);
+    }
     CheckPendingDeletes();
     CheckPendingDeletes();
   }
   }
   #else
   #else

+ 156 - 76
source/core/Common.cpp

@@ -11,6 +11,7 @@
 #include <DateUtils.hpp>
 #include <DateUtils.hpp>
 #include <math.h>
 #include <math.h>
 #include <shlobj.h>
 #include <shlobj.h>
+#include <limits>
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #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)
 bool IsNumber(const UnicodeString Str)
 {
 {
   int Value;
   int Value;
@@ -460,6 +499,17 @@ UnicodeString __fastcall ExtractProgram(UnicodeString Command)
   return Program;
   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)
 UnicodeString __fastcall FormatCommand(UnicodeString Program, UnicodeString Params)
 {
 {
   Program = Program.Trim();
   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)));
     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)
 bool __fastcall IsDigit(wchar_t Ch)
 {
 {
   return (Ch >= '0') && (Ch <= '9');
   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
 struct TDateTimeParams
 {
 {
   TDateTime UnixEpoch;
   TDateTime UnixEpoch;
@@ -870,7 +948,7 @@ struct TDateTimeParams
 };
 };
 typedef std::map<int, TDateTimeParams> TYearlyDateTimeParams;
 typedef std::map<int, TDateTimeParams> TYearlyDateTimeParams;
 static TYearlyDateTimeParams YearlyDateTimeParams;
 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,
 static void __fastcall EncodeDSTMargin(const SYSTEMTIME & Date, unsigned short Year,
   TDateTime & Result);
   TDateTime & Result);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -967,7 +1045,7 @@ static const TDateTimeParams * __fastcall GetDateTimeParams(unsigned short Year)
     }
     }
     Result->SummerDST = (Result->DaylightDate < Result->StandardDate);
     Result->SummerDST = (Result->DaylightDate < Result->StandardDate);
 
 
-    Result->DaylightHack = !IsWin7() || IsExactly2008R2();
+    Result->DaylightHack = !IsWin7();
   }
   }
 
 
   return Result;
   return Result;
@@ -1165,20 +1243,30 @@ FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime,
 TDateTime __fastcall FileTimeToDateTime(const FILETIME & FileTime)
 TDateTime __fastcall FileTimeToDateTime(const FILETIME & FileTime)
 {
 {
   // duplicated in DirView.pas
   // 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
   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;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -1195,7 +1283,7 @@ __int64 __fastcall ConvertTimestampToUnix(const FILETIME & FileTime,
       SYSTEMTIME SystemTime;
       SYSTEMTIME SystemTime;
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
-      TDateTime DateTime = SystemTimeToDateTime(SystemTime);
+      TDateTime DateTime = SystemTimeToDateTimeVerbose(SystemTime);
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       Result += (IsDateInDST(DateTime) ?
       Result += (IsDateInDST(DateTime) ?
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
@@ -1215,7 +1303,7 @@ __int64 __fastcall ConvertTimestampToUnix(const FILETIME & FileTime,
       SYSTEMTIME SystemTime;
       SYSTEMTIME SystemTime;
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
       FileTimeToSystemTime(&LocalFileTime, &SystemTime);
-      TDateTime DateTime = SystemTimeToDateTime(SystemTime);
+      TDateTime DateTime = SystemTimeToDateTimeVerbose(SystemTime);
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       const TDateTimeParams * Params = GetDateTimeParams(DecodeYear(DateTime));
       Result -= (IsDateInDST(DateTime) ?
       Result -= (IsDateInDST(DateTime) ?
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
         Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
@@ -1395,7 +1483,7 @@ UnicodeString __fastcall GetTimeZoneLogString()
   const TDateTimeParams * Params = GetDateTimeParams(0);
   const TDateTimeParams * Params = GetDateTimeParams(0);
 
 
   UnicodeString Result =
   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->CurrentDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->StandardDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->StandardDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->DaylightDifferenceSec),
        FormatTimeZone(Params->BaseDifferenceSec + Params->DaylightDifferenceSec),
@@ -1404,6 +1492,39 @@ UnicodeString __fastcall GetTimeZoneLogString()
   return Result;
   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)
 UnicodeString __fastcall StandardTimestamp(const TDateTime & DateTime)
 {
 {
   return FormatDateTime(L"yyyy'-'mm'-'dd'T'hh':'nn':'ss'.'zzz'Z'", ConvertTimestampToUTC(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;
         break;
 
 
       case L'%':
       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;
         break;
@@ -1677,9 +1806,8 @@ UnicodeString __fastcall NonUrlChars()
   for (unsigned int I = 0; I <= 127; I++)
   for (unsigned int I = 0; I <= 127; I++)
   {
   {
     wchar_t C = static_cast<wchar_t>(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'.'))
         (C == L'_') || (C == L'-') || (C == L'.'))
     {
     {
       // noop
       // noop
@@ -1797,54 +1925,6 @@ bool __fastcall IsWin7()
   return CheckWin32Version(6, 1);
   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()
 LCID __fastcall GetDefaultLCID()
 {
 {
   return GetUserDefaultLCID();
   return GetUserDefaultLCID();
@@ -1888,12 +1968,12 @@ UnicodeString __fastcall WindowsProductName()
   try
   try
   {
   {
     Registry->RootKey = HKEY_LOCAL_MACHINE;
     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;
     delete Registry;
   }
   }
@@ -1907,7 +1987,7 @@ bool __fastcall IsDirectoryWriteable(const UnicodeString & Path)
 {
 {
   UnicodeString FileName =
   UnicodeString FileName =
     IncludeTrailingPathDelimiter(Path) +
     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,
   HANDLE Handle = CreateFile(FileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
     CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 0);
     CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 0);
   bool Result = (Handle != INVALID_HANDLE_VALUE);
   bool Result = (Handle != INVALID_HANDLE_VALUE);

+ 10 - 1
source/core/Common.h

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

+ 1 - 6
source/core/Configuration.cpp

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

+ 0 - 2
source/core/Configuration.h

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

+ 34 - 1
source/core/CopyParam.cpp

@@ -43,6 +43,8 @@ void __fastcall TCopyParamType::Default()
   FileMask = L"*.*";
   FileMask = L"*.*";
   IncludeFileMask.Masks = L"";
   IncludeFileMask.Masks = L"";
   ClearArchive = false;
   ClearArchive = false;
+  RemoveCtrlZ = false;
+  RemoveBOM = false;
   CPSLimit = 0;
   CPSLimit = 0;
   NewerOnly = false;
   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))
   if (!(IncludeFileMask == Defaults.IncludeFileMask))
   {
   {
     ADD(FORMAT(LoadStr(COPY_INFO_FILE_MASK), (IncludeFileMask.Masks)),
     ADD(FORMAT(LoadStr(COPY_INFO_FILE_MASK), (IncludeFileMask.Masks)),
@@ -264,6 +287,8 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
   COPY(FileMask);
   COPY(FileMask);
   COPY(IncludeFileMask);
   COPY(IncludeFileMask);
   COPY(ClearArchive);
   COPY(ClearArchive);
+  COPY(RemoveCtrlZ);
+  COPY(RemoveBOM);
   COPY(CPSLimit);
   COPY(CPSLimit);
   COPY(NewerOnly);
   COPY(NewerOnly);
   #undef COPY
   #undef COPY
@@ -421,7 +446,7 @@ UnicodeString __fastcall TCopyParamType::GetLogStr() const
   return FORMAT(
   return FORMAT(
     L"  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s (%s); FnCs: %s; RIC: %s; "
     L"  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s (%s); FnCs: %s; RIC: %s; "
        "Resume: %s (%d); CalcS: %s; Mask: %s\n"
        "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",
      "  AscM: %s\n",
     (BooleanToEngStr(PreserveTime),
     (BooleanToEngStr(PreserveTime),
      BooleanToEngStr(PreserveReadOnly),
      BooleanToEngStr(PreserveReadOnly),
@@ -436,6 +461,8 @@ UnicodeString __fastcall TCopyParamType::GetLogStr() const
      FileMask,
      FileMask,
      ModeC[TransferMode],
      ModeC[TransferMode],
      BooleanToEngStr(ClearArchive),
      BooleanToEngStr(ClearArchive),
+     BooleanToEngStr(RemoveCtrlZ),
+     BooleanToEngStr(RemoveBOM),
      int(CPSLimit),
      int(CPSLimit),
      BooleanToEngStr(NewerOnly),
      BooleanToEngStr(NewerOnly),
      IncludeFileMask.Masks,
      IncludeFileMask.Masks,
@@ -519,6 +546,8 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
     }
     }
   }
   }
   ClearArchive = Storage->ReadBool(L"ClearArchive", ClearArchive);
   ClearArchive = Storage->ReadBool(L"ClearArchive", ClearArchive);
+  RemoveCtrlZ = Storage->ReadBool(L"RemoveCtrlZ", RemoveCtrlZ);
+  RemoveBOM = Storage->ReadBool(L"RemoveBOM", RemoveBOM);
   CPSLimit = Storage->ReadInteger(L"CPSLimit", CPSLimit);
   CPSLimit = Storage->ReadInteger(L"CPSLimit", CPSLimit);
   NewerOnly = Storage->ReadBool(L"NewerOnly", NewerOnly);
   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"ExcludeFileMask"); // obsolete
   Storage->DeleteValue(L"NegativeExclude"); // obsolete
   Storage->DeleteValue(L"NegativeExclude"); // obsolete
   Storage->WriteBool(L"ClearArchive", ClearArchive);
   Storage->WriteBool(L"ClearArchive", ClearArchive);
+  Storage->WriteBool(L"RemoveCtrlZ", RemoveCtrlZ);
+  Storage->WriteBool(L"RemoveBOM", RemoveBOM);
   Storage->WriteInteger(L"CPSLimit", CPSLimit);
   Storage->WriteInteger(L"CPSLimit", CPSLimit);
   Storage->WriteBool(L"NewerOnly", NewerOnly);
   Storage->WriteBool(L"NewerOnly", NewerOnly);
 }
 }
@@ -567,6 +598,8 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
     C(CalculateSize) &&
     C(CalculateSize) &&
     C(IncludeFileMask) &&
     C(IncludeFileMask) &&
     C(ClearArchive) &&
     C(ClearArchive) &&
+    C(RemoveCtrlZ) &&
+    C(RemoveBOM) &&
     C(CPSLimit) &&
     C(CPSLimit) &&
     C(NewerOnly) &&
     C(NewerOnly) &&
     true;
     true;

+ 6 - 0
source/core/CopyParam.h

@@ -21,6 +21,8 @@ const int cpaNoRights =        0x20;
 const int cpaNoPreserveReadOnly = 0x40;
 const int cpaNoPreserveReadOnly = 0x40;
 const int cpaNoIgnorePermErrors = 0x80;
 const int cpaNoIgnorePermErrors = 0x80;
 const int cpaNoNewerOnly        = 0x100;
 const int cpaNoNewerOnly        = 0x100;
+const int cpaNoRemoveCtrlZ      = 0x200;
+const int cpaNoRemoveBOM        = 0x400;
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 struct TUsableCopyParamAttrs
 struct TUsableCopyParamAttrs
 {
 {
@@ -51,6 +53,8 @@ private:
   UnicodeString FFileMask;
   UnicodeString FFileMask;
   TFileMasks FIncludeFileMask;
   TFileMasks FIncludeFileMask;
   bool FClearArchive;
   bool FClearArchive;
+  bool FRemoveCtrlZ;
+  bool FRemoveBOM;
   unsigned long FCPSLimit;
   unsigned long FCPSLimit;
   bool FNewerOnly;
   bool FNewerOnly;
   static const wchar_t TokenPrefix = L'%';
   static const wchar_t TokenPrefix = L'%';
@@ -110,6 +114,8 @@ public:
   __property UnicodeString FileMask = { read = FFileMask, write = FFileMask };
   __property UnicodeString FileMask = { read = FFileMask, write = FFileMask };
   __property TFileMasks IncludeFileMask = { read = FIncludeFileMask, write = FIncludeFileMask };
   __property TFileMasks IncludeFileMask = { read = FIncludeFileMask, write = FIncludeFileMask };
   __property bool ClearArchive = { read = FClearArchive, write = FClearArchive };
   __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 unsigned long CPSLimit = { read = FCPSLimit, write = FCPSLimit };
   __property bool NewerOnly = { read = FNewerOnly, write = FNewerOnly };
   __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;
     int D = 0;
     for (int Index = 1; Index <= Password.Length(); Index++)
     for (int Index = 1; Index <= Password.Length(); Index++)
     {
     {
-      if ((Password[Index] >= L'a') && (Password[Index] <= L'z'))
+      if (IsLowerCaseLetter(Password[Index]))
       {
       {
         A = 1;
         A = 1;
       }
       }
-      else if ((Password[Index] >= L'A') && (Password[Index] <= L'Z'))
+      else if (IsUpperCaseLetter(Password[Index]))
       {
       {
         B = 1;
         B = 1;
       }
       }
-      else if ((Password[Index] >= L'0') && (Password[Index] <= L'9'))
+      else if (IsDigit(Password[Index]))
       {
       {
         C = 1;
         C = 1;
       }
       }

+ 22 - 5
source/core/Exceptions.cpp

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

+ 75 - 19
source/core/Exceptions.h

@@ -7,7 +7,9 @@
 #include <SysInit.hpp>
 #include <SysInit.hpp>
 #include <System.hpp>
 #include <System.hpp>
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+bool __fastcall ShouldDisplayException(Exception * E);
 bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message);
 bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message);
+bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message);
 UnicodeString __fastcall LastSysErrorMessage();
 UnicodeString __fastcall LastSysErrorMessage();
 TStrings * __fastcall ExceptionToMoreMessages(Exception * E);
 TStrings * __fastcall ExceptionToMoreMessages(Exception * E);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -26,12 +28,30 @@ public:
   __property TStrings* MoreMessages = {read=FMoreMessages};
   __property TStrings* MoreMessages = {read=FMoreMessages};
   __property UnicodeString HelpKeyword = {read=FHelpKeyword};
   __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();
   virtual ExtException * __fastcall Clone();
 
 
@@ -47,16 +67,45 @@ private:
   class NAME : public BASE \
   class NAME : public BASE \
   { \
   { \
   public: \
   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);
 DERIVE_EXT_EXCEPTION(ESsh, ExtException);
@@ -91,8 +140,14 @@ private:
   class NAME : public BASE \
   class NAME : public BASE \
   { \
   { \
   public: \
   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);
 DERIVE_FATAL_EXCEPTION(ESshFatal, EFatal);
@@ -105,7 +160,8 @@ public:
   inline __fastcall ESshTerminate(Exception* E, UnicodeString Msg, TOnceDoneOperation AOperation) :
   inline __fastcall ESshTerminate(Exception* E, UnicodeString Msg, TOnceDoneOperation AOperation) :
     EFatal(E, Msg),
     EFatal(E, Msg),
     Operation(AOperation)
     Operation(AOperation)
-  { }
+  {
+  }
 
 
   virtual ExtException * __fastcall Clone();
   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++)
     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]))
       if ((Index < Size - 1) && (*Ptr == Dest[0]) && (*(Ptr+1) == Dest[1]))
       {
       {
         Index++;
         Index++;
         Ptr++;
         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.
       // now we got the second char, so get rid of it.
       else if ((Index == 0) && PrevToken && (*Ptr == Dest[1]))
       else if ((Index == 0) && PrevToken && (*Ptr == Dest[1]))
       {
       {
         Delete(Index, 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])
       else if (*Ptr == Source[0])
       {
       {
-        if ((*Ptr == Dest[0]) && (Index == Size - 1))
-        {
-          Token = true;
-        }
-
         *Ptr = Dest[0];
         *Ptr = Dest[0];
         if (Dest[1])
         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)
   if (!Result && Directory && !IsUnixRootPath(Path) && Recurse)
   {
   {
     UnicodeString ParentFileName = UnixExtractFileName(Path);
     UnicodeString ParentFileName = UnixExtractFileName(Path);
-    UnicodeString ParentPath = UnixExcludeTrailingBackslash(UnixExtractFilePath(Path));
+    UnicodeString ParentPath = SimpleUnixExcludeTrailingBackslash(UnixExtractFilePath(Path));
     // Pass Params down or not?
     // Pass Params down or not?
     // Currently it includes Size/Time only, what is not used for directories.
     // Currently it includes Size/Time only, what is not used for directories.
     // So it depends of future use. Possibly we should make a copy
     // 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
   else
   {
   {
     Result = Matches(UnixExtractFileName(FileName), Directory,
     Result = Matches(UnixExtractFileName(FileName), Directory,
-      UnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)), Params,
+      SimpleUnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)), Params,
       ImplicitMatch);
       ImplicitMatch);
   }
   }
   return Result;
   return Result;
@@ -638,7 +638,7 @@ void __fastcall TFileMasks::CreateMask(
       {
       {
         // make sure sole "/" (root dir) is preserved as is
         // make sure sole "/" (root dir) is preserved as is
         CreateMaskMask(
         CreateMaskMask(
-          UnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))),
+          SimpleUnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))),
           PartStart, PartStart + D - 1, false,
           PartStart, PartStart + D - 1, false,
           Mask.DirectoryMask);
           Mask.DirectoryMask);
         CreateMaskMask(
         CreateMaskMask(
@@ -972,7 +972,8 @@ void __fastcall TInteractiveCustomCommand::Execute(
 int __fastcall TInteractiveCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 int __fastcall TInteractiveCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 {
 {
   int Len;
   int Len;
-  switch (Command[Index + 1])
+  wchar_t PatternCmd = (Index < Command.Length()) ? Command[Index + 1] : L'\0';
+  switch (PatternCmd)
   {
   {
     case L'?':
     case L'?':
       {
       {
@@ -1055,20 +1056,20 @@ __fastcall TCustomCommandData::TCustomCommandData()
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal)
 __fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal)
 {
 {
-  Init(Terminal->SessionData, Terminal->Password);
+  Init(Terminal->SessionData, Terminal->UserName, Terminal->Password);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TCustomCommandData::TCustomCommandData(
 __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(
 void __fastcall TCustomCommandData::Init(
-  TSessionData * SessionData, const UnicodeString & APassword)
+  TSessionData * SessionData, const UnicodeString & AUserName, const UnicodeString & APassword)
 {
 {
   HostName = SessionData->HostNameExpanded;
   HostName = SessionData->HostNameExpanded;
-  UserName = SessionData->UserNameExpanded;
+  UserName = AUserName;
   Password = APassword;
   Password = APassword;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -1098,7 +1099,8 @@ TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
 int __fastcall TFileCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 int __fastcall TFileCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 {
 {
   int Len;
   int Len;
-  switch (toupper(Command[Index + 1]))
+  wchar_t PatternCmd = (Index < Command.Length()) ? Command[Index + 1] : L'\0';
+  switch (PatternCmd)
   {
   {
     case L'@':
     case L'@':
     case L'U':
     case L'U':

+ 6 - 2
source/core/FileMasks.h

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

+ 1 - 0
source/core/FileSystems.h

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

+ 28 - 3
source/core/FtpFileSystem.cpp

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

+ 1 - 0
source/core/FtpFileSystem.h

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

+ 1 - 1
source/core/Option.cpp

@@ -42,7 +42,7 @@ void __fastcall TOptions::Add(UnicodeString Value)
           break;
           break;
         }
         }
         // this is to treat /home/martin as parameter, not as switch
         // 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;
           Switch = false;
           break;
           break;

+ 85 - 22
source/core/PuttyIntf.cpp

@@ -9,10 +9,11 @@
 #include "Exceptions.h"
 #include "Exceptions.h"
 #include "CoreMain.h"
 #include "CoreMain.h"
 #include "TextsCore.h"
 #include "TextsCore.h"
+#include <StrUtils.hpp>
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 char sshver[50];
 char sshver[50];
 const int platform_uses_x11_unix_by_default = TRUE;
 const int platform_uses_x11_unix_by_default = TRUE;
-CRITICAL_SECTION noise_section;
+CRITICAL_SECTION putty_section;
 bool SaveRandomSeed;
 bool SaveRandomSeed;
 char appname_[50];
 char appname_[50];
 const char *const appname = appname_;
 const char *const appname = appname_;
@@ -30,7 +31,7 @@ void __fastcall PuttyInitialize()
 {
 {
   SaveRandomSeed = true;
   SaveRandomSeed = true;
 
 
-  InitializeCriticalSection(&noise_section);
+  InitializeCriticalSection(&putty_section);
 
 
   // make sure random generator is initialised, so random_save_seed()
   // make sure random generator is initialised, so random_save_seed()
   // in destructor can proceed
   // in destructor can proceed
@@ -58,7 +59,7 @@ void __fastcall PuttyFinalize()
 
 
   sk_cleanup();
   sk_cleanup();
   win_misc_cleanup();
   win_misc_cleanup();
-  DeleteCriticalSection(&noise_section);
+  DeleteCriticalSection(&putty_section);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall DontSaveRandomSeed()
 void __fastcall DontSaveRandomSeed()
@@ -123,6 +124,11 @@ int from_backend_untrusted(void * /*frontend*/, const char * /*data*/, int /*len
   return 0;
   return 0;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+int from_backend_eof(void * /*frontend*/)
+{
+  return FALSE;
+}
+//---------------------------------------------------------------------------
 int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
 int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
 {
 {
   assert(p != NULL);
   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];
       prompt_t * Prompt = p->prompts[Index];
       Prompts->AddObject(Prompt->prompt, (TObject *)(FLAGMASK(Prompt->echo, pupEcho)));
       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,
     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++)
       for (int Index = 0; Index < int(p->n_prompts); Index++)
       {
       {
         prompt_t * Prompt = p->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;
       Result = 1;
     }
     }
@@ -256,12 +262,20 @@ void modalfatalbox(char * fmt, ...)
   va_end(Param);
   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*/)
 void cleanup_exit(int /*code*/)
 {
 {
   throw ESshFatal(NULL, "");
   throw ESshFatal(NULL, "");
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-int askappend(void * /*frontend*/, Filename /*filename*/,
+int askappend(void * /*frontend*/, Filename * /*filename*/,
   void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
   void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
 {
 {
   // this is called from logging.c of putty, which is never used with WinSCP
   // 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
   // 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();
   return ticks + GetTickCount();
 }
 }
@@ -306,12 +319,12 @@ void expire_timer_context(void * /*ctx*/)
   // nothing
   // nothing
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-Pinger pinger_new(Config * /*cfg*/, Backend * /*back*/, void * /*backhandle*/)
+Pinger pinger_new(Conf * /*conf*/, Backend * /*back*/, void * /*backhandle*/)
 {
 {
   return NULL;
   return NULL;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void pinger_reconfig(Pinger /*pinger*/, Config * /*oldcfg*/, Config * /*newcfg*/)
+void pinger_reconfig(Pinger /*pinger*/, Conf * /*oldconf*/, Conf * /*newconf*/)
 {
 {
   // nothing
   // nothing
 }
 }
@@ -326,23 +339,25 @@ void set_busy_status(void * /*frontend*/, int /*status*/)
   // nothing
   // 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.
   // 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
   else
   {
   {
-    *user = '\0';
+    result = NULL;
   }
   }
-  return (*user != '\0');
+  return result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
 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());
   return parse_blocksize(AnsiSizeStr.c_str());
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-bool __fastcall HasGSSAPI()
+bool __fastcall HasGSSAPI(UnicodeString CustomPath)
 {
 {
   static int has = -1;
   static int has = -1;
   if (has < 0)
   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
     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++)
       for (int Index = 0; (has <= 0) && (Index < List->nlibraries); Index++)
       {
       {
         ssh_gss_library * library = &List->libraries[Index];
         ssh_gss_library * library = &List->libraries[Index];
@@ -521,6 +539,7 @@ bool __fastcall HasGSSAPI()
     __finally
     __finally
     {
     {
       ssh_gss_cleanup(List);
       ssh_gss_cleanup(List);
+      conf_free(conf);
     }
     }
 
 
     if (has < 0)
     if (has < 0)
@@ -531,3 +550,47 @@ bool __fastcall HasGSSAPI()
   return (has > 0);
   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);
 __int64 __fastcall ParseSize(UnicodeString SizeStr);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-bool __fastcall HasGSSAPI();
+bool __fastcall HasGSSAPI(UnicodeString CustomPath);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall AES256EncodeWithMAC(char * Data, size_t Len, const char * Password,
 void __fastcall AES256EncodeWithMAC(char * Data, size_t Len, const char * Password,
   size_t PasswordLen, const char * Salt);
   size_t PasswordLen, const char * Salt);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+UnicodeString __fastcall NormalizeFingerprint(UnicodeString Fingerprint);
+UnicodeString __fastcall KeyTypeFromFingerprint(UnicodeString Fingerprint);
+//---------------------------------------------------------------------------
 #endif
 #endif

+ 2 - 3
source/core/Queue.cpp

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

+ 33 - 7
source/core/RemoteFiles.cpp

@@ -15,6 +15,19 @@
 #include "HelpCore.h"
 #include "HelpCore.h"
 /* TODO 1 : Path class instead of UnicodeString (handle relativity...) */
 /* 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)
 UnicodeString __fastcall UnixIncludeTrailingBackslash(const UnicodeString Path)
 {
 {
   // it used to return "/" when input path was empty
   // it used to return "/" when input path was empty
@@ -29,11 +42,24 @@ UnicodeString __fastcall UnixIncludeTrailingBackslash(const UnicodeString Path)
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 // Keeps "/" for root 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)
 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)
 UnicodeString __fastcall AbsolutePath(const UnicodeString & Base, const UnicodeString & Path)
 {
 {
+  // There's a duplicate implementation in TTerminal::ExpandFileName()
   UnicodeString Result;
   UnicodeString Result;
   if (Path.IsEmpty())
   if (Path.IsEmpty())
   {
   {
@@ -427,8 +454,7 @@ int __fastcall FakeFileImageIndex(UnicodeString FileName, unsigned long Attrs,
   TSHFileInfoW SHFileInfo;
   TSHFileInfoW SHFileInfo;
   // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
   // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
   if ((FileName == L"..") ||
   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))
       IsReservedName(FileName))
   {
   {
     FileName = L"dumb";
     FileName = L"dumb";
@@ -1865,7 +1891,7 @@ bool __fastcall TRemoteDirectoryChangesCache::DirectoryChangeKey(
   bool Result = !Change.IsEmpty();
   bool Result = !Change.IsEmpty();
   if (Result)
   if (Result)
   {
   {
-    bool Absolute = TTerminal::IsAbsolutePath(Change);
+    bool Absolute = UnixIsAbsolutePath(Change);
     Result = !SourceDir.IsEmpty() || Absolute;
     Result = !SourceDir.IsEmpty() || Absolute;
     if (Result)
     if (Result)
     {
     {

+ 4 - 1
source/core/RemoteFiles.h

@@ -425,8 +425,11 @@ public:
     const TRemoteProperties & OriginalProperties, TRemoteProperties NewProperties);
     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 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 UnixExtractFileDir(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFilePath(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFilePath(const UnicodeString Path);
 UnicodeString __fastcall UnixExtractFileName(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()
 void __fastcall TSCPFileSystem::Open()
 {
 {
+  // this is used for reconnects only
   FSecureShell->Open();
   FSecureShell->Open();
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -328,6 +329,11 @@ bool __fastcall TSCPFileSystem::GetActive()
   return FSecureShell->Active;
   return FSecureShell->Active;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::CollectUsage()
+{
+  FSecureShell->CollectUsage();
+}
+//---------------------------------------------------------------------------
 const TSessionInfo & __fastcall TSCPFileSystem::GetSessionInfo()
 const TSessionInfo & __fastcall TSCPFileSystem::GetSessionInfo()
 {
 {
   return FSecureShell->GetSessionInfo();
   return FSecureShell->GetSessionInfo();
@@ -440,6 +446,8 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
     case fcRename:
     case fcRename:
     case fcRemoteMove:
     case fcRemoteMove:
     case fcRemoteCopy:
     case fcRemoteCopy:
+    case fcRemoveCtrlZUpload:
+    case fcRemoveBOMUpload:
       return true;
       return true;
 
 
     case fcTextMode:
     case fcTextMode:
@@ -1682,8 +1690,12 @@ void __fastcall TSCPFileSystem::SCPSource(const UnicodeString FileName,
           // Than we add current block to file buffer
           // Than we add current block to file buffer
           if (OperationProgress->AsciiTransfer)
           if (OperationProgress->AsciiTransfer)
           {
           {
+            int ConvertParams =
+              FLAGMASK(CopyParam->RemoveCtrlZ, cpRemoveCtrlZ) |
+              FLAGMASK(CopyParam->RemoveBOM, cpRemoveBOM);
             BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
             BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-              FTerminal->SessionData->EOLType, cpRemoveCtrlZ | cpRemoveBOM, ConvertToken);
+              FTerminal->SessionData->EOLType,
+              ConvertParams, ConvertToken);
             BlockBuf.Memory->Seek(0, soFromBeginning);
             BlockBuf.Memory->Seek(0, soFromBeginning);
             AsciiBuf.ReadStream(BlockBuf.Memory, BlockBuf.Size, true);
             AsciiBuf.ReadStream(BlockBuf.Memory, BlockBuf.Size, true);
             // We don't need it any more
             // 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 Open();
   virtual void __fastcall Close();
   virtual void __fastcall Close();
   virtual bool __fastcall GetActive();
   virtual bool __fastcall GetActive();
+  virtual void __fastcall CollectUsage();
   virtual void __fastcall Idle();
   virtual void __fastcall Idle();
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual UnicodeString __fastcall AbsolutePath(UnicodeString Path, bool Local);
   virtual void __fastcall AnyCommand(const UnicodeString Command,
   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"))
   if (SameText(FCommands->ResolveCommand(Command), L"open"))
   {
   {
     UnicodeString AParams = Params;
     UnicodeString AParams = Params;
-    std::auto_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
+    std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
 
 
     UnicodeString MaskedParams;
     UnicodeString MaskedParams;
     UnicodeString Param;
     UnicodeString Param;
@@ -2111,7 +2111,7 @@ UnicodeString __fastcall TManagementScript::GetLogCmd(const UnicodeString & Full
       UnicodeString MaskedUrl;
       UnicodeString MaskedUrl;
       bool DefaultsOnly;
       bool DefaultsOnly;
 
 
-      std::auto_ptr<TSessionData> Data(
+      std::unique_ptr<TSessionData> Data(
         FStoredSessions->ParseUrl(Session, Parameters.get(), DefaultsOnly, NULL, NULL, &MaskedUrl));
         FStoredSessions->ParseUrl(Session, Parameters.get(), DefaultsOnly, NULL, NULL, &MaskedUrl));
       if (Session != MaskedUrl)
       if (Session != MaskedUrl)
       {
       {

+ 189 - 147
source/core/SecureShell.cpp

@@ -2,13 +2,13 @@
 #include <vcl.h>
 #include <vcl.h>
 #pragma hdrstop
 #pragma hdrstop
 
 
+#include "Common.h"
 #include "PuttyIntf.h"
 #include "PuttyIntf.h"
 #include "Exceptions.h"
 #include "Exceptions.h"
 #include "Interface.h"
 #include "Interface.h"
 #include "SecureShell.h"
 #include "SecureShell.h"
 #include "TextsCore.h"
 #include "TextsCore.h"
 #include "HelpCore.h"
 #include "HelpCore.h"
-#include "Common.h"
 #include "CoreMain.h"
 #include "CoreMain.h"
 
 
 #ifndef AUTO_WINSOCK
 #ifndef AUTO_WINSOCK
@@ -55,8 +55,6 @@ __fastcall TSecureShell::TSecureShell(TSessionUI* UI,
   ResetConnection();
   ResetConnection();
   FOnCaptureOutput = NULL;
   FOnCaptureOutput = NULL;
   FOnReceive = NULL;
   FOnReceive = NULL;
-  FConfig = new Config();
-  memset(FConfig, 0, sizeof(*FConfig));
   FSocket = INVALID_SOCKET;
   FSocket = INVALID_SOCKET;
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FFrozen = false;
   FFrozen = false;
@@ -71,9 +69,6 @@ __fastcall TSecureShell::~TSecureShell()
   Active = false;
   Active = false;
   ResetConnection();
   ResetConnection();
   CloseHandle(FSocketEvent);
   CloseHandle(FSocketEvent);
-  ClearConfig(FConfig);
-  delete FConfig;
-  FConfig = NULL;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::ResetConnection()
 void __fastcall TSecureShell::ResetConnection()
@@ -137,32 +132,51 @@ const TSessionInfo & __fastcall TSecureShell::GetSessionInfo()
   return FSessionInfo;
   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
   // 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
   // always set 0, as we will handle keepalives ourselves to avoid
   // multi-threaded issues in putty timer list
   // 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++)
   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;
       case cipArcfour: pcipher = CIPHER_ARCFOUR; break;
       default: assert(false);
       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++)
   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;
       case kexRSA: pkex = KEX_RSA; break;
       default: assert(false);
       default: assert(false);
     }
     }
-    cfg->ssh_kexlist[k] = pkex;
+    conf_set_int_int(conf, CONF_ssh_kexlist, k, pkex);
   }
   }
 
 
   UnicodeString SPublicKeyFile = Data->PublicKeyFile;
   UnicodeString SPublicKeyFile = Data->PublicKeyFile;
   if (SPublicKeyFile.IsEmpty()) SPublicKeyFile = Configuration->DefaultKeyFile;
   if (SPublicKeyFile.IsEmpty()) SPublicKeyFile = Configuration->DefaultKeyFile;
   SPublicKeyFile = StripPathQuotes(ExpandEnvironmentVariables(SPublicKeyFile));
   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)
   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
   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())
   if (!Data->TunnelPortFwd.IsEmpty())
   {
   {
     assert(!Simple);
     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
     // 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
   else
   {
   {
     assert(Simple);
     assert(Simple);
-    cfg->ssh_simple = Data->SshSimple && Simple;
+    conf_set_int(conf, CONF_ssh_simple, Data->SshSimple && Simple);
 
 
     if (Data->FSProtocol == fsSCPonly)
     if (Data->FSProtocol == fsSCPonly)
     {
     {
-      cfg->ssh_subsys = FALSE;
+      conf_set_int(conf, CONF_ssh_subsys, FALSE);
       if (Data->Shell.IsEmpty())
       if (Data->Shell.IsEmpty())
       {
       {
         // Following forces Putty to open default shell
         // Following forces Putty to open default shell
         // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
         // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
-        cfg->remote_cmd[0] = L'\0';
+        conf_set_str(conf, CONF_remote_cmd, "");
       }
       }
       else
       else
       {
       {
-        cfg->remote_cmd_ptr = AnsiStrNew(Data->Shell.c_str());
+        conf_set_str(conf, CONF_remote_cmd, AnsiString(Data->Shell).c_str());
       }
       }
     }
     }
     else
     else
     {
     {
       if (Data->SftpServer.IsEmpty())
       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
       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)
       if (Data->FSProtocol != fsSFTPonly)
       {
       {
-        cfg->ssh_subsys2 = FALSE;
+        conf_set_int(conf, CONF_ssh_subsys2, FALSE);
         if (Data->Shell.IsEmpty())
         if (Data->Shell.IsEmpty())
         {
         {
           // Following forces Putty to open default shell
           // Following forces Putty to open default shell
           // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
           // 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
         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())
       if ((Data->FSProtocol == fsSFTPonly) && Data->SftpServer.IsEmpty())
       {
       {
         // see psftp_connect() from psftp.c
         // 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
   // 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++)
   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()
 void __fastcall TSecureShell::Open()
@@ -330,15 +348,23 @@ void __fastcall TSecureShell::Open()
   FAuthenticationLog = L"";
   FAuthenticationLog = L"";
   FNoConnectionResponse = false;
   FNoConnectionResponse = false;
   FUI->Information(LoadStr(STATUS_LOOKUPHOST), true);
   FUI->Information(LoadStr(STATUS_LOOKUPHOST), true);
-  StoreToConfig(FSessionData, FConfig, Simple);
 
 
   try
   try
   {
   {
     char * RealHost;
     char * RealHost;
     FreeBackend(); // in case we are reconnecting
     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);
     sfree(RealHost);
     if (InitError)
     if (InitError)
     {
     {
@@ -981,7 +1007,7 @@ unsigned int __fastcall TSecureShell::TimeoutPrompt(TQueryParamsTimerEvent PoolE
       Params.Timeout = FConfiguration->SessionReopenAutoStall;
       Params.Timeout = FConfiguration->SessionReopenAutoStall;
       Params.TimeoutAnswer = qaAbort;
       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);
       NULL, qaRetry | qaAbort, &Params);
   }
   }
   __finally
   __finally
@@ -1163,12 +1189,9 @@ int __fastcall TSecureShell::TranslateAuthenticationMessage(
 
 
   int Result = TranslatePuttyMessage(Translation, LENOF(Translation), Message, HelpKeyword);
   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;
   return Result;
@@ -1435,6 +1458,8 @@ void inline __fastcall TSecureShell::CheckConnection(int Message)
       HelpKeyword = HELP_NOT_CONNECTED;
       HelpKeyword = HELP_NOT_CONNECTED;
     }
     }
 
 
+    Str = MainInstructions(Str);
+
     int ExitCode = get_ssh_exitcode(FBackendHandle);
     int ExitCode = get_ssh_exitcode(FBackendHandle);
     if (ExitCode >= 0)
     if (ExitCode >= 0)
     {
     {
@@ -1664,7 +1689,12 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
     {
     {
       Handles = sresize(Handles, HandleCount + 1, HANDLE);
       Handles = sresize(Handles, HandleCount + 1, HANDLE);
       Handles[HandleCount] = FSocketEvent;
       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 (WaitResult < WAIT_OBJECT_0 + HandleCount)
       {
       {
         if (handle_got_event(Handles[WaitResult - WAIT_OBJECT_0]))
         if (handle_got_event(Handles[WaitResult - WAIT_OBJECT_0]))
@@ -1727,6 +1757,8 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
       sfree(Handles);
       sfree(Handles);
     }
     }
 
 
+    run_toplevel_callbacks();
+
     unsigned int TicksAfter = GetTickCount();
     unsigned int TicksAfter = GetTickCount();
     // ticks wraps once in 49.7 days
     // ticks wraps once in 49.7 days
     if (TicksBefore < TicksAfter)
     if (TicksBefore < TicksAfter)
@@ -1889,7 +1921,7 @@ UnicodeString __fastcall TSecureShell::FormatKeyStr(UnicodeString KeyStr)
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::VerifyHostKey(UnicodeString Host, int Port,
 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)));
   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;
   FSessionInfo.HostKeyFingerprint = Fingerprint;
+  UnicodeString NormalizedFingerprint = NormalizeFingerprint(Fingerprint);
 
 
   bool Result = false;
   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.Aliases = Aliases;
       Params.AliasesCount = AliasesCount;
       Params.AliasesCount = AliasesCount;
       unsigned int R = FUI->QueryUser(
       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);
         NULL, Answers, &Params, qtWarning);
 
 
       switch (R) {
       switch (R) {
@@ -2098,7 +2137,10 @@ bool __fastcall TSecureShell::GetReady()
   return FOpened && (FWaiting == 0);
   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
 #ifndef PuttyIntfH
 struct Backend;
 struct Backend;
-struct Config;
+struct Conf;
 #endif
 #endif
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 struct _WSANETWORKEVENTS;
 struct _WSANETWORKEVENTS;
@@ -35,7 +35,6 @@ private:
   Backend * FBackend;
   Backend * FBackend;
   void * FBackendHandle;
   void * FBackendHandle;
   const unsigned int * FMaxPacketSize;
   const unsigned int * FMaxPacketSize;
-  Config * FConfig;
   TNotifyEvent FOnReceive;
   TNotifyEvent FOnReceive;
   bool FFrozen;
   bool FFrozen;
   bool FDataWhileFrozen;
   bool FDataWhileFrozen;
@@ -105,8 +104,7 @@ protected:
   void __fastcall inline LogEvent(const UnicodeString & Str);
   void __fastcall inline LogEvent(const UnicodeString & Str);
   void __fastcall FatalError(UnicodeString Error, UnicodeString HelpKeyword = L"");
   void __fastcall FatalError(UnicodeString Error, UnicodeString HelpKeyword = L"");
   UnicodeString __fastcall FormatKeyStr(UnicodeString KeyStr);
   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:
 public:
   __fastcall TSecureShell(TSessionUI * UI, TSessionData * SessionData,
   __fastcall TSecureShell(TSessionUI * UI, TSessionData * SessionData,
@@ -131,7 +129,7 @@ public:
   unsigned long __fastcall MaxPacketSize();
   unsigned long __fastcall MaxPacketSize();
   void __fastcall ClearStdError();
   void __fastcall ClearStdError();
   bool __fastcall GetStoredCredentialsTried();
   bool __fastcall GetStoredCredentialsTried();
-  void __fastcall EnableUsage();
+  void __fastcall CollectUsage();
 
 
   void __fastcall RegisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall RegisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall UnregisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall UnregisterReceiveHandler(TNotifyEvent Handler);
@@ -148,7 +146,7 @@ public:
   void __fastcall CWrite(const char * Data, int Length);
   void __fastcall CWrite(const char * Data, int Length);
   const UnicodeString & __fastcall GetStdError();
   const UnicodeString & __fastcall GetStdError();
   void __fastcall VerifyHostKey(UnicodeString Host, int Port,
   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 AskAlg(const UnicodeString AlgType, const UnicodeString AlgName);
   void __fastcall DisplayBanner(const UnicodeString & Banner);
   void __fastcall DisplayBanner(const UnicodeString & Banner);
   void __fastcall OldKeyfileWarning();
   void __fastcall OldKeyfileWarning();

+ 180 - 77
source/core/SessionData.cpp

@@ -41,8 +41,7 @@ const UnicodeString PuttyTelnetProtocol(L"telnet");
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 TDateTime __fastcall SecToDateTime(int Sec)
 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 ----------------------------------------------------
 //--- TSessionData ----------------------------------------------------
 __fastcall TSessionData::TSessionData(UnicodeString aName):
 __fastcall TSessionData::TSessionData(UnicodeString aName):
@@ -93,6 +92,7 @@ void __fastcall TSessionData::Default()
   SendBuf = DefaultSendBuf;
   SendBuf = DefaultSendBuf;
   SshSimple = true;
   SshSimple = true;
   HostKey = L"";
   HostKey = L"";
+  FOverrideCachedHostKey = true;
 
 
   ProxyMethod = ::pmNone;
   ProxyMethod = ::pmNone;
   ProxyHost = L"proxy";
   ProxyHost = L"proxy";
@@ -194,6 +194,7 @@ void __fastcall TSessionData::Default()
   Selected = false;
   Selected = false;
   FModified = false;
   FModified = false;
   FSource = ::ssNone;
   FSource = ::ssNone;
+  FSaveOnly = false;
 
 
   // add also to TSessionLog::AddStartupInfo()
   // add also to TSessionLog::AddStartupInfo()
 }
 }
@@ -214,6 +215,8 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(Ftps); \
   PROPERTY(Ftps); \
   PROPERTY(LocalDirectory); \
   PROPERTY(LocalDirectory); \
   PROPERTY(RemoteDirectory); \
   PROPERTY(RemoteDirectory); \
+  PROPERTY(Color); \
+  PROPERTY(SynchronizeBrowsing);
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 #define ADVANCED_PROPERTIES \
 #define ADVANCED_PROPERTIES \
   PROPERTY(PingInterval); \
   PROPERTY(PingInterval); \
@@ -234,7 +237,6 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(RekeyTime); \
   PROPERTY(RekeyTime); \
   PROPERTY(HostKey); \
   PROPERTY(HostKey); \
   \
   \
-  PROPERTY(SynchronizeBrowsing); \
   PROPERTY(UpdateDirectories); \
   PROPERTY(UpdateDirectories); \
   PROPERTY(CacheDirectories); \
   PROPERTY(CacheDirectories); \
   PROPERTY(CacheDirectoryChanges); \
   PROPERTY(CacheDirectoryChanges); \
@@ -298,8 +300,6 @@ void __fastcall TSessionData::NonPersistant()
     PROPERTY(SFTPBug[(TSftpBug)Index]); \
     PROPERTY(SFTPBug[(TSftpBug)Index]); \
   } \
   } \
   \
   \
-  PROPERTY(Color); \
-  \
   PROPERTY(Tunnel); \
   PROPERTY(Tunnel); \
   PROPERTY(TunnelHostName); \
   PROPERTY(TunnelHostName); \
   PROPERTY(TunnelPortNumber); \
   PROPERTY(TunnelPortNumber); \
@@ -324,23 +324,28 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(MinTlsVersion); \
   PROPERTY(MinTlsVersion); \
   PROPERTY(MaxTlsVersion); \
   PROPERTY(MaxTlsVersion); \
   \
   \
-  PROPERTY(IsWorkspace); \
-  PROPERTY(Link); \
-  \
   PROPERTY(CustomParam1); \
   PROPERTY(CustomParam1); \
   PROPERTY(CustomParam2);
   PROPERTY(CustomParam2);
+#define META_PROPERTIES \
+  PROPERTY(IsWorkspace); \
+  PROPERTY(Link);
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Assign(TPersistent * Source)
 void __fastcall TSessionData::Assign(TPersistent * Source)
 {
 {
   if (Source && Source->InheritsFrom(__classid(TSessionData)))
   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);
     PROPERTY(Name);
     BASE_PROPERTIES;
     BASE_PROPERTIES;
     ADVANCED_PROPERTIES;
     ADVANCED_PROPERTIES;
+    META_PROPERTIES;
     #undef PROPERTY
     #undef PROPERTY
-    FModified = ((TSessionData *)Source)->Modified;
-    FSource = ((TSessionData *)Source)->FSource;
+    FOverrideCachedHostKey = SourceData->FOverrideCachedHostKey;
+    FModified = SourceData->Modified;
+    FSource = SourceData->FSource;
+    FSaveOnly = SourceData->FSaveOnly;
   }
   }
   else
   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)
   if (!AdvancedOnly)
   {
   {
     BASE_PROPERTIES;
     BASE_PROPERTIES;
+    META_PROPERTIES;
   }
   }
   ADVANCED_PROPERTIES;
   ADVANCED_PROPERTIES;
   #undef PROPERTY
   #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)
 bool __fastcall TSessionData::IsInFolderOrWorkspace(UnicodeString AFolder)
@@ -367,6 +397,15 @@ bool __fastcall TSessionData::IsInFolderOrWorkspace(UnicodeString AFolder)
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & RewritePassword)
 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);
   PortNumber = Storage->ReadInteger(L"PortNumber", PortNumber);
   UserName = Storage->ReadString(L"UserName", UserName);
   UserName = Storage->ReadString(L"UserName", UserName);
   // must be loaded after UserName, because HostName may be in format user@host
   // 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)
 inline void __fastcall MoveStr(UnicodeString & Source, UnicodeString * Dest, int Count)
 {
 {
   if (Dest != NULL)
   if (Dest != NULL)
@@ -1312,12 +1371,39 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         Ftps = AFtps;
         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);
       UnicodeString RawUserName = CutToChar(UserInfo, L':', false);
       UserName = DecodeUrlChars(RawUserName);
       UserName = DecodeUrlChars(RawUserName);
 
 
       Password = DecodeUrlChars(UserInfo);
       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)
       if (MaskedUrl != NULL)
       {
       {
@@ -1373,6 +1459,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         Options->FindSwitch(L"certificate", Value))
         Options->FindSwitch(L"certificate", Value))
     {
     {
       HostKey = Value;
       HostKey = Value;
+      FOverrideCachedHostKey = true;
     }
     }
     FtpPasvMode = Options->SwitchValue(L"passive", FtpPasvMode);
     FtpPasvMode = Options->SwitchValue(L"passive", FtpPasvMode);
     if (Options->FindSwitch(L"implicit"))
     if (Options->FindSwitch(L"implicit"))
@@ -1582,11 +1669,15 @@ void __fastcall TSessionData::SetUnsetNationalVars(bool value)
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetUserName(UnicodeString 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()
 UnicodeString __fastcall TSessionData::GetUserNameExpanded()
@@ -2241,11 +2332,15 @@ void __fastcall TSessionData::SetTunnelPortNumber(int value)
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetTunnelUserName(UnicodeString 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)
 void __fastcall TSessionData::SetTunnelPassword(UnicodeString avalue)
@@ -2634,7 +2729,7 @@ void __fastcall TStoredSessionList::ImportLevelFromFilezilla(_di_IXMLNode Node,
     _di_IXMLNode ChildNode = Node->ChildNodes->Get(Index);
     _di_IXMLNode ChildNode = Node->ChildNodes->Get(Index);
     if (ChildNode->NodeName == L"Server")
     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->Assign(DefaultSettings);
       SessionData->ImportFromFilezilla(ChildNode, Path);
       SessionData->ImportFromFilezilla(ChildNode, Path);
       Add(SessionData.release());
       Add(SessionData.release());
@@ -2761,66 +2856,72 @@ void __fastcall TStoredSessionList::UpdateStaticUsage()
   int Color = 0;
   int Color = 0;
   bool Folders = false;
   bool Folders = false;
   bool Workspaces = 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++)
   for (int Index = 0; Index < Count; Index++)
   {
   {
     TSessionData * Data = Sessions[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"StoredSessionsCountPassword", Password);
   Configuration->Usage->Set(L"StoredSessionsCountColor", Color);
   Configuration->Usage->Set(L"StoredSessionsCountColor", Color);
   Configuration->Usage->Set(L"StoredSessionsCountAdvanced", Advanced);
   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
   // actually default might be true, see below for when the default is actually used
   bool CustomDefaultStoredSession = false;
   bool CustomDefaultStoredSession = false;
@@ -3034,7 +3137,7 @@ void __fastcall TStoredSessionList::GetFolderOrWorkspace(const UnicodeString & N
 TStrings * __fastcall TStoredSessionList::GetFolderOrWorkspaceList(
 TStrings * __fastcall TStoredSessionList::GetFolderOrWorkspaceList(
   const UnicodeString & Name)
   const UnicodeString & Name)
 {
 {
-  std::auto_ptr<TStringList> Result(new TStringList());
+  std::unique_ptr<TStringList> Result(new TStringList());
 
 
   for (int Index = 0; (Index < Count); Index++)
   for (int Index = 0; (Index < Count); Index++)
   {
   {
@@ -3052,7 +3155,7 @@ TStrings * __fastcall TStoredSessionList::GetFolderOrWorkspaceList(
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 TStrings * __fastcall TStoredSessionList::GetWorkspaces()
 TStrings * __fastcall TStoredSessionList::GetWorkspaces()
 {
 {
-  std::auto_ptr<TStringList> Result(new TStringList());
+  std::unique_ptr<TStringList> Result(new TStringList());
   Result->Sorted = true;
   Result->Sorted = true;
   Result->Duplicates = dupIgnore;
   Result->Duplicates = dupIgnore;
   Result->CaseSensitive = false;
   Result->CaseSensitive = false;

+ 7 - 0
source/core/SessionData.h

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

+ 9 - 1
source/core/SessionInfo.cpp

@@ -893,7 +893,8 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
   BeginUpdate();
   BeginUpdate();
   try
   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)
     if (Data == NULL)
     {
     {
       AddSeparator();
       AddSeparator();
@@ -919,6 +920,10 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       ADF(L"Process ID: %d", (int(GetCurrentProcessId())));
       ADF(L"Process ID: %d", (int(GetCurrentProcessId())));
       ADF(L"Command-line: %s", (CmdLine));
       ADF(L"Command-line: %s", (CmdLine));
       ADF(L"Time zone: %s", (GetTimeZoneLogString()));
       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())));
       ADF(L"Login time: %s", (FormatDateTime(L"dddddd tt", Now())));
       AddSeparator();
       AddSeparator();
     }
     }
@@ -969,6 +974,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
           ADF(L"Local command: %s", (Data->ProxyLocalCommand));
           ADF(L"Local command: %s", (Data->ProxyLocalCommand));
         }
         }
       }
       }
+      ADF(L"Send buffer: %d", (Data->SendBuf));
       wchar_t const * BugFlags = L"+-A";
       wchar_t const * BugFlags = L"+-A";
       if (Data->UsesSsh)
       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"");
           Bugs += UnicodeString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?L",":L"");
         }
         }
         ADF(L"SSH Bugs: %s", (Bugs));
         ADF(L"SSH Bugs: %s", (Bugs));
+        ADF(L"Simple channel: %s", (BooleanToEngStr(Data->SshSimple)));
         ADF(L"Return code variable: %s; Lookup user groups: %s",
         ADF(L"Return code variable: %s; Lookup user groups: %s",
           ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
           ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
            BugFlags[Data->LookupUserGroups]));
            BugFlags[Data->LookupUserGroups]));
@@ -1069,6 +1076,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
     }
     }
 
 
     #undef ADF
     #undef ADF
+    #undef ADSTR
   }
   }
   __finally
   __finally
   {
   {

+ 1 - 1
source/core/SessionInfo.h

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

+ 55 - 23
source/core/SftpFileSystem.cpp

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

+ 1 - 2
source/core/SftpFileSystem.h

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

+ 120 - 51
source/core/Terminal.cpp

@@ -508,7 +508,6 @@ __fastcall TTerminal::TTerminal(TSessionData * SessionData,
   FTunnelUI = NULL;
   FTunnelUI = NULL;
   FTunnelOpening = false;
   FTunnelOpening = false;
   FCallbackGuard = NULL;
   FCallbackGuard = NULL;
-  FEnableSecureShellUsage = false;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TTerminal::~TTerminal()
 __fastcall TTerminal::~TTerminal()
@@ -604,16 +603,12 @@ void __fastcall TTerminal::RecryptPasswords()
   FTunnelPassword = EncryptPassword(DecryptPassword(FTunnelPassword));
   FTunnelPassword = EncryptPassword(DecryptPassword(FTunnelPassword));
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::IsAbsolutePath(const UnicodeString Path)
-{
-  return !Path.IsEmpty() && Path[1] == L'/';
-}
-//---------------------------------------------------------------------------
 UnicodeString __fastcall TTerminal::ExpandFileName(UnicodeString Path,
 UnicodeString __fastcall TTerminal::ExpandFileName(UnicodeString Path,
   const UnicodeString BasePath)
   const UnicodeString BasePath)
 {
 {
+  // replace this by AbsolutePath()
   Path = UnixExcludeTrailingBackslash(Path);
   Path = UnixExcludeTrailingBackslash(Path);
-  if (!IsAbsolutePath(Path) && !BasePath.IsEmpty())
+  if (!UnixIsAbsolutePath(Path) && !BasePath.IsEmpty())
   {
   {
     // TODO: Handle more complicated cases like "../../xxx"
     // TODO: Handle more complicated cases like "../../xxx"
     if (Path == L"..")
     if (Path == L"..")
@@ -732,14 +727,6 @@ void __fastcall TTerminal::Open()
                 FSecureShell = new TSecureShell(this, FSessionData, Log, Configuration);
                 FSecureShell = new TSecureShell(this, FSessionData, Log, Configuration);
                 try
                 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
                   // there will be only one channel in this session
                   FSecureShell->Simple = true;
                   FSecureShell->Simple = true;
                   FSecureShell->Open();
                   FSecureShell->Open();
@@ -811,6 +798,12 @@ void __fastcall TTerminal::Open()
 
 
         DoStartup();
         DoStartup();
 
 
+        if (FCollectFileSystemUsage)
+        {
+          FFileSystem->CollectUsage();
+          FCollectFileSystemUsage = false;
+        }
+
         DoInformation(LoadStr(STATUS_READY), true);
         DoInformation(LoadStr(STATUS_READY), true);
         FStatus = ssOpened;
         FStatus = ssOpened;
       }
       }
@@ -1115,7 +1108,7 @@ unsigned int __fastcall TTerminal::QueryUserException(const UnicodeString Query,
     {
     {
       if (!ExMessage.IsEmpty() && !Query.IsEmpty())
       if (!ExMessage.IsEmpty() && !Query.IsEmpty())
       {
       {
-        MoreMessages->Add(ExMessage);
+        MoreMessages->Add(UnformatMessage(ExMessage));
       }
       }
 
 
       ExtException * EE = dynamic_cast<ExtException*>(E);
       ExtException * EE = dynamic_cast<ExtException*>(E);
@@ -2824,10 +2817,12 @@ TUsableCopyParamAttrs __fastcall TTerminal::UsableCopyParamAttrs(int Params)
     FLAGMASK(FLAGSET(Params, cpDelete), cpaNoClearArchive) |
     FLAGMASK(FLAGSET(Params, cpDelete), cpaNoClearArchive) |
     FLAGMASK(!IsCapable[fcIgnorePermErrors], cpaNoIgnorePermErrors);
     FLAGMASK(!IsCapable[fcIgnorePermErrors], cpaNoIgnorePermErrors);
   Result.Download = Result.General | cpaNoClearArchive | cpaNoRights |
   Result.Download = Result.General | cpaNoClearArchive | cpaNoRights |
-    cpaNoIgnorePermErrors;
+    cpaNoIgnorePermErrors | cpaNoRemoveCtrlZ | cpaNoRemoveBOM;
   Result.Upload = Result.General | cpaNoPreserveReadOnly |
   Result.Upload = Result.General | cpaNoPreserveReadOnly |
     FLAGMASK(!IsCapable[fcModeChangingUpload], cpaNoRights) |
     FLAGMASK(!IsCapable[fcModeChangingUpload], cpaNoRights) |
-    FLAGMASK(!IsCapable[fcPreservingTimestampUpload], cpaNoPreserveTime);
+    FLAGMASK(!IsCapable[fcPreservingTimestampUpload], cpaNoPreserveTime) |
+    FLAGMASK(!IsCapable[fcRemoveCtrlZUpload], cpaNoRemoveCtrlZ) |
+    FLAGMASK(!IsCapable[fcRemoveBOMUpload], cpaNoRemoveBOM);
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -2930,6 +2925,10 @@ bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, int Params)
 void __fastcall TTerminal::DeleteLocalFile(UnicodeString FileName,
 void __fastcall TTerminal::DeleteLocalFile(UnicodeString FileName,
   const TRemoteFile * /*File*/, void * Params)
   const TRemoteFile * /*File*/, void * Params)
 {
 {
+  if ((OperationProgress != NULL) && (OperationProgress->Operation == foDelete))
+  {
+    OperationProgress->SetFile(FileName);
+  }
   if (OnDeleteLocalFile == NULL)
   if (OnDeleteLocalFile == NULL)
   {
   {
     if (!RecursiveDeleteFile(FileName, false))
     if (!RecursiveDeleteFile(FileName, false))
@@ -3174,9 +3173,16 @@ void __fastcall TTerminal::CalculateFileSize(UnicodeString FileName,
     {
     {
       if (!File->IsSymLink)
       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
       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,
   __int64 & Size, int Params, const TCopyParamType * CopyParam,
-  TCalculateSizeStats * Stats)
+  bool AllowDirs, TCalculateSizeStats * Stats)
 {
 {
   TCalculateSizeParams Param;
   TCalculateSizeParams Param;
   Param.Size = 0;
   Param.Size = 0;
   Param.Params = Params;
   Param.Params = Params;
   Param.CopyParam = CopyParam;
   Param.CopyParam = CopyParam;
   Param.Stats = Stats;
   Param.Stats = Stats;
+  Param.AllowDirs = AllowDirs;
+  Param.Result = true;
   ProcessFiles(FileList, foCalculateSize, CalculateFileSize, &Param);
   ProcessFiles(FileList, foCalculateSize, CalculateFileSize, &Param);
   Size = Param.Size;
   Size = Param.Size;
+  return Param.Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::CalculateFilesChecksum(const UnicodeString & Alg,
 void __fastcall TTerminal::CalculateFilesChecksum(const UnicodeString & Alg,
@@ -3282,7 +3291,8 @@ void __fastcall TTerminal::RenameFile(const TRemoteFile * File,
         QuestionFmt = LoadStr(FILE_OVERWRITE);
         QuestionFmt = LoadStr(FILE_OVERWRITE);
       }
       }
       TQueryParams Params(qpNeverAskAgainCheck);
       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);
         qaYes | qaNo, &Params);
       if (Result == qaNeverAskAgain)
       if (Result == qaNeverAskAgain)
       {
       {
@@ -3769,7 +3779,7 @@ bool __fastcall TTerminal::DoCreateLocalFile(const UnicodeString FileName,
             SUSPEND_OPERATION
             SUSPEND_OPERATION
             (
             (
               Answer = QueryUser(
               Answer = QueryUser(
-                FMTLOAD(READ_ONLY_OVERWRITE, (FileName)), NULL,
+                MainInstructions(FMTLOAD(READ_ONLY_OVERWRITE, (FileName))), NULL,
                 qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll, 0);
                 qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll, 0);
             );
             );
             switch (Answer) {
             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);
   TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
   TOnceDoneOperation OnceDoneOperation = odoIdle;
   TOnceDoneOperation OnceDoneOperation = odoIdle;
   OperationProgress.Start(foCalculateSize, osLocal, FileList->Count);
   OperationProgress.Start(foCalculateSize, osLocal, FileList->Count);
@@ -4032,14 +4043,21 @@ void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
 
 
     assert(!FOperationProgress);
     assert(!FOperationProgress);
     FOperationProgress = &OperationProgress;
     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];
       UnicodeString FileName = FileList->Strings[Index];
+      TSearchRec Rec;
       if (FileSearchRec(FileName, 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);
     CloseOnCompletion(OnceDoneOperation);
   }
   }
+  return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 struct TSynchronizeFileData
 struct TSynchronizeFileData
@@ -4968,14 +4987,13 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
 
 
   try
   try
   {
   {
-
     __int64 Size;
     __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);
     TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
@@ -4984,7 +5002,7 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
     FOperationProgress = &OperationProgress;
     FOperationProgress = &OperationProgress;
     try
     try
     {
     {
-      if (CopyParam->CalculateSize)
+      if (CalculatedSize)
       {
       {
         OperationProgress.SetTotalSize(Size);
         OperationProgress.SetTotalSize(Size);
       }
       }
@@ -5063,20 +5081,21 @@ bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
       bool TotalSizeKnown = false;
       bool TotalSizeKnown = false;
       TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
       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;
           TotalSizeKnown = true;
         }
         }
-        __finally
-        {
-          ExceptionOnFail = false;
-        }
+      }
+      __finally
+      {
+        ExceptionOnFail = false;
       }
       }
 
 
       OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
       OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
@@ -5152,9 +5171,59 @@ void __fastcall TTerminal::ReflectSettings()
   // also FTunnelLog ?
   // 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,
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,

+ 9 - 6
source/core/Terminal.h

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

+ 19 - 17
source/core/WebDAVFileSystem.cpp

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

+ 1 - 0
source/core/WebDAVFileSystem.h

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

+ 2 - 2
source/dragext/DragExt.cpp

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

+ 8 - 20
source/filezilla/AsyncSocketEx.cpp

@@ -288,11 +288,13 @@ public:
 	//Processes event notifications sent by the sockets or the layers
 	//Processes event notifications sent by the sockets or the layers
 	static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 	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)
 		if (message>=WM_SOCKETEX_NOTIFY)
 		{
 		{
-			//Verify parameters
-			ASSERT(hWnd);
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
 			ASSERT(pWnd);
 			ASSERT(pWnd);
 			
 			
 			if (message<static_cast<UINT>(WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize)) //Index is within socket storage
 			if (message<static_cast<UINT>(WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize)) //Index is within socket storage
@@ -499,10 +501,6 @@ public:
 #ifndef NOLAYERS
 #ifndef NOLAYERS
 		else if (message == WM_USER) //Notification event sent by a layer
 		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);
 			ASSERT(pWnd);
 			
 			
 			if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
 			if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
@@ -642,6 +640,7 @@ public:
 #endif //NOLAYERS
 #endif //NOLAYERS
 		else if (message == WM_USER+1)
 		else if (message == WM_USER+1)
 		{
 		{
+			ASSERT(pWnd);
 			// WSAAsyncGetHostByName reply
 			// WSAAsyncGetHostByName reply
 
 
 			// Verify parameters
 			// Verify parameters
@@ -686,15 +685,7 @@ public:
 		}
 		}
 		else if (message == WM_USER + 2)
 		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
 			if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
 				return 0;
 				return 0;
 			
 			
@@ -709,12 +700,9 @@ public:
 		}
 		}
 		else if (message == WM_TIMER)
 		else if (message == WM_TIMER)
 		{
 		{
+			ASSERT(pWnd);
 			if (wParam != 1)
 			if (wParam != 1)
 				return 0;
 				return 0;
-			
-			ASSERT(hWnd);
-			CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)GetWindowLongPtr(hWnd, GWL_USERDATA);
-			ASSERT(pWnd);
 
 
 			if (pWnd->m_pThreadData->layerCloseNotify.empty())
 			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 (!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())
 					if (ShutDownComplete())
 						TriggerEvent(FD_CLOSE, 0, TRUE);
 						TriggerEvent(FD_CLOSE, 0, TRUE);
@@ -616,7 +617,9 @@ void CAsyncSslSocketLayer::OnReceive(int nErrorCode)
 		TriggerEvents();
 		TriggerEvents();
 	}
 	}
 	else
 	else
+	{
 		TriggerEvent(FD_READ, nErrorCode, TRUE);
 		TriggerEvent(FD_READ, nErrorCode, TRUE);
+	}
 }
 }
 
 
 void CAsyncSslSocketLayer::OnSend(int nErrorCode)
 void CAsyncSslSocketLayer::OnSend(int nErrorCode)
@@ -660,7 +663,7 @@ void CAsyncSslSocketLayer::OnSend(int nErrorCode)
 
 
 		//Send the data waiting in the network bio
 		//Send the data waiting in the network bio
 		char buffer[16384];
 		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);
 		int numread = pBIO_read(m_nbio, buffer, len);
 		if (numread <= 0)
 		if (numread <= 0)
 			m_mayTriggerWrite = true;
 			m_mayTriggerWrite = true;
@@ -862,7 +865,8 @@ int CAsyncSslSocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags)
 		}
 		}
 		if (m_nNetworkError)
 		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;
 				m_mayTriggerReadUp = true;
 				TriggerEvents();
 				TriggerEvents();
@@ -880,7 +884,8 @@ int CAsyncSslSocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags)
 		{
 		{
 			return 0;
 			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)
 			if (GetLayerState() == closed)
 			{
 			{
@@ -1077,7 +1082,11 @@ int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode,
 		{
 		{
 			USES_CONVERSION;
 			USES_CONVERSION;
 			pSSL_CTX_set_verify(m_ssl_ctx, SSL_VERIFY_PEER, verify_callback);
 			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);
 		MASK_TLS_VERSION(SSL_VERSION_TLS12, SSL_OP_NO_TLSv1_2);
 	pSSL_ctrl(m_ssl, SSL_CTRL_OPTIONS, options, NULL);
 	pSSL_ctrl(m_ssl, SSL_CTRL_OPTIONS, options, NULL);
 
 
+	LogSocketMessage(FZ_LOG_INFO, _T("Loading system certificates"));
+	LoadSslWindowsSystemCertificateStore(m_ssl_ctx);
+
 	//Init SSL connection
 	//Init SSL connection
 	void *ssl_sessionid = NULL;
 	void *ssl_sessionid = NULL;
 	{
 	{
@@ -1386,7 +1398,8 @@ BOOL CAsyncSslSocketLayer::ShutDownComplete()
 		numread = pBIO_read(m_sslbio, buffer, 1000);
 		numread = pBIO_read(m_sslbio, buffer, 1000);
 	} while (numread > 0);
 	} while (numread > 0);
 
 
-	if (pBIO_ctrl_pending(m_nbio))
+	size_t pending = pBIO_ctrl_pending(m_nbio);
+	if (pending)
 	{
 	{
 		return FALSE;
 		return FALSE;
 	}
 	}
@@ -1398,6 +1411,7 @@ BOOL CAsyncSslSocketLayer::ShutDownComplete()
 
 
 void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int ret)
 void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int ret)
 {
 {
+	USES_CONVERSION;
 	CAsyncSslSocketLayer *pLayer = 0;
 	CAsyncSslSocketLayer *pLayer = 0;
 	m_sCriticalSection.Lock();
 	m_sCriticalSection.Lock();
 	t_SslLayerList *cur = m_pSslLayerList;
 	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);
 		const char* desc = pSSL_alert_desc_string_long(ret);
 
 
 		// Don't send close notify warning
 		// 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;
 	m_onCloseCalled = true;
 	if (m_bUseSSL && pBIO_ctrl)
 	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();
 			TriggerEvents();
 		}
 		}
@@ -2347,7 +2365,8 @@ int CAsyncSslSocketLayer::SendRaw(const void* lpBuf, int nBufLen, int nFlags)
 
 
 void CAsyncSslSocketLayer::TriggerEvents()
 void CAsyncSslSocketLayer::TriggerEvents()
 {
 {
-	if (pBIO_ctrl_pending(m_nbio) > 0)
+	size_t pending = pBIO_ctrl_pending(m_nbio);
+	if (pending > 0)
 	{
 	{
 		if (m_mayTriggerWrite)
 		if (m_mayTriggerWrite)
 		{
 		{
@@ -2374,7 +2393,8 @@ void CAsyncSslSocketLayer::TriggerEvents()
 	}
 	}
 	else
 	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;
 			m_mayTriggerRead = false;
 			TriggerEvent(FD_READ, 0);
 			TriggerEvent(FD_READ, 0);
@@ -2406,3 +2426,39 @@ int CAsyncSslSocketLayer::pem_passwd_cb(char *buf, int size, int rwflag, void *u
 
 
 	return len;
 	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_TLS11 11
 #define SSL_VERSION_TLS12 12
 #define SSL_VERSION_TLS12 12
 
 
+void __fastcall LoadSslWindowsSystemCertificateStore(SSL_CTX * Ctx);
+
 #endif // ASYNCSSLSOCKETLEAYER_INCLUDED
 #endif // ASYNCSSLSOCKETLEAYER_INCLUDED

+ 1 - 0
source/filezilla/ControlSocket.h

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

+ 10 - 0
source/filezilla/FileZillaApi.cpp

@@ -565,6 +565,16 @@ bool CFileZillaApi::UsingMlsd()
 	return m_pMainThread->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()
 std::string CFileZillaApi::GetTlsVersionStr()
 {
 {
 	//Check if call allowed
 	//Check if call allowed

+ 1 - 0
source/filezilla/FileZillaApi.h

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

+ 14 - 11
source/filezilla/FileZillaIntf.cpp

@@ -10,8 +10,6 @@
 #pragma comment(lib, "uafxcwd.lib")
 #pragma comment(lib, "uafxcwd.lib")
 #endif
 #endif
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
-//---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TFileZillaIntf::Initialize()
 void __fastcall TFileZillaIntf::Initialize()
@@ -78,7 +76,7 @@ void __fastcall TFileZillaIntf::Destroying()
 bool __fastcall TFileZillaIntf::SetCurrentPath(const wchar_t * APath)
 bool __fastcall TFileZillaIntf::SetCurrentPath(const wchar_t * APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->SetCurrentPath(Path), L"setcurrentpath");
   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)
 bool __fastcall TFileZillaIntf::MakeDir(const wchar_t* APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->MakeDir(Path), L"makedir");
   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)
   const wchar_t* APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->Chmod(Value, FileName, Path), L"chmod");
   return Check(FFileZillaApi->Chmod(Value, FileName, Path), L"chmod");
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 bool __fastcall TFileZillaIntf::Delete(const wchar_t* FileName, const wchar_t* APath)
 bool __fastcall TFileZillaIntf::Delete(const wchar_t* FileName, const wchar_t* APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->Delete(FileName, Path), L"delete");
   return Check(FFileZillaApi->Delete(FileName, Path), L"delete");
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 bool __fastcall TFileZillaIntf::RemoveDir(const wchar_t* FileName, const wchar_t* APath)
 bool __fastcall TFileZillaIntf::RemoveDir(const wchar_t* FileName, const wchar_t* APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->RemoveDir(FileName, Path), L"removedir");
   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)
   const wchar_t* NewName, const wchar_t* APath, const wchar_t* ANewPath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   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");
   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)
 bool __fastcall TFileZillaIntf::List(const wchar_t * APath)
 {
 {
   ASSERT(FFileZillaApi != NULL);
   ASSERT(FFileZillaApi != NULL);
-  CServerPath Path(APath, FServer->nServerType);
+  CServerPath Path(APath);
   return Check(FFileZillaApi->List(Path), L"list");
   return Check(FFileZillaApi->List(Path), L"list");
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -240,7 +238,7 @@ bool __fastcall TFileZillaIntf::FileTransfer(const wchar_t * LocalFile,
 
 
   Transfer.localfile = LocalFile;
   Transfer.localfile = LocalFile;
   Transfer.remotefile = RemoteFile;
   Transfer.remotefile = RemoteFile;
-  Transfer.remotepath = CServerPath(RemotePath, FServer->nServerType);
+  Transfer.remotepath = CServerPath(RemotePath);
   Transfer.get = Get;
   Transfer.get = Get;
   Transfer.size = Size;
   Transfer.size = Size;
   Transfer.server = *FServer;
   Transfer.server = *FServer;
@@ -524,6 +522,11 @@ bool __fastcall TFileZillaIntf::UsingMlsd()
   return FFileZillaApi->UsingMlsd();
   return FFileZillaApi->UsingMlsd();
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+bool __fastcall TFileZillaIntf::UsingUtf8()
+{
+  return FFileZillaApi->UsingUtf8();
+}
+//---------------------------------------------------------------------------
 std::string __fastcall TFileZillaIntf::GetTlsVersionStr()
 std::string __fastcall TFileZillaIntf::GetTlsVersionStr()
 {
 {
   return FFileZillaApi->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 GetCurrentPath(wchar_t * Path, size_t MaxLen);
 
 
   bool __fastcall UsingMlsd();
   bool __fastcall UsingMlsd();
+  bool __fastcall UsingUtf8();
   std::string __fastcall GetTlsVersionStr();
   std::string __fastcall GetTlsVersionStr();
   std::string __fastcall GetCipherName();
   std::string __fastcall GetCipherName();
 
 

+ 8 - 4
source/filezilla/FtpControlSocket.cpp

@@ -37,7 +37,6 @@
 #include "filezillaapi.h"
 #include "filezillaapi.h"
 #include "misc/utf8.h"
 #include "misc/utf8.h"
 #ifdef MPEXT
 #ifdef MPEXT
-#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
 #endif
 #endif
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG
@@ -300,10 +299,10 @@ bool CFtpControlSocket::InitConnect()
 		{
 		{
 			filename = filename.Left(pos + 1);
 			filename = filename.Left(pos + 1);
 			filename += _T("cacert.pem");
 			filename += _T("cacert.pem");
-			m_pSslLayer->SetCertStorage(filename);
 		}
 		}
 		else
 		else
 			filename = _MPT("cacert.pem");
 			filename = _MPT("cacert.pem");
+		m_pSslLayer->SetCertStorage(filename);
 	}
 	}
 #endif
 #endif
 
 
@@ -1523,6 +1522,11 @@ bool CFtpControlSocket::UsingMlsd()
 		 (m_serverCapabilities.GetCapability(mlsd_command) == yes));
 		 (m_serverCapabilities.GetCapability(mlsd_command) == yes));
 }
 }
 
 
+bool CFtpControlSocket::UsingUtf8()
+{
+	return m_bUTF8;
+}
+
 std::string CFtpControlSocket::GetTlsVersionStr()
 std::string CFtpControlSocket::GetTlsVersionStr()
 {
 {
 	if (m_pSslLayer != NULL)
 	if (m_pSslLayer != NULL)
@@ -6304,8 +6308,8 @@ bool CFtpControlSocket::CheckForcePasvIp(CString & host)
 		default: // auto
 		default: // auto
 			if (!GetPeerName(ahost, tmpPort))
 			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))
 			else if (!IsRoutableAddress(host) && IsRoutableAddress(ahost))
 			{
 			{

+ 1 - 0
source/filezilla/FtpControlSocket.h

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

+ 1 - 1
source/filezilla/FtpListResult.cpp

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

+ 7 - 0
source/filezilla/MainThread.cpp

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

+ 1 - 0
source/filezilla/MainThread.h

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

+ 13 - 1
source/filezilla/TransferSocket.cpp

@@ -463,7 +463,19 @@ void CTransferSocket::OnConnect(int nErrorCode)
 			SetSockOpt(SO_SNDBUF, &value, sizeof(value));
 			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;
 		m_nTransferState = STATE_STARTED;
 		
 		

+ 2 - 0
source/filezilla/stdafx.h

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

+ 4 - 7
source/forms/Authenticate.cpp

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

+ 2 - 3
source/forms/Authenticate.h

@@ -65,9 +65,8 @@ protected:
   virtual void __fastcall Dispatch(void * AMessage);
   virtual void __fastcall Dispatch(void * AMessage);
   void __fastcall WMNCCreate(TWMNCCreate & Message);
   void __fastcall WMNCCreate(TWMNCCreate & Message);
   TLabel * __fastcall GenerateLabel(int Current, UnicodeString Caption);
   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 DoCancel();
   void __fastcall AdjustLogView();
   void __fastcall AdjustLogView();
 
 

+ 39 - 9
source/forms/Console.dfm

@@ -9,7 +9,7 @@ object ConsoleDialog: TConsoleDialog
   ClientWidth = 551
   ClientWidth = 551
   Color = clBtnFace
   Color = clBtnFace
   Constraints.MinHeight = 250
   Constraints.MinHeight = 250
-  Constraints.MinWidth = 380
+  Constraints.MinWidth = 420
   ParentFont = True
   ParentFont = True
   Icon.Data = {
   Icon.Data = {
     0000010001001010000001002000680400001600000028000000100000002000
     0000010001001010000001002000680400001600000028000000100000002000
@@ -64,7 +64,7 @@ object ConsoleDialog: TConsoleDialog
     Shape = bsBottomLine
     Shape = bsBottomLine
   end
   end
   object Label1: TLabel
   object Label1: TLabel
-    Left = 13
+    Left = 51
     Top = 13
     Top = 13
     Width = 78
     Width = 78
     Height = 13
     Height = 13
@@ -72,25 +72,25 @@ object ConsoleDialog: TConsoleDialog
     FocusControl = CommandEdit
     FocusControl = CommandEdit
   end
   end
   object Label2: TLabel
   object Label2: TLabel
-    Left = 13
+    Left = 51
     Top = 56
     Top = 56
     Width = 87
     Width = 87
     Height = 13
     Height = 13
     Caption = 'Current directory:'
     Caption = 'Current directory:'
   end
   end
   object Label4: TLabel
   object Label4: TLabel
-    Left = 13
+    Left = 51
     Top = 34
     Top = 34
-    Width = 452
+    Width = 414
     Height = 13
     Height = 13
     Anchors = [akLeft, akTop, akRight]
     Anchors = [akLeft, akTop, akRight]
     AutoSize = False
     AutoSize = False
     Caption = 'Do not execute commands that require user-input or data transfer'
     Caption = 'Do not execute commands that require user-input or data transfer'
   end
   end
   object DirectoryLabel: TPathLabel
   object DirectoryLabel: TPathLabel
-    Left = 120
+    Left = 158
     Top = 56
     Top = 56
-    Width = 337
+    Width = 299
     Height = 13
     Height = 13
     IndentHorizontal = 0
     IndentHorizontal = 0
     IndentVertical = 0
     IndentVertical = 0
@@ -98,6 +98,36 @@ object ConsoleDialog: TConsoleDialog
     Anchors = [akLeft, akTop, akRight]
     Anchors = [akLeft, akTop, akRight]
     AutoSize = False
     AutoSize = False
   end
   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
   object OutputMemo: TMemo
     Left = 0
     Left = 0
     Top = 78
     Top = 78
@@ -125,9 +155,9 @@ object ConsoleDialog: TConsoleDialog
     TabOrder = 2
     TabOrder = 2
   end
   end
   object CommandEdit: THistoryComboBox
   object CommandEdit: THistoryComboBox
-    Left = 120
+    Left = 158
     Top = 9
     Top = 9
-    Width = 251
+    Width = 213
     Height = 21
     Height = 21
     AutoComplete = False
     AutoComplete = False
     Anchors = [akLeft, akTop, akRight]
     Anchors = [akLeft, akTop, akRight]

+ 2 - 0
source/forms/Console.h

@@ -16,6 +16,7 @@
 #include "WinInterface.h"
 #include "WinInterface.h"
 #include <Terminal.h>
 #include <Terminal.h>
 #include "PngImageList.hpp"
 #include "PngImageList.hpp"
+#include <Vcl.Imaging.pngimage.hpp>
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 class TConsoleDialog : public TForm
 class TConsoleDialog : public TForm
 {
 {
@@ -40,6 +41,7 @@ __published:
   TEditCopy *EditCopy;
   TEditCopy *EditCopy;
   TEditSelectAll *EditSelectAll;
   TEditSelectAll *EditSelectAll;
   TAction *AdjustWindow;
   TAction *AdjustWindow;
+  TImage *Image;
   void __fastcall ExecuteButtonClick(TObject *Sender);
   void __fastcall ExecuteButtonClick(TObject *Sender);
   void __fastcall CommandEditChange(TObject *Sender);
   void __fastcall CommandEditChange(TObject *Sender);
   void __fastcall HelpButtonClick(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);
       UnicodeString Drive = ExtractFileDrive(Dir);
       if (!DirectoryExists(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)
               qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel)
         {
         {
           if (!ForceDirectories(Dir))
           if (!ForceDirectories(Dir))

+ 10 - 0
source/forms/CopyParams.cpp

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

+ 11 - 2
source/forms/CopyParams.dfm

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

+ 1 - 0
source/forms/CopyParams.h

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

+ 40 - 13
source/forms/Custom.cpp

@@ -12,6 +12,8 @@
 #include <HelpWin.h>
 #include <HelpWin.h>
 #include <CoreMain.h>
 #include <CoreMain.h>
 #include <PasTools.hpp>
 #include <PasTools.hpp>
+#include <ProgParams.h>
+#include <Tools.h>
 
 
 #include "Custom.h"
 #include "Custom.h"
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
@@ -189,9 +191,11 @@ void __fastcall TCustomDialog::AddButtonControl(TButtonControl * Control)
 class TSaveSessionDialog : public TCustomDialog
 class TSaveSessionDialog : public TCustomDialog
 {
 {
 public:
 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:
 protected:
   virtual void __fastcall DoValidate();
   virtual void __fastcall DoValidate();
@@ -202,14 +206,19 @@ private:
   TEdit * SessionNameEdit;
   TEdit * SessionNameEdit;
   TComboBox * FolderCombo;
   TComboBox * FolderCombo;
   TCheckBox * SavePasswordCheck;
   TCheckBox * SavePasswordCheck;
+  TCheckBox * CreateShortcutCheck;
   UnicodeString FRootFolder;
   UnicodeString FRootFolder;
 
 
   UnicodeString __fastcall GetSessionName();
   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)
   TCustomDialog(HELP_SESSION_SAVE)
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TSaveSessionDialog::Init(bool CanSavePassword, bool NotRecommendedSavingPassword)
 {
 {
   Caption = LoadStr(SAVE_SESSION_CAPTION);
   Caption = LoadStr(SAVE_SESSION_CAPTION);
 
 
@@ -248,12 +257,18 @@ __fastcall TSaveSessionDialog::TSaveSessionDialog(
       (CustomWinConfiguration->UseMasterPassword ? SAVE_SESSION_PASSWORD_MASTER : SAVE_SESSION_PASSWORD_RECOMMENDED));
       (CustomWinConfiguration->UseMasterPassword ? SAVE_SESSION_PASSWORD_MASTER : SAVE_SESSION_PASSWORD_RECOMMENDED));
   AddButtonControl(SavePasswordCheck);
   AddButtonControl(SavePasswordCheck);
 
 
+  CreateShortcutCheck = new TCheckBox(this);
+  CreateShortcutCheck->Caption = LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT);
+  AddButtonControl(CreateShortcutCheck);
+
   EnableControl(SavePasswordCheck, CanSavePassword);
   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);
   SessionNameEdit->Text = TSessionData::ExtractLocalName(SessionName);
   UnicodeString Folder = TSessionData::ExtractFolderName(SessionName);
   UnicodeString Folder = TSessionData::ExtractFolderName(SessionName);
   if (Folder.IsEmpty())
   if (Folder.IsEmpty())
@@ -265,11 +280,13 @@ bool __fastcall TSaveSessionDialog::Execute(UnicodeString & SessionName, bool &
     FolderCombo->Text = Folder;
     FolderCombo->Text = Folder;
   }
   }
   SavePasswordCheck->Checked = SavePassword;
   SavePasswordCheck->Checked = SavePassword;
+  CreateShortcutCheck->Checked = CreateShortcut;
   bool Result = TCustomDialog::Execute();
   bool Result = TCustomDialog::Execute();
   if (Result)
   if (Result)
   {
   {
     SessionName = GetSessionName();
     SessionName = GetSessionName();
     SavePassword = SavePasswordCheck->Checked;
     SavePassword = SavePasswordCheck->Checked;
+    CreateShortcut = CreateShortcutCheck->Checked;
   }
   }
   return Result;
   return Result;
 }
 }
@@ -336,6 +353,7 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
   UnicodeString SessionName = SessionData->SessionName;
   UnicodeString SessionName = SessionData->SessionName;
 
 
   bool Result;
   bool Result;
+  bool CreateShortcut = false;
   if (!ForceDialog && ((PSavePassword == NULL) || SavePassword))
   if (!ForceDialog && ((PSavePassword == NULL) || SavePassword))
   {
   {
     CustomWinConfiguration->AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(SessionData);
     CustomWinConfiguration->AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(SessionData);
@@ -343,11 +361,12 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
   }
   }
   else
   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
     try
     {
     {
-      Result = Dialog->Execute(SessionName, SavePassword);
+      Dialog->Init((PSavePassword != NULL), NotRecommendedSavingPassword);
+      Result = Dialog->Execute(SessionName, SavePassword, CreateShortcut, SessionData->Name);
     }
     }
     __finally
     __finally
     {
     {
@@ -367,6 +386,14 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
       StoredSessions->NewSession(SessionName, SessionData);
       StoredSessions->NewSession(SessionName, SessionData);
     // modified only, explicit
     // modified only, explicit
     StoredSessions->Save(false, true);
     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;
   return NewSession;
@@ -386,7 +413,7 @@ void __fastcall SessionNameValidate(const UnicodeString & Text,
     Abort();
     Abort();
   }
   }
   else if ((Data != NULL) && (Text != OriginalName) &&
   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)
       qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
   {
   {
     Abort();
     Abort();
@@ -425,7 +452,7 @@ __fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
   WorkspaceNameCombo->AutoComplete = false;
   WorkspaceNameCombo->AutoComplete = false;
   AddComboBox(WorkspaceNameCombo, CreateLabel(LoadStr(SAVE_WORKSPACE_PROMPT)));
   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());
   WorkspaceNameCombo->Items->AddStrings(Workspaces.get());
 
 
   SavePasswordsCheck = new TCheckBox(this);
   SavePasswordsCheck = new TCheckBox(this);
@@ -438,7 +465,7 @@ __fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
   EnableControl(SavePasswordsCheck, CanSavePasswords);
   EnableControl(SavePasswordsCheck, CanSavePasswords);
 
 
   CreateShortcutCheck = new TCheckBox(this);
   CreateShortcutCheck = new TCheckBox(this);
-  CreateShortcutCheck->Caption = LoadStr(SAVE_WORKSPACE_SHORTCUT);
+  CreateShortcutCheck->Caption = LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT);
   AddButtonControl(CreateShortcutCheck);
   AddButtonControl(CreateShortcutCheck);
 
 
   EnableAutoSaveCheck = new TCheckBox(this);
   EnableAutoSaveCheck = new TCheckBox(this);
@@ -494,7 +521,7 @@ bool __fastcall DoSaveWorkspaceDialog(UnicodeString & WorkspaceName,
   bool * SavePasswords, bool NotRecommendedSavingPasswords,
   bool * SavePasswords, bool NotRecommendedSavingPasswords,
   bool & CreateShortcut, bool & EnableAutoSave)
   bool & CreateShortcut, bool & EnableAutoSave)
 {
 {
-  std::auto_ptr<TSaveWorkspaceDialog> Dialog(
+  std::unique_ptr<TSaveWorkspaceDialog> Dialog(
     new TSaveWorkspaceDialog((SavePasswords != NULL), NotRecommendedSavingPasswords));
     new TSaveWorkspaceDialog((SavePasswords != NULL), NotRecommendedSavingPasswords));
 
 
   bool Dummy = false;
   bool Dummy = false;

Some files were not shown because too many files changed in this diff