diff --git a/Text/XML/Expat/Annotated.hs b/Text/XML/Expat/Annotated.hs
--- a/Text/XML/Expat/Annotated.hs
+++ b/Text/XML/Expat/Annotated.hs
@@ -49,24 +49,10 @@
   saxToTreeG,
 
   -- * Abstraction of string types
-  GenericXMLString(..),
-
-  -- * Deprecated
-  eAttrs,
-  parseSAX,
-  parseSAXThrowing,
-  parseSAXLocations,
-  parseSAXLocationsThrowing,
-  parseTree,
-  parseTree',
-  parseTreeThrowing,
-  unannotate,
-  ParserOptions,
-  defaultParserOptions
+  GenericXMLString(..)
   ) where
 
-import Control.Arrow
-import qualified Text.XML.Expat.Tree as Tree
+import Control.Arrow (first)
 import Text.XML.Expat.SAX ( Encoding(..)
                           , GenericXMLString(..)
                           , ParseOptions(..)
@@ -74,13 +60,7 @@
                           , SAXEvent(..)
                           , XMLParseError(..)
                           , XMLParseException(..)
-                          , XMLParseLocation(..)
-                          , parseSAX
-                          , parseSAXThrowing
-                          , parseSAXLocations
-                          , parseSAXLocationsThrowing
-                          , ParserOptions
-                          , defaultParserOptions )
+                          , XMLParseLocation(..) )
 import qualified Text.XML.Expat.SAX as SAX
 import Text.XML.Expat.Internal.Namespaced
 import Text.XML.Expat.Internal.NodeClass
@@ -91,7 +71,7 @@
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
-import Data.List.Class
+import Data.List.Class (List(..), ListItem(..), cons, foldlL, joinM)
 import Data.Monoid
 
 
@@ -99,8 +79,8 @@
 -- that it has an extra piece of information of your choice attached to each
 -- Element.
 --
--- @c@ is the container type for the element's children, which is [] in the
--- @hexpat@ package, and a monadic list type for @hexpat-iteratee@.
+-- @c@ is the container type for the element's children, which would normally be [],
+-- but could potentially be a monadic list type to allow for chunked I/O.
 --
 -- @tag@ is the tag type, which can either be one of several string types,
 -- or a special type from the @Text.XML.Expat.Namespaced@ or
@@ -153,10 +133,6 @@
     Text t1 == Text t2 = t1 == t2
     _ == _ = False
 
-eAttrs :: Node a tag text -> [(tag, text)]
-{-# DEPRECATED eAttrs "use eAttributes instead" #-}
-eAttrs = eAttributes
-
 instance (NFData tag, NFData text, NFData a) => NFData (NodeG a [] tag text) where
     rnf (Element nam att chi ann) = rnf (nam, att, chi, ann)
     rnf (Text txt) = rnf txt
@@ -223,13 +199,6 @@
 instance (Functor c, List c) => MkElementClass (NodeG ()) c where
     mkElement name attrs children = Element name attrs children ()
 
--- | Convert an annotated tree (/Annotated/ module) into a non-annotated
--- tree (/Tree/ module).  DEPRECATED in favour of 'fromElement'.
-unannotate :: Functor c => NodeG a c tag text -> Tree.NodeG c tag text
-{-# DEPRECATED unannotate "use fromElement instead" #-}
-unannotate (Element na at ch _) = (Tree.Element na at (fmap unannotate ch))
-unannotate (Text t) = Tree.Text t
-
 -- | Type alias for an annotated node with unqualified tag names where
 -- tag and text are the same string type
 type UNode a text = Node a text text
@@ -339,18 +308,6 @@
        -> ItemM l (NodeG XMLParseLocation l tag text)
 parseG opts = saxToTreeG . SAX.parseLocationsG opts
 
--- | DEPRECATED: Use 'parse' instead.
---
--- Lazily parse XML to tree. Note that forcing the XMLParseError return value
--- will force the entire parse.  Therefore, to ensure lazy operation, don't
--- check the error status until you have processed the tree.
-parseTree :: (GenericXMLString tag, GenericXMLString text) =>
-             Maybe Encoding      -- ^ Optional encoding override
-          -> L.ByteString        -- ^ Input text (a lazy ByteString)
-          -> (LNode tag text, Maybe XMLParseError)
-{-# DEPRECATED parseTree "use Text.XML.Annotated.parse instead" #-}
-parseTree mEnc = parse (ParseOptions mEnc Nothing)
-
 -- | Lazily parse XML to tree. In the event of an error, throw 'XMLParseException'.
 --
 -- @parseThrowing@ can throw an exception from pure code, which is generally a bad
@@ -364,32 +321,12 @@
               -> LNode tag text
 parseThrowing opts bs = fst $ saxToTree $ SAX.parseLocationsThrowing opts bs
 
--- | DEPRECATED: use 'parseThrowing' instead
---
--- Lazily parse XML to tree. In the event of an error, throw 'XMLParseException'.
-parseTreeThrowing :: (GenericXMLString tag, GenericXMLString text) =>
-             Maybe Encoding      -- ^ Optional encoding override
-          -> L.ByteString        -- ^ Input text (a lazy ByteString)
-          -> LNode tag text
-{-# DEPRECATED parseTreeThrowing "use Text.XML.Annotated.parseThrowing instead" #-}
-parseTreeThrowing mEnc = parseThrowing (ParseOptions mEnc Nothing)
-
 -- | Strictly parse XML to tree. Returns error message or valid parsed tree.
 parse' :: (GenericXMLString tag, GenericXMLString text) =>
           ParseOptions tag text   -- ^ Parse options
        -> B.ByteString            -- ^ Input text (a strict ByteString)
        -> Either XMLParseError (LNode tag text)
-parse' opts bs = case parse opts (L.fromChunks [bs]) of
-    (_, Just err)   -> Left err
-    (root, Nothing) -> Right root 
-
--- | DEPRECATED: use 'parse' instead.
---
--- Strictly parse XML to tree. Returns error message or valid parsed tree.
-parseTree' :: (GenericXMLString tag, GenericXMLString text) =>
-              Maybe Encoding      -- ^ Optional encoding override
-           -> B.ByteString        -- ^ Input text (a strict ByteString)
-           -> Either XMLParseError (LNode tag text)
-{-# DEPRECATED parseTree' "use Text.XML.Expat.parse' instead" #-}
-parseTree' mEnc = parse' (ParseOptions mEnc Nothing)
+parse' opts doc = case parse opts (L.fromChunks [doc]) of
+    (xml, Nothing) -> Right xml
+    (_, Just err)  -> Left err
 
diff --git a/Text/XML/Expat/Cursor.hs b/Text/XML/Expat/Cursor.hs
--- a/Text/XML/Expat/Cursor.hs
+++ b/Text/XML/Expat/Cursor.hs
@@ -97,7 +97,7 @@
 import Data.Maybe(isNothing)
 import Data.Monoid
 import Data.Functor.Identity
-import Data.List.Class
+import Data.List.Class (List(..), ListItem(..), cons, foldlL, lengthL)
 
 data Tag tag text = Tag { tagName    :: tag
                         , tagAttribs :: Attributes tag text
diff --git a/Text/XML/Expat/Extended.hs b/Text/XML/Expat/Extended.hs
--- a/Text/XML/Expat/Extended.hs
+++ b/Text/XML/Expat/Extended.hs
@@ -80,7 +80,7 @@
 import Control.DeepSeq
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
-import Data.List.Class
+import Data.List.Class (List, foldlL, joinM)
 import Data.Maybe
 import Data.Monoid
 
diff --git a/Text/XML/Expat/Format.hs b/Text/XML/Expat/Format.hs
--- a/Text/XML/Expat/Format.hs
+++ b/Text/XML/Expat/Format.hs
@@ -28,9 +28,6 @@
         formatDocument,
         formatDocument',
         formatDocumentG,
-        -- * Deprecated names
-        formatTree,
-        formatTree',
         -- * Low level
         xmlHeader,
         treeToSAX,
@@ -52,18 +49,12 @@
 import qualified Data.ByteString.Lazy as L
 import Data.ByteString.Internal (c2w, w2c)
 import Data.Char (isSpace)
-import Data.List.Class
+import Data.List.Class (List(..), ListItem(..), fromList)
 import Data.Monoid
 import Data.Word
 import Data.Text (Text)
 import Text.XML.Expat.Tree (UNode)
 
--- | DEPRECATED: Renamed to 'format'.
-formatTree :: (NodeClass n [], GenericXMLString tag, GenericXMLString text) =>
-              n [] tag text
-           -> L.ByteString
-formatTree = format
-
 -- | Format document with <?xml.. header - lazy variant that returns lazy ByteString.
 format :: (NodeClass n [], GenericXMLString tag, GenericXMLString text) =>
           n [] tag text
@@ -77,12 +68,6 @@
           n c tag text
        -> c B.ByteString
 formatG node = cons xmlHeader $ formatNodeG node
-
--- | DEPRECATED: Renamed to 'format''.
-formatTree' :: (NodeClass n [], GenericXMLString tag, GenericXMLString text) =>
-               n [] tag text
-            -> B.ByteString
-formatTree' = B.concat . L.toChunks . formatTree
 
 -- | Format document with <?xml.. header - strict variant that returns strict ByteString.
 format' :: (NodeClass n [], GenericXMLString tag, GenericXMLString text) =>
diff --git a/Text/XML/Expat/IO.hs b/Text/XML/Expat/IO.hs
deleted file mode 100644
--- a/Text/XML/Expat/IO.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# OPTIONS_HADDOCK hide #-}
-module Text.XML.Expat.IO
-       {-# DEPRECATED "Renamed to Text.XML.Expat.Internal.IO" #-}
-    (
-        module Text.XML.Expat.Internal.IO
-    ) where
-
-import Text.XML.Expat.Internal.IO
-
diff --git a/Text/XML/Expat/Internal/DocumentClass.hs b/Text/XML/Expat/Internal/DocumentClass.hs
--- a/Text/XML/Expat/Internal/DocumentClass.hs
+++ b/Text/XML/Expat/Internal/DocumentClass.hs
@@ -6,7 +6,7 @@
 import Text.XML.Expat.Internal.NodeClass (NodeClass)
 import Control.DeepSeq
 import Control.Monad (mzero)
-import Data.List.Class
+import Data.List.Class (List)
 
 
 -- | XML declaration, consisting of version, encoding and standalone.
diff --git a/Text/XML/Expat/Internal/Glue.c b/Text/XML/Expat/Internal/Glue.c
new file mode 100644
--- /dev/null
+++ b/Text/XML/Expat/Internal/Glue.c
@@ -0,0 +1,245 @@
+#include <expat.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef struct {
+    XML_Parser parser;
+    XML_Char* (*decoder)(const XML_Char*);
+    int locations;
+} MyParser;
+
+typedef struct {
+    size_t offset;
+    size_t capacity;
+    uint8_t* block;
+    MyParser* mp;
+} Block;
+
+/*!
+ * Allocate the specified amount of room in the buffer.
+ */
+static void* alloc(Block* blk, size_t room)
+{
+    size_t minCapacity = blk->offset + room;
+    size_t start = blk->offset;
+    {
+        int changed = 0;
+        size_t capacity = blk->capacity;
+        while (capacity < minCapacity) {
+            capacity = capacity * 2;
+            changed = 1;
+        }
+        if (changed) {
+            blk->capacity = capacity;
+            blk->block = realloc(blk->block, capacity);
+        }
+    }
+    blk->offset += room;
+    return blk->block + start;
+}
+
+static void pushType(Block* blk, uint32_t type)
+{
+    *(uint32_t*)alloc(blk, 4) = type;
+    if (blk->mp->locations) {
+        int64_t* loc = alloc(blk, 32);
+        loc[0] = (int64_t)XML_GetCurrentLineNumber(blk->mp->parser);
+        loc[1] = (int64_t)XML_GetCurrentColumnNumber(blk->mp->parser);
+        loc[2] = (int64_t)XML_GetCurrentByteIndex(blk->mp->parser);
+        loc[3] = (int64_t)XML_GetCurrentByteCount(blk->mp->parser);
+    }
+}
+
+#define ROUND_UP_32(x) (((x) + 3) & ~3)
+
+static void startElement(
+    void *userData,
+    const XML_Char *name,
+    const XML_Char **atts)
+{
+    Block* blk = userData;
+    size_t nameLen = strlen(name) + 1;
+    size_t nAtts, i;
+    for (nAtts = 0; atts[nAtts] != NULL; nAtts += 2) ;
+    pushType(blk, 1);
+    *(uint32_t*)alloc(blk, 4) = nAtts;
+    memcpy(alloc(blk, nameLen), name, nameLen);
+    for (i = 0; i < nAtts; i++) {
+        size_t attLen = strlen(atts[i]) + 1;
+        memcpy(alloc(blk, attLen), atts[i], attLen);
+    }
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+static void endElement(void *userData, const XML_Char *name)
+{
+    Block* blk = userData;
+    size_t nameLen = strlen(name) + 1;
+    pushType(blk, 2);
+    memcpy(alloc(blk, nameLen), name, nameLen);
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+static void characterData(
+    void *userData,
+    const XML_Char *s,
+    int len)
+{
+    Block* blk = userData;
+    pushType(blk, 3);
+    *(uint32_t*)alloc(blk, 4) = len;
+    memcpy(alloc(blk, (size_t)len), s, (size_t)len);
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+static void xmlDeclHandler(void           *userData,
+                            const XML_Char *version,
+                            const XML_Char *encoding,
+                            int             standalone)
+{
+    Block* blk = userData;
+    int verLen = strlen(version) + 1;
+    pushType(blk, 4);
+    memcpy(alloc(blk, verLen), version, verLen);
+    if (encoding != NULL) {
+        int encLen = strlen(encoding)+1;
+        uint8_t* pEnc = alloc(blk, encLen+1);
+        pEnc[0] = 1;
+        memcpy(pEnc+1, encoding, encLen);
+    }
+    else
+        *(uint8_t*)alloc(blk, 1) = 0;
+    *(int8_t*)alloc(blk, 1) = (int8_t)standalone;
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+static void startCData(void* userData)
+{
+    Block* blk = userData;
+    pushType(blk, 5);
+}
+
+static void endCData(void* userData)
+{
+    Block* blk = userData;
+    pushType(blk, 6);
+}
+
+static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data)
+{
+    Block* blk = userData;
+    int targetLen = strlen(target) + 1;
+    int dataLen = strlen(data) + 1;
+    pushType(blk, 7);
+    memcpy(alloc(blk, targetLen), target, targetLen);
+    memcpy(alloc(blk, dataLen), data, dataLen);
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+static void comment(void* userData, const XML_Char *text)
+{
+    Block* blk = userData;
+    int textLen = strlen(text) + 1;
+    pushType(blk, 8);
+    memcpy(alloc(blk, textLen), text, textLen);
+    blk->offset = ROUND_UP_32(blk->offset);
+}
+
+MyParser* hexpatNewParser(const XML_Char* encoding, int locations)
+{
+    MyParser* mp = malloc(sizeof(MyParser));
+    XML_Parser p = XML_ParserCreate(encoding);
+    XML_SetStartElementHandler(p, startElement);
+    XML_SetEndElementHandler(p, endElement);
+    XML_SetCharacterDataHandler(p, characterData);
+    XML_SetXmlDeclHandler(p, xmlDeclHandler);
+    XML_SetCdataSectionHandler(p, startCData, endCData);
+    XML_SetProcessingInstructionHandler(p, processingInstruction);
+    XML_SetCommentHandler(p, comment);
+    mp->parser = p;
+    mp->locations = locations;
+    return mp;
+}
+
+void hexpatFreeParser(MyParser* mp)
+{
+    XML_ParserFree(mp->parser);
+    free(mp);
+}
+
+static int externalEntityRef(XML_Parser parser,
+                                const XML_Char *context,
+                                const XML_Char *base,
+                                const XML_Char *systemId,
+                                const XML_Char *publicId)
+{
+    if (systemId == NULL && publicId == NULL) {
+        XML_Parser eep = XML_ExternalEntityParserCreate(parser, context, NULL);
+        enum XML_Status ret = XML_Parse(eep, "", 0, XML_TRUE);
+        if (ret == XML_STATUS_OK) {
+            XML_ParserFree(eep);
+        }
+        else {
+            XML_ParserFree(eep);
+            XML_StopParser(parser, 0);
+        }
+    }
+    else
+        XML_StopParser(parser, 0);
+}
+
+static void skippedEntity(void *userData,
+                           const XML_Char *entityName,
+                           int is_parameter_entity)
+{
+    Block* blk = userData;
+    if (is_parameter_entity)
+        XML_StopParser(blk->mp->parser, 0);
+    else {
+        XML_Char* out = blk->mp->decoder(entityName);
+        if (out != NULL) {
+            characterData(blk, out, strlen(out));
+            free(out);
+        }
+        else
+            XML_StopParser(blk->mp->parser, 0);
+    }
+}
+
+enum XML_Status hexpatParse(
+    MyParser* mp,
+    const char* s,
+    int len,
+    int isFinal,
+    uint8_t** buffer,
+    int* length)
+{
+    enum XML_Status ret;
+    Block blk;
+    blk.offset = 0;
+    blk.capacity = 256;
+    blk.block = malloc(blk.capacity);
+    blk.mp = mp;
+    XML_SetUserData(mp->parser, &blk);
+    ret = XML_Parse(mp->parser, s, len, isFinal);
+    *(uint32_t*)alloc(&blk, 4) = 0;
+    *buffer = blk.block;
+    *length = (int)blk.offset;
+    return ret;
+}
+
+void hexpatSetEntityHandler(
+    MyParser* mp,
+    XML_Char* (*decoder)(const XML_Char*))
+{
+    mp->decoder = decoder;
+    XML_UseForeignDTD(mp->parser, XML_TRUE);
+    XML_SetExternalEntityRefHandler(mp->parser, externalEntityRef);
+    XML_SetSkippedEntityHandler(mp->parser, skippedEntity);
+}
+
+XML_Parser hexpatGetParser(MyParser* mp)
+{
+    return mp->parser;
+}
diff --git a/Text/XML/Expat/Internal/IO.hs b/Text/XML/Expat/Internal/IO.hs
--- a/Text/XML/Expat/Internal/IO.hs
+++ b/Text/XML/Expat/Internal/IO.hs
@@ -1,94 +1,32 @@
 {-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}
+{-# OPTIONS_GHC -fno-cse -fno-full-laziness #-}
 
+
 -- | Low-level interface to Expat. Unless speed is paramount, this should
 -- normally be avoided in favour of the interfaces provided by
--- 'Text.XML.Expat.SAX' and 'Text.XML.Expat.Tree', etc.  Basic usage is:
---
--- (1) Make a new parser: 'newParser'.
---
--- (2) Set up callbacks on the parser: 'setStartElementHandler', etc.
---
--- (3) Feed data into the parser: 'parse', 'parse'' or 'parseChunk'.  Some of
---     these functions must be wrapped in 'withParser'.
-
+-- 'Text.XML.Expat.SAX' and 'Text.XML.Expat.Tree', etc.
 module Text.XML.Expat.Internal.IO (
-  -- ** Parser Setup
-  Parser, newParser,
-
-  -- ** Parsing
-  parse, parse',
-  withParser,
-  ParserPtr, Parser_struct,
-  parseChunk,
+  HParser,
+  hexpatNewParser,
+  encodingToString,
   Encoding(..),
   XMLParseError(..),
-  getParseLocation,
-  XMLParseLocation(..),
-
-  -- ** Parser Callbacks
-  XMLDeclarationHandler,
-  StartElementHandler,
-  EndElementHandler,
-  CharacterDataHandler,
-  ExternalEntityRefHandler,
-  SkippedEntityHandler,
-  StartCDataHandler,
-  EndCDataHandler,
-  CommentHandler,
-  ProcessingInstructionHandler,
-  setXMLDeclarationHandler,
-  setStartElementHandler,
-  setEndElementHandler,
-  setCharacterDataHandler,
-  setStartCDataHandler,
-  setEndCDataHandler,
-  setProcessingInstructionHandler,
-  setCommentHandler,
-  setExternalEntityRefHandler,
-  setSkippedEntityHandler,
-  setUseForeignDTD,
-
-  -- ** Lower-level interface
-  parseExternalEntityReference,
-  ExpatHandlers,
-
-  -- ** Helpers
-  encodingToString
+  XMLParseLocation(..)
   ) where
 
-import Control.Concurrent
-import Control.Exception (bracket)
+import Control.Applicative
 import Control.DeepSeq
-import Control.Monad
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BSL
-import Data.IORef
-import Foreign hiding (unsafePerformIO)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as I
+import Data.Int
+import Data.Word
+import Foreign
 import Foreign.C
-import System.IO.Unsafe (unsafePerformIO)
 
 
--- |Opaque parser type.
 data Parser_struct
 type ParserPtr = Ptr Parser_struct
-data Parser = Parser
-    { _parserObj                    :: ForeignPtr Parser_struct
-    , _xmlDeclarationHandler        :: IORef CXMLDeclarationHandler
-    , _startElementHandler          :: IORef CStartElementHandler
-    , _endElementHandler            :: IORef CEndElementHandler
-    , _cdataHandler                 :: IORef CCharacterDataHandler
-    , _externalEntityRefHandler     :: IORef (Maybe CExternalEntityRefHandler)
-    , _skippedEntityHandler         :: IORef (Maybe CSkippedEntityHandler)
-    , _startCDataHandler            :: IORef CStartCDataHandler
-    , _endCDataHandler              :: IORef CEndCDataHandler
-    , _processingInstructionHandler :: IORef CProcessingInstructionHandler
-    , _commentHandler               :: IORef CCommentHandler
-    }
 
-instance Show Parser where
-    showsPrec _ (Parser fp _ _ _ _ _ _ _ _ _ _) = showsPrec 0 fp
-
--- |Encoding types available for the document encoding.
 data Encoding = ASCII | UTF8 | UTF16 | ISO88591
 encodingToString :: Encoding -> String
 encodingToString ASCII    = "US-ASCII"
@@ -100,99 +38,16 @@
 withOptEncoding Nothing    f = f nullPtr
 withOptEncoding (Just enc) f = withCString (encodingToString enc) f
 
-
-parserCreate :: Maybe Encoding -> IO (ParserPtr)
-parserCreate a1 =
-  withOptEncoding a1 $ \a1' -> do
-      pp <- parserCreate'_ a1'
-      xmlSetUserData pp pp
-      return pp
-
--- | Create a 'Parser'.
-newParser :: Maybe Encoding -> IO Parser
-newParser enc = do
-  ptr          <- parserCreate enc
-  fptr         <- newForeignPtr parserFree ptr
-  nullXMLDeclH <- newIORef nullCXMLDeclarationHandler
-  nullStartH   <- newIORef nullCStartElementHandler
-  nullEndH     <- newIORef nullCEndElementHandler
-  nullCharH    <- newIORef nullCCharacterDataHandler
-  extH         <- newIORef Nothing
-  skipH        <- newIORef Nothing
-  nullSCDataH  <- newIORef nullCStartCDataHandler
-  nullECDataH  <- newIORef nullCEndCDataHandler
-  nullPIH      <- newIORef nullCProcessingInstructionHandler
-  nullCommentH <- newIORef nullCCommentHandler
-
-  return $ Parser fptr nullXMLDeclH nullStartH nullEndH nullCharH extH skipH 
-    nullSCDataH nullECDataH nullPIH nullCommentH
-  
-setUseForeignDTD :: Parser -> Bool -> IO ()
-setUseForeignDTD p b = withParser p $ \p' -> xmlUseForeignDTD p' b'
-  where
-    b' = if b then 1 else 0
-
 -- ByteString.useAsCStringLen is almost what we need, but C2HS wants a CInt
 -- instead of an Int.
-withBStringLen :: BS.ByteString -> ((CString, CInt) -> IO a) -> IO a
+withBStringLen :: B.ByteString -> ((CString, CInt) -> IO a) -> IO a
 withBStringLen bs f = do
-  BS.useAsCStringLen bs $ \(str, len) -> f (str, fromIntegral len)
+  B.useAsCStringLen bs $ \(str, len) -> f (str, fromIntegral len)
 
 unStatus :: CInt -> Bool
 unStatus 0 = False
 unStatus _ = True
 
--- |@parse data@ feeds /lazy/ ByteString data into a 'Parser'. It returns
--- Nothing on success, or Just the parse error.
-parse :: Parser -> BSL.ByteString -> IO (Maybe XMLParseError)
-parse parser bs = withParser parser $ \pp -> do
-    let
-        doParseChunks [] = doParseChunk pp BS.empty True
-        doParseChunks (c:cs) = do
-            ok <- doParseChunk pp c False
-            if ok
-                then doParseChunks cs
-                else return False
-    ok <- doParseChunks (BSL.toChunks bs)
-    if ok
-        then return Nothing
-        else Just `fmap` getError pp
-
--- |@parse data@ feeds /strict/ ByteString data into a 'Parser'. It returns
--- Nothing on success, or Just the parse error.
-parse' :: Parser -> BS.ByteString -> IO (Maybe XMLParseError)
-parse' parser bs = withParser parser $ \pp -> do
-    ok <- doParseChunk pp bs True
-    if ok
-        then return Nothing
-        else Just `fmap` getError pp
-
-parseExternalEntityReference :: Parser
-                             -> CString         -- ^ context
-                             -> Maybe Encoding  -- ^ encoding
-                             -> CStringLen      -- ^ text
-                             -> IO Bool
-parseExternalEntityReference parser context encoding (text,sz) =
-    withParser parser $ \pp -> do
-        extp <- withOptEncoding encoding $
-                xmlExternalEntityParserCreate pp context
-        e <- doParseChunk'_ extp text (fromIntegral sz) 1
-        parserFree' extp
-        return $ e == 1
-
--- |@parseChunk data False@ feeds /strict/ ByteString data into a
--- 'Parser'.  The end of the data is indicated by passing @True@ for the
--- final parameter.   It returns Nothing on success, or Just the parse error.
-parseChunk :: ParserPtr
-           -> BS.ByteString
-           -> Bool
-           -> IO (Maybe XMLParseError)
-parseChunk pp xml final = do
-    ok <- doParseChunk pp xml final
-    if ok
-        then return Nothing
-        else Just `fmap` getError pp
-
 getError :: ParserPtr -> IO XMLParseError
 getError pp = do
     code <- xmlGetErrorCode pp
@@ -201,146 +56,10 @@
     loc <- getParseLocation pp
     return $ XMLParseError err loc
 
-data ExpatHandlers = ExpatHandlers
-    (FunPtr CXMLDeclarationHandler)
-    (FunPtr CStartElementHandler)
-    (FunPtr CEndElementHandler)
-    (FunPtr CCharacterDataHandler)
-    (Maybe (FunPtr CExternalEntityRefHandler))
-    (Maybe (FunPtr CSkippedEntityHandler))
-    (FunPtr CStartCDataHandler)
-    (FunPtr CEndCDataHandler)
-    (FunPtr CProcessingInstructionHandler)
-    (FunPtr CCommentHandler)
-
--- | Most of the low-level functions take a ParserPtr so are required to be
--- called inside @withParser@.
-withParser :: Parser
-           -> (ParserPtr -> IO a)  -- ^ Computation where parseChunk and other low-level functions may be used
-           -> IO a
-withParser parser@(Parser fp _ _ _ _ _ _ _ _ _ _) code = withForeignPtr fp $ \pp -> do
-    bracket
-        (unsafeSetHandlers parser pp)
-        unsafeReleaseHandlers
-        (\_ -> code pp)
-  where
-    unsafeSetHandlers :: Parser -> ParserPtr -> IO ExpatHandlers
-    unsafeSetHandlers (Parser _ xmlDeclRef startRef endRef charRef extRef skipRef 
-        startCDataRef endCDataRef processingInstructionRef commentRef) pp =
-      do
-        cXMLDeclH <- mkCXMLDeclarationHandler =<< readIORef xmlDeclRef
-        cStartH <- mkCStartElementHandler =<< readIORef startRef
-        cEndH   <- mkCEndElementHandler =<< readIORef endRef
-        cCharH  <- mkCCharacterDataHandler =<< readIORef charRef
-        mExtH   <- readIORef extRef >>=
-                       maybe (return Nothing)
-                             (\h -> liftM Just $ mkCExternalEntityRefHandler h)
-    
-        mSkipH  <- readIORef skipRef >>=
-                       maybe (return Nothing)
-                             (\h -> liftM Just $ mkCSkippedEntityHandler h)
-                             
-        cStartCDataH <- mkCStartCDataHandler =<< readIORef startCDataRef
-        cEndCDataH   <- mkCEndCDataHandler =<< readIORef endCDataRef
-        
-        cProcessingInstructionH   <- mkCProcessingInstructionHandler =<< readIORef processingInstructionRef
-        cCommentH   <- mkCCommentHandler =<< readIORef commentRef
-    
-        xmlSetxmldeclhandler       pp cXMLDeclH
-        xmlSetstartelementhandler  pp cStartH
-        xmlSetendelementhandler    pp cEndH
-        xmlSetcharacterdatahandler pp cCharH
-        xmlSetstartcdatahandler  pp cStartCDataH
-        xmlSetendcdatahandler    pp cEndCDataH
-        xmlSetprocessinginstructionhandler pp cProcessingInstructionH
-        xmlSetcommenthandler pp cCommentH
-        maybe (return ())
-              (xmlSetExternalEntityRefHandler pp)
-              mExtH
-        maybe (return ())
-              (xmlSetSkippedEntityHandler pp)
-              mSkipH
-    
-        return $ ExpatHandlers cXMLDeclH cStartH cEndH cCharH mExtH mSkipH 
-            cStartCDataH cEndCDataH cProcessingInstructionH cCommentH
-    
-    unsafeReleaseHandlers :: ExpatHandlers -> IO ()
-    unsafeReleaseHandlers (ExpatHandlers cXMLDeclH cStartH cEndH cCharH mcExtH mcSkipH 
-            cStartCDataH cEndCDataH cProcessingInstructionH cCommentH) = do
-        freeHaskellFunPtr cXMLDeclH
-        freeHaskellFunPtr cStartH
-        freeHaskellFunPtr cEndH
-        freeHaskellFunPtr cCharH
-        maybe (return ()) freeHaskellFunPtr mcExtH
-        maybe (return ()) freeHaskellFunPtr mcSkipH
-        freeHaskellFunPtr cStartCDataH
-        freeHaskellFunPtr cEndCDataH
-        freeHaskellFunPtr cProcessingInstructionH
-        freeHaskellFunPtr cCommentH
-
 -- |Obtain C value from Haskell 'Bool'.
 --
 cFromBool :: Num a => Bool -> a
-cFromBool  = fromBool
-
-doParseChunk :: ParserPtr -> BS.ByteString -> Bool -> IO (Bool)
-doParseChunk = ensureBoundThread $ \a1 a2 a3 ->
-  withBStringLen a2 $ \(a2'1, a2'2) ->
-  let {a3' = cFromBool a3} in
-  doParseChunk'_ a1 a2'1  a2'2 a3' >>= \res ->
-  let {res' = unStatus res} in
-  return (res')
-
-data WorkerIface = WorkerIface (MVar (ParserPtr, BS.ByteString, Bool)) (MVar Bool)
-
-workerIfaceRef :: IORef (Maybe WorkerIface)
-{-# NOINLINE workerIfaceRef #-}
-workerIfaceRef = unsafePerformIO $ newIORef Nothing
-
--- If the calling thread is not bound, we delegate to a bound thread, because
--- otherwise we get a thread explosion (this is true in ghc-6.12.X).
--- See test/thread-leak/ directory for a test case.
-ensureBoundThread :: (ParserPtr -> BS.ByteString -> Bool -> IO Bool)
-                  -> ParserPtr
-                  -> BS.ByteString
-                  -> Bool
-                  -> IO Bool
-ensureBoundThread doit p bs last = do
-    bound <- isCurrentThreadBound
-    if rtsSupportsBoundThreads && not bound
-        then delegate
-        else doit p bs last
-  where
-    delegate = do
-        mIface <- readIORef workerIfaceRef
-        case mIface of
-            Just iface -> pipeTo iface
-            Nothing -> do
-                inV <- newEmptyMVar
-                outV <- newEmptyMVar
-                let iface = WorkerIface inV outV
-                justSetItGlobally <- atomicModifyIORef workerIfaceRef $ \mIface ->
-                    case mIface of
-                        Just _  -> (mIface, False)
-                        Nothing -> (Just iface, True) 
-                if justSetItGlobally
-                    then do
-                        _ <- forkOS $ worker iface
-                        pipeTo iface
-                    else
-                        -- If it wasn't changed, then this is because we got a race
-                        -- condition with another thread.  We resolve this by trying
-                        -- again.  We'll succeed on the second attempt.  The mvars
-                        -- we allocated here will be GC'd.
-                        delegate
-
-    pipeTo (WorkerIface inV outV) =
-        putMVar inV (p, bs, last) >> takeMVar outV
-
-    worker (WorkerIface inV outV) = forever $
-        putMVar outV =<< uncurry3 doit =<< takeMVar inV
-      where
-        uncurry3 f (a, b, c) = f a b c 
+cFromBool = fromBool
 
 -- | Parse error, consisting of message text and error location
 data XMLParseError = XMLParseError String XMLParseLocation deriving (Eq, Show)
@@ -373,373 +92,6 @@
             xmlByteCount = fromIntegral count
         }
 
--- | The type of the \"XML declaration\" callback.  Parameters are version,
--- encoding (which can be nullPtr), and standalone declaration, where -1 = no
--- declaration, 0 = "no" and 1 = "yes". Return True to continue parsing as
--- normal, or False to terminate the parse.
-type XMLDeclarationHandler = ParserPtr -> CString -> CString -> CInt -> IO Bool
-
--- | The type of the \"element started\" callback.  The first parameter is the
--- element name; the second are the (attribute, value) pairs. Return True to
--- continue parsing as normal, or False to terminate the parse.
-type StartElementHandler  = ParserPtr -> CString -> [(CString, CString)] -> IO Bool
-
--- | The type of the \"element ended\" callback.  The parameter is the element
--- name. Return True to continue parsing as normal, or False to terminate the
--- parse.
-type EndElementHandler    = ParserPtr -> CString -> IO Bool
-
--- | The type of the \"character data\" callback.  The parameter is the
--- character data processed.  This callback may be called more than once while
--- processing a single conceptual block of text. Return True to continue
--- parsing as normal, or False to terminate the parse.
-type CharacterDataHandler = ParserPtr -> CStringLen -> IO Bool
-
--- | The type of the \"start cdata\" callback.   Return True to continue
--- parsing as normal, or False to terminate the parse.
-type StartCDataHandler = ParserPtr -> IO Bool
-
--- | The type of the \"end cdata\" callback.   Return True to continue
--- parsing as normal, or False to terminate the parse.
-type EndCDataHandler = ParserPtr -> IO Bool
-
--- | The type of the \"processing instruction\" callback.  The first parameter
--- is the first word in the processing instruction.  The second parameter is
--- the rest of the characters in the processing instruction after skipping all
--- whitespace after the initial word. Return True to continue parsing as normal,
--- or False to terminate the parse.
-type ProcessingInstructionHandler = ParserPtr -> CString -> CString -> IO Bool
-
--- | The type of the \"comment\" callback.  The parameter is the comment text.
--- Return True to continue parsing as normal, or False to terminate the parse.
-type CommentHandler = ParserPtr -> CString -> IO Bool
-
--- | The type of the \"external entity reference\" callback. See the expat
--- documentation.
-type ExternalEntityRefHandler =  Parser
-                              -> CString   -- context
-                              -> CString   -- base
-                              -> CString   -- systemID
-                              -> CString   -- publicID
-                              -> IO Bool
-
--- | Set a skipped entity handler. 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.
-type SkippedEntityHandler =  ParserPtr
-                          -> CString   -- entityName
-                          -> Int       -- is a parameter entity?
-                          -> IO Bool
-
-
-type CXMLDeclarationHandler = ParserPtr -> CString -> CString -> CInt -> IO ()
-
-nullCXMLDeclarationHandler :: CXMLDeclarationHandler
-nullCXMLDeclarationHandler _ _ _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCXMLDeclarationHandler :: CXMLDeclarationHandler
-                           -> IO (FunPtr CXMLDeclarationHandler)
-
-wrapXMLDeclarationHandler :: Parser -> XMLDeclarationHandler -> CXMLDeclarationHandler
-wrapXMLDeclarationHandler parser handler = h
-  where
-    h pp ver enc sd | ver /= nullPtr = do
-        stillRunning <- handler pp ver enc sd
-        unless stillRunning $ stopp parser
-    {- From expat.h:
-       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.
-     -}
-    h _ _ _ _ = return ()  -- text declaration (ignore)
-
--- | Attach a XMLDeclarationHandler to a Parser.
-setXMLDeclarationHandler :: Parser -> XMLDeclarationHandler -> IO ()
-setXMLDeclarationHandler parser@(Parser _ xmlDeclRef _ _ _ _ _ _ _ _ _) handler =
-    writeIORef xmlDeclRef $ wrapXMLDeclarationHandler parser handler
-
-
-type CStartElementHandler = ParserPtr -> CString -> Ptr CString -> IO ()
-
-nullCStartElementHandler :: CStartElementHandler
-nullCStartElementHandler _ _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCStartElementHandler :: CStartElementHandler
-                         -> IO (FunPtr CStartElementHandler)
-
-wrapStartElementHandler :: Parser -> StartElementHandler -> CStartElementHandler
-wrapStartElementHandler parser handler = h
-  where
-    h pp cname cattrs = do
-        cattrlist <- peekArray0 nullPtr cattrs
-        stillRunning <- handler pp cname (pairwise cattrlist)
-        unless stillRunning $ stopp parser
-
--- | Attach a StartElementHandler to a Parser.
-setStartElementHandler :: Parser -> StartElementHandler -> IO ()
-setStartElementHandler parser@(Parser _ _ startRef _ _ _ _ _ _ _ _) handler =
-    writeIORef startRef $ wrapStartElementHandler parser handler
-
-
-type CEndElementHandler = ParserPtr -> CString -> IO ()
-
-nullCEndElementHandler :: CEndElementHandler
-nullCEndElementHandler _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCEndElementHandler :: CEndElementHandler
-                       -> IO (FunPtr CEndElementHandler)
-wrapEndElementHandler :: Parser -> EndElementHandler -> CEndElementHandler
-wrapEndElementHandler parser handler = h
-  where
-    h pp cname = do
-        stillRunning <- handler pp cname
-        unless stillRunning $ stopp parser
-
--- | Attach an EndElementHandler to a Parser.
-setEndElementHandler :: Parser -> EndElementHandler -> IO ()
-setEndElementHandler parser@(Parser _ _ _ endRef _ _ _ _ _ _ _) handler =
-    writeIORef endRef $ wrapEndElementHandler parser handler
-
-
-type CCharacterDataHandler = ParserPtr -> CString -> CInt -> IO ()
-
-nullCCharacterDataHandler :: CCharacterDataHandler
-nullCCharacterDataHandler _ _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCCharacterDataHandler :: CCharacterDataHandler
-                          -> IO (FunPtr CCharacterDataHandler)
-wrapCharacterDataHandler :: Parser -> CharacterDataHandler -> CCharacterDataHandler
-wrapCharacterDataHandler parser handler = h
-  where
-    h pp cdata len = do
-        stillRunning <- handler pp (cdata, fromIntegral len)
-        unless stillRunning $ stopp parser
-
--- | Attach an CharacterDataHandler to a Parser.
-setCharacterDataHandler :: Parser -> CharacterDataHandler -> IO ()
-setCharacterDataHandler parser@(Parser _ _ _ _ charRef _ _ _ _ _ _) handler =
-    writeIORef charRef $ wrapCharacterDataHandler parser handler
-
-
-type CStartCDataHandler = ParserPtr -> IO ()
-
-nullCStartCDataHandler :: CStartCDataHandler
-nullCStartCDataHandler _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCStartCDataHandler :: CStartCDataHandler
-                         -> IO (FunPtr CStartCDataHandler)
-
-wrapStartCDataHandler :: Parser -> StartCDataHandler -> CStartCDataHandler
-wrapStartCDataHandler parser handler = h
-  where
-    h pp = do
-        stillRunning <- handler pp
-        unless stillRunning $ stopp parser
-
--- | Attach a StartCDataHandler to a Parser.
-setStartCDataHandler :: Parser -> StartCDataHandler -> IO ()
-setStartCDataHandler parser@(Parser _ _ _ _ _ _ _ startCData _ _ _) handler =
-    writeIORef startCData $ wrapStartCDataHandler parser handler
-
-
-type CEndCDataHandler = ParserPtr -> IO ()
-
-nullCEndCDataHandler :: CEndCDataHandler
-nullCEndCDataHandler _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCEndCDataHandler :: CEndCDataHandler
-                         -> IO (FunPtr CEndCDataHandler)
-
-wrapEndCDataHandler :: Parser -> EndCDataHandler -> CEndCDataHandler
-wrapEndCDataHandler parser handler = h
-  where
-    h pp = do
-        stillRunning <- handler pp
-        unless stillRunning $ stopp parser
-
--- | Attach a EndCDataHandler to a Parser.
-setEndCDataHandler :: Parser -> EndCDataHandler -> IO ()
-setEndCDataHandler parser@(Parser _ _ _ _ _ _ _ _ endCData _ _) handler =
-    writeIORef endCData $ wrapEndCDataHandler parser handler
-
-
-type CProcessingInstructionHandler = ParserPtr -> CString -> CString -> IO ()
-
-nullCProcessingInstructionHandler :: CProcessingInstructionHandler
-nullCProcessingInstructionHandler _ _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCProcessingInstructionHandler :: CProcessingInstructionHandler
-                          -> IO (FunPtr CProcessingInstructionHandler)
-                          
-wrapProcessingInstructionHandler :: Parser -> ProcessingInstructionHandler -> CProcessingInstructionHandler
-wrapProcessingInstructionHandler parser handler = h
-  where
-    h pp ctarget cdata = do
-        stillRunning <- handler pp ctarget cdata
-        unless stillRunning $ stopp parser
-
--- | Attach a ProcessingInstructionHandler to a Parser.
-setProcessingInstructionHandler :: Parser -> ProcessingInstructionHandler -> IO ()
-setProcessingInstructionHandler parser@(Parser _ _ _ _ _ _ _ _ _ piRef _) handler =
-    writeIORef piRef $ wrapProcessingInstructionHandler parser handler
-
-
-type CCommentHandler = ParserPtr -> CString -> IO ()
-
-nullCCommentHandler :: CCommentHandler
-nullCCommentHandler _ _ = return ()
-
-foreign import ccall safe "wrapper"
-  mkCCommentHandler :: CCommentHandler
-                          -> IO (FunPtr CCommentHandler)
-                          
-wrapCommentHandler :: Parser -> CommentHandler -> CCommentHandler
-wrapCommentHandler parser handler = h
-  where
-    h pp cdata = do
-        stillRunning <- handler pp cdata
-        unless stillRunning $ stopp parser
-
--- | Attach a CommentHandler to a Parser.
-setCommentHandler :: Parser -> CommentHandler -> IO ()
-setCommentHandler parser@(Parser _ _ _ _ _ _ _ _ _ _ commentRef) handler =
-    writeIORef commentRef $ wrapCommentHandler parser handler
-
-
-pairwise :: [a] -> [(a,a)]
-pairwise (x1:x2:xs) = (x1,x2) : pairwise xs
-pairwise _          = []
-
-stopp :: Parser -> IO ()
-stopp parser = withParser parser $ \p -> xmlStopParser p 0
-
-------------------------------------------------------------------------------
--- C imports
-
-foreign import ccall unsafe "XML_ParserCreate"
-  parserCreate'_ :: Ptr CChar -> IO ParserPtr
-  
-foreign import ccall unsafe "XML_SetUserData"
-  xmlSetUserData :: ParserPtr -> ParserPtr -> IO ()
-
-foreign import ccall unsafe "XML_SetXmlDeclHandler"
-  xmlSetxmldeclhandler :: ParserPtr -> FunPtr CXMLDeclarationHandler -> IO ()
-
-foreign import ccall unsafe "XML_SetStartElementHandler"
-  xmlSetstartelementhandler :: ParserPtr -> ((FunPtr (ParserPtr -> ((Ptr CChar) -> ((Ptr (Ptr CChar)) -> (IO ())))) -> (IO ())))
-
-foreign import ccall unsafe "XML_SetEndElementHandler"
-  xmlSetendelementhandler :: ParserPtr -> ((FunPtr (ParserPtr -> ((Ptr CChar) -> (IO ()))) -> (IO ())))
-  
-foreign import ccall unsafe "XML_SetCharacterDataHandler"
-  xmlSetcharacterdatahandler :: ParserPtr -> ((FunPtr (ParserPtr -> ((Ptr CChar) -> (CInt -> (IO ())))) -> (IO ())))
-  
-foreign import ccall unsafe "XML_SetStartCdataSectionHandler"
-  xmlSetstartcdatahandler :: ParserPtr -> FunPtr CStartCDataHandler -> IO ()
-
-foreign import ccall unsafe "XML_SetEndCdataSectionHandler"
-  xmlSetendcdatahandler :: ParserPtr -> FunPtr CStartCDataHandler -> IO ()
-  
-foreign import ccall unsafe "XML_SetCommentHandler"
-  xmlSetcommenthandler :: ParserPtr -> ((FunPtr (ParserPtr -> ((Ptr CChar) -> (IO ()))) -> (IO ())))
-  
-foreign import ccall unsafe "XML_SetProcessingInstructionHandler"
-  xmlSetprocessinginstructionhandler :: ParserPtr -> ((FunPtr (ParserPtr -> ((Ptr CChar) -> ((Ptr CChar) -> (IO ())))) -> (IO ())))
-
-foreign import ccall safe "XML_Parse"
-  doParseChunk'_ :: ParserPtr -> ((Ptr CChar) -> (CInt -> (CInt -> (IO CInt))))
-
-foreign import ccall unsafe "XML_UseForeignDTD"
-  xmlUseForeignDTD :: ParserPtr     -- ^ parser
-                   -> CChar         -- ^ use foreign DTD? (external entity ref
-                                    -- handler will be called with publicID &
-                                    -- systemID set to null
-                   -> IO ()
-
-foreign import ccall "&XML_ParserFree" parserFree :: FunPtr (ParserPtr -> IO ())
-foreign import ccall "XML_ParserFree" parserFree' :: ParserPtr -> IO ()
-
-type CExternalEntityRefHandler = ParserPtr   -- parser
-                              -> Ptr CChar   -- context
-                              -> Ptr CChar   -- base
-                              -> Ptr CChar   -- systemID
-                              -> Ptr CChar   -- publicID
-                              -> IO ()
-
-foreign import ccall unsafe "wrapper"
-  mkCExternalEntityRefHandler :: CExternalEntityRefHandler
-                              -> IO (FunPtr CExternalEntityRefHandler)
-
-
-foreign import ccall unsafe "XML_SetExternalEntityRefHandler"
-  xmlSetExternalEntityRefHandler :: ParserPtr
-                                 -> FunPtr CExternalEntityRefHandler
-                                 -> IO ()
-
-foreign import ccall unsafe "XML_SetSkippedEntityHandler"
-  xmlSetSkippedEntityHandler :: ParserPtr
-                             -> FunPtr CSkippedEntityHandler
-                             -> IO ()
-
-foreign import ccall unsafe "XML_ExternalEntityParserCreate"
-  xmlExternalEntityParserCreate :: ParserPtr
-                                -> CString   -- ^ context
-                                -> CString   -- ^ encoding
-                                -> IO ParserPtr
-
-type CSkippedEntityHandler =  ParserPtr -- user data pointer
-                           -> CString   -- entity name
-                           -> CInt      -- is a parameter entity?
-                           -> IO ()
-
-foreign import ccall safe "wrapper"
-  mkCSkippedEntityHandler :: CSkippedEntityHandler
-                          -> IO (FunPtr CSkippedEntityHandler)
-
-
-wrapExternalEntityRefHandler :: Parser
-                             -> ExternalEntityRefHandler
-                             -> CExternalEntityRefHandler
-wrapExternalEntityRefHandler parser handler = h
-  where
-    h _ context base systemID publicID = do
-        stillRunning <- handler parser context base systemID publicID
-        unless stillRunning $ stopp parser
-
-
-wrapSkippedEntityHandler :: Parser
-                         -> SkippedEntityHandler
-                         -> CSkippedEntityHandler
-wrapSkippedEntityHandler parser handler = h
-  where
-    h pp entityName i = do
-        stillRunning <- handler pp entityName (fromIntegral i)
-        unless stillRunning $ stopp parser
-
-
-setExternalEntityRefHandler :: Parser -> ExternalEntityRefHandler -> IO ()
-setExternalEntityRefHandler parser h =
-    writeIORef ref $ Just $ wrapExternalEntityRefHandler parser h
-  where
-    ref = _externalEntityRefHandler parser
-
-setSkippedEntityHandler :: Parser -> SkippedEntityHandler -> IO ()
-setSkippedEntityHandler parser h =
-    writeIORef ref $ Just $ wrapSkippedEntityHandler parser h
-  where
-    ref = _skippedEntityHandler parser
-
 -- Note on word sizes:
 --
 -- on expat 2.0:
@@ -774,6 +126,96 @@
     :: ParserPtr -> IO CInt
 foreign import ccall unsafe "expat.h XML_ErrorString" xmlErrorString
     :: CInt -> IO CString
-foreign import ccall unsafe "expat.h XML_StopParser" xmlStopParser
-    :: ParserPtr -> CInt -> IO ()
+
+type HParser = B.ByteString -> Bool -> IO (ForeignPtr Word8, CInt, Maybe XMLParseError)
+
+foreign import ccall unsafe "hexpatNewParser"
+  _hexpatNewParser :: Ptr CChar -> CInt -> IO MyParserPtr
+
+foreign import ccall unsafe "hexpatGetParser"
+  _hexpatGetParser :: MyParserPtr -> ParserPtr
+
+data MyParser_struct
+type MyParserPtr = Ptr MyParser_struct
+
+foreign import ccall "&hexpatFreeParser" hexpatFreeParser :: FunPtr (MyParserPtr -> IO ())
+
+hexpatNewParser :: Maybe Encoding
+                -> Maybe (B.ByteString -> Maybe B.ByteString)  -- ^ Entity decoder
+                -> Bool        -- ^ Whether to include input locations
+                -> IO (HParser, IO XMLParseLocation)
+hexpatNewParser enc mDecoder locations =
+    withOptEncoding enc $ \cEnc -> do
+        parser <- newForeignPtr hexpatFreeParser =<< _hexpatNewParser cEnc (cFromBool locations)
+        return (parse parser, withForeignPtr parser $ \mp -> getParseLocation $ _hexpatGetParser mp)
+  where
+    parse parser = case mDecoder of
+        Nothing -> \text final ->
+            alloca $ \ppData ->
+            alloca $ \pLen ->
+            withBStringLen text $ \(textBuf, textLen) ->
+            withForeignPtr parser $ \pp -> do
+                ok <- unStatus <$> _hexpatParseUnsafe pp textBuf textLen (cFromBool final) ppData pLen
+                pData <- peek ppData
+                len <- peek pLen
+                err <- if ok
+                    then return Nothing
+                    else Just <$> getError (_hexpatGetParser pp)
+                fpData <- newForeignPtr funPtrFree pData
+                return (fpData, len, err)
+        Just decoder -> \text final ->
+            alloca $ \ppData ->
+            alloca $ \pLen ->
+            withBStringLen text $ \(textBuf, textLen) ->
+            withForeignPtr parser $ \pp -> do
+                eh <- mkCEntityHandler . wrapCEntityHandler $ decoder
+                _hexpatSetEntityHandler pp eh
+                ok <- unStatus <$> _hexpatParseSafe pp textBuf textLen (cFromBool final) ppData pLen
+                freeHaskellFunPtr eh
+                pData <- peek ppData
+                len <- peek pLen
+                err <- if ok
+                    then return Nothing
+                    else Just <$> getError (_hexpatGetParser pp)
+                fpData <- newForeignPtr funPtrFree pData
+                return (fpData, len, err)
+
+foreign import ccall unsafe "hexpatParse"
+  _hexpatParseUnsafe :: MyParserPtr -> Ptr CChar -> CInt -> CInt -> Ptr (Ptr Word8) -> Ptr CInt -> IO CInt
+
+foreign import ccall safe "hexpatParse"
+  _hexpatParseSafe :: MyParserPtr -> Ptr CChar -> CInt -> CInt -> Ptr (Ptr Word8) -> Ptr CInt -> IO CInt
+
+type CEntityHandler = Ptr CChar -> IO (Ptr CChar)
+
+foreign import ccall safe "wrapper"
+  mkCEntityHandler :: CEntityHandler
+                   -> IO (FunPtr CEntityHandler)
+
+peekByteStringLen :: CStringLen -> IO B.ByteString
+{-# INLINE peekByteStringLen #-}
+peekByteStringLen (cstr, len) =
+    I.create (fromIntegral len) $ \ptr ->
+        I.memcpy ptr (castPtr cstr) (fromIntegral len)
+
+wrapCEntityHandler :: (B.ByteString -> Maybe B.ByteString) -> CEntityHandler
+wrapCEntityHandler handler = h
+  where
+    h cname = do
+        sz <- fromIntegral <$> I.c_strlen cname
+        name <- peekByteStringLen (cname, sz)
+        case handler name of
+            Just text -> do
+                let (fp, offset, len) = I.toForeignPtr text
+                withForeignPtr fp $ \ctextBS -> do
+                    ctext <- mallocBytes (len + 1) :: IO CString
+                    I.memcpy (castPtr ctext) (ctextBS `plusPtr` offset) (fromIntegral len)
+                    poke (ctext `plusPtr` len) (0 :: CChar)
+                    return ctext
+            Nothing -> return nullPtr
+
+foreign import ccall unsafe "hexpatSetEntityHandler"
+  _hexpatSetEntityHandler :: MyParserPtr -> FunPtr CEntityHandler -> IO ()
+
+foreign import ccall "&free" funPtrFree :: FunPtr (Ptr Word8 -> IO ())
 
diff --git a/Text/XML/Expat/Internal/NodeClass.hs b/Text/XML/Expat/Internal/NodeClass.hs
--- a/Text/XML/Expat/Internal/NodeClass.hs
+++ b/Text/XML/Expat/Internal/NodeClass.hs
@@ -7,7 +7,7 @@
 
 import Control.Monad (mzero, liftM)
 import Data.Functor.Identity
-import Data.List.Class
+import Data.List.Class (List(..), ListItem(..), cons, fromList, mapL, toList)
 import Data.Monoid (Monoid)
 import Text.XML.Expat.SAX (GenericXMLString)
 
@@ -108,15 +108,6 @@
 
     -- | Generic text node constructor.
     mkText :: text -> n c tag text
-
--- | DEPRECATED. Map an element non-recursively, allowing the tag type to be changed.
-mapElement :: NodeClass n c =>
-              ((tag, [(tag, text)], c (n c tag text))
-           -> (tag', [(tag', text)], c (n c tag' text)))
-           -> n c tag text
-           -> n c tag' text
-{-# DEPRECATED mapElement "renamed to modifyElement" #-}
-mapElement = modifyElement
 
 -- | Change a list of nodes recursively from one container type to another, with
 -- a specified function to convert the container type.
diff --git a/Text/XML/Expat/Namespaced.hs b/Text/XML/Expat/Namespaced.hs
deleted file mode 100644
--- a/Text/XML/Expat/Namespaced.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# OPTIONS_HADDOCK hide #-}
-module Text.XML.Expat.Namespaced
-        {-# DEPRECATED "Use Text.XML.Expat.Text or Text.XML.Expat.Annotated instead" #-}
-    (
-        module Text.XML.Expat.Internal.Namespaced
-    ) where
-
-import Text.XML.Expat.Internal.Namespaced
-
diff --git a/Text/XML/Expat/NodeClass.hs b/Text/XML/Expat/NodeClass.hs
deleted file mode 100644
--- a/Text/XML/Expat/NodeClass.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# OPTIONS_HADDOCK hide #-}
-module Text.XML.Expat.NodeClass
-       {-# DEPRECATED "Use Text.XML.Expat.Text or Text.XML.Expat.Annotated instead" #-}
-    (
-        module Text.XML.Expat.Internal.NodeClass
-    ) where
-
-import Text.XML.Expat.Internal.NodeClass
-
diff --git a/Text/XML/Expat/Proc.hs b/Text/XML/Expat/Proc.hs
--- a/Text/XML/Expat/Proc.hs
+++ b/Text/XML/Expat/Proc.hs
@@ -6,7 +6,7 @@
 import Text.XML.Expat.SAX
 
 import Control.Monad
-import Data.List.Class
+import Data.List.Class (filter)
 import Data.Maybe(listToMaybe)
 import Data.Monoid
 import Prelude hiding (filter)
diff --git a/Text/XML/Expat/Qualified.hs b/Text/XML/Expat/Qualified.hs
deleted file mode 100644
--- a/Text/XML/Expat/Qualified.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# OPTIONS_HADDOCK hide #-}
-module Text.XML.Expat.Qualified
-       {-# DEPRECATED "Use Text.XML.Expat.Text or Text.XML.Expat.Annotated instead" #-}
-    (
-        module Text.XML.Expat.Internal.Qualified
-    ) where
-
-import Text.XML.Expat.Internal.Qualified
-
diff --git a/Text/XML/Expat/SAX.hs b/Text/XML/Expat/SAX.hs
--- a/Text/XML/Expat/SAX.hs
+++ b/Text/XML/Expat/SAX.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, CPP, ScopedTypeVariables, FlexibleInstances #-}
+{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, CPP, ScopedTypeVariables, FlexibleInstances, GADTs #-}
+{-# OPTIONS_GHC -fno-cse -fno-full-laziness #-}
 
 -- hexpat, a Haskell wrapper for expat
 -- Copyright (C) 2008 Evan Martin <martine@danga.com>
@@ -16,7 +17,6 @@
   ParseOptions(..),
   SAXEvent(..),
 
-  textFromCString,
   parse,
   parseG,
   parseLocations,
@@ -28,41 +28,36 @@
   -- * Variants that throw exceptions
   XMLParseException(..),
 
-  -- * Helpers
-  setEntityDecoder,
-
   -- * Abstraction of string types
-  GenericXMLString(..),
-
-  -- * Deprecated parse functions
-  parseSAX,
-  parseSAXLocations,
-  parseSAXLocationsThrowing,
-  parseSAXThrowing,
-  ParserOptions,
-  defaultParserOptions
+  GenericXMLString(..)
   ) where
 
-import Text.XML.Expat.Internal.IO hiding (parse)
+import Control.Concurrent.MVar
+import Control.Exception as Exc
+import Text.XML.Expat.Internal.IO
+import Data.Bits
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import qualified Data.ByteString.Internal as I
-import Data.IORef
+import Data.Int
 import Data.ByteString.Internal (c2w, w2c, c_strlen)
 import qualified Data.Monoid as M
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
 import qualified Codec.Binary.UTF8.String as U8
+import Data.List.Class (List(..), ListItem(..), cons, fromList, mapL)
 import Data.Typeable
-import Data.List.Class hiding (tail)
-import Control.Exception.Extensible as Exc
+import Data.Word
 import Control.Applicative
 import Control.DeepSeq
 import Control.Monad
 import System.IO.Unsafe
-import Foreign.C.String
+import Foreign.C
+import Foreign.ForeignPtr
+import Foreign.Marshal.Array
 import Foreign.Ptr
+import Foreign.Storable
 
 
 data ParseOptions tag text = ParseOptions
@@ -74,18 +69,10 @@
           -- be decoded into text using the supplied lookup function
     }
 
-{-# DEPRECATED ParserOptions "renamed to ParseOptions" #-}
-type ParserOptions tag text = ParseOptions tag text
-
 defaultParseOptions :: ParseOptions tag text
 defaultParseOptions = ParseOptions Nothing Nothing
 
--- | DEPRECATED. Renamed to defaultParseOptions.
-defaultParserOptions :: ParseOptions tag text
-{-# DEPRECATED defaultParserOptions "renamed to defaultParseOptions" #-}
-defaultParserOptions = defaultParseOptions
 
-
 -- | An abstraction for any string type you want to use as xml text (that is,
 -- attribute values or element text content). If you want to use a
 -- new string type with /hexpat/, you must make it an instance of
@@ -98,7 +85,7 @@
     gxHead :: s -> Char
     gxTail :: s -> s
     gxBreakOn :: Char -> s -> (s, s)
-    gxFromCStringLen :: CStringLen -> IO s
+    gxFromByteString :: B.ByteString -> s
     gxToByteString :: s -> B.ByteString
 
 instance GenericXMLString String where
@@ -109,7 +96,7 @@
     gxHead = head
     gxTail = tail
     gxBreakOn c = break (==c)
-    gxFromCStringLen cstr = U8.decode . B.unpack <$> peekByteStringLen cstr
+    gxFromByteString = U8.decode . B.unpack
     gxToByteString = B.pack . map c2w . U8.encodeString
 
 instance GenericXMLString B.ByteString where
@@ -120,7 +107,7 @@
     gxHead = w2c . B.head
     gxTail = B.tail
     gxBreakOn c = B.break (== c2w c)
-    gxFromCStringLen = peekByteStringLen
+    gxFromByteString = id
     gxToByteString = id
 
 instance GenericXMLString T.Text where
@@ -140,16 +127,9 @@
 #else
     gxBreakOn c = T.breakBy (==c)
 #endif
-    gxFromCStringLen cstr = TE.decodeUtf8 <$> peekByteStringLen cstr
+    gxFromByteString = TE.decodeUtf8
     gxToByteString = TE.encodeUtf8
 
-peekByteStringLen :: CStringLen -> IO B.ByteString
-{-# INLINE peekByteStringLen #-}
-peekByteStringLen (cstr, len) =
-    I.create (fromIntegral len) $ \ptr ->
-        I.memcpy ptr (castPtr cstr) (fromIntegral len)
-
-
 data SAXEvent tag text =
     XMLDeclaration text (Maybe text) (Maybe Bool) |
     StartElement tag [(tag, text)] |
@@ -173,139 +153,150 @@
     rnf (Comment text) = rnf text
     rnf (FailDocument err) = rnf err
 
--- | Converts a 'CString' to a 'GenericXMLString' type.
-textFromCString :: GenericXMLString text => CString -> IO text
-{-# INLINE textFromCString #-}
-textFromCString cstr = do
-    len <- c_strlen cstr
-    gxFromCStringLen (cstr, fromIntegral len)
-
--- | A helper for configuring the hexpat parser to use the specified entity
--- decoder.
-setEntityDecoder :: (GenericXMLString tag, GenericXMLString text)
-                 => Parser
-                 -> (tag -> Maybe text)   -- ^ Entity decoder
-                 -> (ParserPtr -> text -> IO ())       -- ^ Code to insert character data into the document
-                 -> IO ()
-setEntityDecoder parser decoder insertText = do
-    setUseForeignDTD parser True
-    setExternalEntityRefHandler parser eh
-    setSkippedEntityHandler parser skip
-
-  where
-    skip _  _ 1 = return False
-    skip pp entityName 0 = do
-        en <- textFromCString entityName
-        let mbt = decoder en
-        maybe (return False)
-              (\t -> do
-                   insertText pp t
-                   return True)
-              mbt
-    skip _ _ _ = undefined
-
-    eh pp ctx _ systemID publicID =
-        if systemID == nullPtr && publicID == nullPtr
-           then withCStringLen "" $ \c -> do
-               parseExternalEntityReference pp ctx Nothing c
-           else return False
-
 -- | Parse a generalized list of ByteStrings containing XML to SAX events.
 -- In the event of an error, FailDocument is the last element of the output list.
 parseG :: forall tag text l . (GenericXMLString tag, GenericXMLString text, List l) =>
           ParseOptions tag text -- ^ Parse options
        -> l ByteString          -- ^ Input text (a lazy ByteString)
        -> l (SAXEvent tag text)
-parseG opts inputBlocks = runParser inputBlocks parser queueRef cacheRef
-  where
-    (parser, queueRef, cacheRef) = unsafePerformIO $ do
-        let enc = overrideEncoding opts
-        let mEntityDecoder = entityDecoder opts
-
-        parser <- newParser enc
-        queueRef <- newIORef []
-
-        case mEntityDecoder of
-            Just deco -> setEntityDecoder parser deco $ \_ txt -> do
-                modifyIORef queueRef (CharacterData txt:)
-            Nothing -> return ()
-
-        setXMLDeclarationHandler parser $ \_ cVer cEnc cSd -> do
-            ver <- textFromCString cVer
-            mEnc <- if cEnc == nullPtr
-                then return Nothing
-                else Just <$> textFromCString cEnc
-            let sd = if cSd < 0
-                    then Nothing
-                    else Just $ if cSd /= 0 then True else False
-            modifyIORef queueRef (XMLDeclaration ver mEnc sd:)
-            return True
-
-        setStartElementHandler parser $ \_ cName cAttrs -> do
-            name <- textFromCString cName
-            attrs <- forM cAttrs $ \(cAttrName,cAttrValue) -> do
-                attrName <- textFromCString cAttrName
-                attrValue <- textFromCString cAttrValue
-                return (attrName, attrValue)
-            modifyIORef queueRef (StartElement name attrs:)
-            return True
+{-# NOINLINE parseG #-}
+parseG opts inputBlocks = mapL (return . fst) $ parseImpl opts inputBlocks False noExtra failureA
+  where noExtra _ offset = return ((), offset)
+        failureA _ = return ()
 
-        setEndElementHandler parser $ \_ cName -> do
-            name <- textFromCString cName
-            modifyIORef queueRef (EndElement name:)
-            return True
+-- | Parse a generalized list of ByteStrings containing XML to SAX events.
+-- In the event of an error, FailDocument is the last element of the output list.
+parseLocationsG :: forall tag text l . (GenericXMLString tag, GenericXMLString text, List l) =>
+                   ParseOptions tag text -- ^ Parse options
+                -> l ByteString          -- ^ Input text (a lazy ByteString)
+                -> l (SAXEvent tag text, XMLParseLocation)
+{-# NOINLINE parseLocationsG #-}
+parseLocationsG opts inputBlocks = parseImpl opts inputBlocks True fetchLocation id
+  where
+    fetchLocation pBuf offset = do
+        [a, b, c, d] <- peekArray 4 (pBuf `plusPtr` offset :: Ptr Int64)
+        return (XMLParseLocation a b c d, offset + 32)
 
-        setCharacterDataHandler parser $ \_ cText -> do
-            txt <- gxFromCStringLen cText
-            modifyIORef queueRef (CharacterData txt:)
-            return True
-            
-        setStartCDataHandler parser $ \_  -> do
-            modifyIORef queueRef (StartCData :)
-            return True
-            
-        setEndCDataHandler parser $ \_  -> do
-            modifyIORef queueRef (EndCData :)
-            return True
-            
-        setProcessingInstructionHandler parser $ \_ cTarget cText -> do
-            target <- textFromCString cTarget
-            txt <- textFromCString cText
-            modifyIORef queueRef (ProcessingInstruction target txt :)
-            return True
-            
-        setCommentHandler parser $ \_ cText -> do
-            txt <- textFromCString cText
-            modifyIORef queueRef (Comment txt :)
-            return True
+parseImpl :: forall a tag text l . (GenericXMLString tag, GenericXMLString text, List l) =>
+             ParseOptions tag text -- ^ Parse options
+          -> l ByteString          -- ^ Input text (a lazy ByteString)
+          -> Bool                  -- ^ True to add locations to binary output
+          -> (Ptr Word8 -> Int -> IO (a, Int)) -- ^ Fetch extra data
+          -> (IO XMLParseLocation -> IO a)     -- ^ Fetch a value for failure case 
+          -> l (SAXEvent tag text, a)
+parseImpl opts inputBlocks addLocations extra failureA = runParser inputBlocks parse cacheRef
+  where
+    (parse, getLocation, cacheRef) = unsafePerformIO $ do
+        (parse, getLocation) <- hexpatNewParser
+            (overrideEncoding opts)
+            ((\decode -> fmap gxToByteString . decode . gxFromByteString) <$> entityDecoder opts)
+            addLocations
 
-        cacheRef <- newIORef Nothing
-        return (parser, queueRef, cacheRef)
+        cacheRef <- newMVar Nothing
+        return (parse, getLocation, cacheRef)
 
-    runParser iblks parser queueRef cacheRef = joinL $ do
+    runParser iblks parse cacheRef = joinL $ do
         li <- runList iblks
         return $ unsafePerformIO $ do
-            mCached <- readIORef cacheRef
+            mCached <- takeMVar cacheRef
             case mCached of
-                Just l -> return l
+                Just l -> do
+                    putMVar cacheRef mCached
+                    return l
                 Nothing -> do
-                    rema <- case li of
-                            Nil         -> do
-                                mError <- withParser parser $ \pp -> parseChunk pp B.empty True
-                                return $ handleFailure mError mzero
-                            Cons blk t -> unsafeInterleaveIO $ do
-                                mError <- withParser parser $ \pp -> parseChunk pp blk False
-                                cacheRef' <- newIORef Nothing
-                                return $ handleFailure mError (runParser t parser queueRef cacheRef')
-                    queue <- readIORef queueRef
-                    writeIORef queueRef []
-                    let l = fromList (reverse queue) `mplus` rema
-                    writeIORef cacheRef (Just l)
+                    (saxen, rema) <- case li of
+                        Nil         -> do
+                            (buf, len, mError) <- parse B.empty True
+                            saxen <- parseBuf buf len extra
+                            rema <- handleFailure mError mzero
+                            return (saxen, rema)
+                        Cons blk t -> {-unsafeInterleaveIO $-} do
+                            (buf, len, mError) <- parse blk False
+                            saxen <- parseBuf buf len extra
+                            cacheRef' <- newMVar Nothing
+                            rema <- handleFailure mError (runParser t parse cacheRef')
+                            return (saxen, rema)
+                    let l = fromList saxen `mplus` rema
+                    putMVar cacheRef (Just l)
                     return l
       where
-        handleFailure (Just err) _ = FailDocument err `cons` mzero
-        handleFailure Nothing    l = l
+        handleFailure (Just err) _ = do a <- failureA getLocation
+                                        return $ (FailDocument err, a) `cons` mzero
+        handleFailure Nothing    l = return l
 
+parseBuf :: (GenericXMLString tag, GenericXMLString text) =>
+            ForeignPtr Word8 -> CInt -> (Ptr Word8 -> Int -> IO (a, Int)) -> IO [(SAXEvent tag text, a)]
+parseBuf buf _ processExtra = withForeignPtr buf $ \pBuf -> doit [] pBuf 0
+  where
+    roundUp32 offset = (offset + 3) .&. complement 3
+    doit acc pBuf offset0 = offset0 `seq` do
+        typ <- peek (pBuf `plusPtr` offset0 :: Ptr Word32)
+        (a, offset) <- processExtra pBuf (offset0 + 4)
+        case typ of
+            0 -> return (reverse acc)
+            1 -> do
+                nAtts <- peek (pBuf `plusPtr` offset :: Ptr Word32)
+                let pName = pBuf `plusPtr` (offset + 4)
+                lName <- fromIntegral <$> c_strlen pName
+                let name = gxFromByteString $ I.fromForeignPtr buf (offset + 4) lName
+                (atts, offset') <- foldM (\(atts, offset) _ -> do
+                        let pAtt = pBuf `plusPtr` offset
+                        lAtt <- fromIntegral <$> c_strlen pAtt
+                        let att = gxFromByteString $ I.fromForeignPtr buf offset lAtt
+                            offset' = offset + lAtt + 1
+                            pValue = pBuf `plusPtr` offset'
+                        lValue <- fromIntegral <$> c_strlen pValue
+                        let value = gxFromByteString $ I.fromForeignPtr buf offset' lValue
+                        return ((att, value):atts, offset' + lValue + 1)
+                    ) ([], offset + 4 + lName + 1) [1,3..nAtts]
+                doit ((StartElement name (reverse atts), a) : acc) pBuf (roundUp32 offset')
+            2 -> do
+                let pName = pBuf `plusPtr` offset
+                lName <- fromIntegral <$> c_strlen pName
+                let name = gxFromByteString $ I.fromForeignPtr buf offset lName
+                    offset' = offset + lName + 1
+                doit ((EndElement name, a) : acc) pBuf (roundUp32 offset')
+            3 -> do
+                len <- fromIntegral <$> peek (pBuf `plusPtr` offset :: Ptr Word32)
+                let text = gxFromByteString $ I.fromForeignPtr buf (offset + 4) len
+                    offset' = offset + 4 + len
+                doit ((CharacterData text, a) : acc) pBuf (roundUp32 offset')
+            4 -> do
+                let pEnc = pBuf `plusPtr` offset
+                lEnc <- fromIntegral <$> c_strlen pEnc
+                let enc = gxFromByteString $ I.fromForeignPtr buf offset lEnc
+                    offset' = offset + lEnc + 1
+                    pVer = pBuf `plusPtr` offset'
+                pVerFirst <- peek (castPtr pVer :: Ptr Word8)
+                (mVer, offset'') <- case pVerFirst of
+                    0 -> return (Nothing, offset' + 1)
+                    1 -> do
+                        lVer <- fromIntegral <$> c_strlen (pVer `plusPtr` 1)
+                        return (Just $ gxFromByteString $ I.fromForeignPtr buf (offset' + 1) lVer, offset' + 1 + lVer + 1)
+                    _ -> error "hexpat: bad data from C land"
+                cSta <- peek (pBuf `plusPtr` offset'' :: Ptr Int8)
+                let sta = if cSta < 0  then Nothing else
+                          if cSta == 0 then Just False else
+                                            Just True
+                doit ((XMLDeclaration enc mVer sta, a) : acc) pBuf (roundUp32 (offset'' + 1))
+            5 -> doit ((StartCData, a) : acc) pBuf offset
+            6 -> doit ((EndCData, a) : acc) pBuf offset
+            7 -> do
+                let pTarget = pBuf `plusPtr` offset
+                lTarget <- fromIntegral <$> c_strlen pTarget
+                let target = gxFromByteString $ I.fromForeignPtr buf offset lTarget
+                    offset' = offset + lTarget + 1
+                    pData = pBuf `plusPtr` offset'
+                lData <- fromIntegral <$> c_strlen pData
+                let dat = gxFromByteString $ I.fromForeignPtr buf offset' lData
+                doit ((ProcessingInstruction target dat, a) : acc) pBuf (roundUp32 (offset' + lData + 1))
+            8 -> do
+                let pText = pBuf `plusPtr` offset
+                lText <- fromIntegral <$> c_strlen pText
+                let text = gxFromByteString $ I.fromForeignPtr buf offset lText
+                doit ((Comment text, a) : acc) pBuf (roundUp32 (offset + lText + 1))
+            _ -> error "hexpat: bad data from C land"
+
 -- | Lazily parse XML to SAX events. In the event of an error, FailDocument is
 -- the last element of the output list.
 parse :: (GenericXMLString tag, GenericXMLString text) =>
@@ -315,132 +306,12 @@
 parse opts input = parseG opts (L.toChunks input)
 
 
--- | DEPRECATED: Use 'parse' instead.
---
--- Lazily parse XML to SAX events. In the event of an error, FailDocument is
--- the last element of the output list. Deprecated in favour of new
--- 'Text.XML.Expat.SAX.parse'
-parseSAX :: (GenericXMLString tag, GenericXMLString text) =>
-            Maybe Encoding      -- ^ Optional encoding override
-         -> L.ByteString        -- ^ Input text (a lazy ByteString)
-         -> [SAXEvent tag text]
-{-# DEPRECATED parseSAX "use Text.XML.Expat.SAX.parse instead" #-}
-parseSAX enc = parse (ParseOptions enc Nothing)
-
-
 -- | An exception indicating an XML parse error, used by the /..Throwing/ variants.
 data XMLParseException = XMLParseException XMLParseError
     deriving (Eq, Show, Typeable)
 
 instance Exception XMLParseException where
 
-
--- | Parse a generalized list of ByteStrings containing XML to SAX events.
--- In the event of an error, FailDocument is the last element of the output list.
-parseLocationsG :: forall tag text l . (GenericXMLString tag, GenericXMLString text, List l) =>
-                   ParseOptions tag text -- ^ Parse options
-                -> l ByteString          -- ^ Input text (a lazy ByteString)
-                -> l (SAXEvent tag text, XMLParseLocation)
-parseLocationsG opts inputBlocks = runParser inputBlocks parser queueRef cacheRef
-  where
-    (parser, queueRef, cacheRef) = unsafePerformIO $ do
-        let enc = overrideEncoding opts
-        let mEntityDecoder = entityDecoder opts
-
-        parser <- newParser enc
-        queueRef <- newIORef []
-
-        case mEntityDecoder of
-            Just deco -> setEntityDecoder parser deco $ \pp txt -> do
-                loc <- getParseLocation pp
-                modifyIORef queueRef ((CharacterData txt, loc):)
-            Nothing -> return ()
-
-        setXMLDeclarationHandler parser $ \pp cVer cEnc cSd -> do
-            ver <- textFromCString cVer
-            mEnc <- if cEnc == nullPtr
-                then return Nothing
-                else Just <$> textFromCString cEnc
-            let sd = if cSd < 0
-                    then Nothing
-                    else Just $ if cSd /= 0 then True else False
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((XMLDeclaration ver mEnc sd, loc):)
-            return True
-
-        setStartElementHandler parser $ \pp cName cAttrs -> do
-            name <- textFromCString cName
-            attrs <- forM cAttrs $ \(cAttrName,cAttrValue) -> do
-                attrName <- textFromCString cAttrName
-                attrValue <- textFromCString cAttrValue
-                return (attrName, attrValue)
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((StartElement name attrs,loc):)
-            return True
-
-        setEndElementHandler parser $ \pp cName -> do
-            name <- textFromCString cName
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((EndElement name, loc):)
-            return True
-
-        setCharacterDataHandler parser $ \pp cText -> do
-            txt <- gxFromCStringLen cText
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((CharacterData txt, loc):)
-            return True
-            
-        setStartCDataHandler parser $ \pp -> do
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((StartCData, loc):)
-            return True
-            
-        setEndCDataHandler parser $ \pp -> do
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((EndCData,loc):)
-            return True
-            
-        setProcessingInstructionHandler parser $ \pp cTarget cText -> do
-            target <- textFromCString cTarget
-            txt <- textFromCString cText
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((ProcessingInstruction target txt, loc):)
-            return True
-            
-        setCommentHandler parser $ \pp cText -> do
-            txt <- textFromCString cText
-            loc <- getParseLocation pp
-            modifyIORef queueRef ((Comment txt, loc):)
-            return True
-
-        cacheRef <- newIORef Nothing
-        return (parser, queueRef, cacheRef)
-
-    runParser iblks parser queueRef cacheRef = joinL $ do
-        li <- runList iblks
-        return $ unsafePerformIO $ do
-            mCached <- readIORef cacheRef
-            case mCached of
-                Just l -> return l
-                Nothing -> do
-                    rema <- case li of
-                            Nil         -> do
-                                mError <- withParser parser $ \pp -> parseChunk pp B.empty True
-                                handleFailure mError mzero
-                            Cons blk t -> unsafeInterleaveIO $ do
-                                mError <- withParser parser $ \pp -> parseChunk pp blk False
-                                cacheRef' <- newIORef Nothing
-                                handleFailure mError (runParser t parser queueRef cacheRef')
-                    queue <- readIORef queueRef
-                    writeIORef queueRef []
-                    let l = fromList (reverse queue) `mplus` rema
-                    writeIORef cacheRef (Just l)
-                    return l
-      where
-        handleFailure (Just err) _ = do loc <- withParser parser getParseLocation
-                                        return $ (FailDocument err, loc) `cons` mzero
-        handleFailure Nothing    l = return l
-
 -- | A variant of parseSAX that gives a document location with each SAX event.
 parseLocations :: (GenericXMLString tag, GenericXMLString text) =>
                   ParseOptions tag text  -- ^ Parse options
@@ -448,17 +319,7 @@
                -> [(SAXEvent tag text, XMLParseLocation)]
 parseLocations opts input = parseLocationsG opts (L.toChunks input)
 
--- | DEPRECATED: Use 'parseLocations' instead.
---
--- A variant of parseSAX that gives a document location with each SAX event.
-parseSAXLocations :: (GenericXMLString tag, GenericXMLString text) =>
-            Maybe Encoding      -- ^ Optional encoding override
-         -> L.ByteString        -- ^ Input text (a lazy ByteString)
-         -> [(SAXEvent tag text, XMLParseLocation)]
-{-# DEPRECATED parseSAXLocations "use Text.XML.Expat.SAX.parseLocations instead" #-}
-parseSAXLocations enc = parseLocations (ParseOptions enc Nothing)
 
-
 -- | Lazily parse XML to SAX events. In the event of an error, throw
 -- 'XMLParseException'.
 --
@@ -477,18 +338,6 @@
     freakOut other = other
 
 
--- | DEPRECATED: Use 'parseThrowing' instead.
---
--- Lazily parse XML to SAX events. In the event of an error, throw
--- 'XMLParseException'.
-parseSAXThrowing :: (GenericXMLString tag, GenericXMLString text) =>
-                    Maybe Encoding      -- ^ Optional encoding override
-                 -> L.ByteString        -- ^ Input text (a lazy ByteString)
-                 -> [SAXEvent tag text]
-{-# DEPRECATED parseSAXThrowing "use Text.XML.Expat.SAX.parseThrowing instead" #-}
-parseSAXThrowing mEnc = parseThrowing (ParseOptions mEnc Nothing)
-
-
 -- | A variant of parseSAX that gives a document location with each SAX event.
 -- In the event of an error, throw 'XMLParseException'.
 --
@@ -505,16 +354,3 @@
   where
     freakOut (FailDocument err, _) = Exc.throw $ XMLParseException err
     freakOut other = other
-
-
--- | DEPRECATED: Used 'parseLocationsThrowing' instead.
---
--- A variant of parseSAX that gives a document location with each SAX event.
--- In the event of an error, throw 'XMLParseException'.
-parseSAXLocationsThrowing :: (GenericXMLString tag, GenericXMLString text) =>
-                             Maybe Encoding      -- ^ Optional encoding override
-                          -> L.ByteString        -- ^ Input text (a lazy ByteString)
-                          -> [(SAXEvent tag text, XMLParseLocation)]
-{-# DEPRECATED parseSAXLocationsThrowing "use Text.XML.Expat.SAX.parseLocationsThrowing instead" #-}
-parseSAXLocationsThrowing mEnc =
-    parseLocationsThrowing (ParseOptions mEnc Nothing)
diff --git a/Text/XML/Expat/Tree.hs b/Text/XML/Expat/Tree.hs
--- a/Text/XML/Expat/Tree.hs
+++ b/Text/XML/Expat/Tree.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, FlexibleInstances,
-        MultiParamTypeClasses, TypeFamilies #-}
+        MultiParamTypeClasses, TypeFamilies, ScopedTypeVariables #-}
 
 -- hexpat, a Haskell wrapper for expat
 -- Copyright (C) 2008 Evan Martin <martine@danga.com>
@@ -128,60 +128,35 @@
   saxToTreeG,
 
   -- * Abstraction of string types
-  GenericXMLString(..),
-
-  -- * Deprecated
-  eAttrs,
-  Nodes,
-  UNodes,
-  QNodes,
-  NNodes,
-  parseTree,
-  parseTree',
-  parseSAX,
-  parseSAXLocations,
-  parseTreeThrowing,
-  parseSAXThrowing,
-  parseSAXLocationsThrowing,
-  ParserOptions,
-  defaultParserOptions
+  GenericXMLString(..)
   ) where
 
-import Text.XML.Expat.Internal.IO hiding (parse,parse')
-import qualified Text.XML.Expat.Internal.IO as IO
-import Text.XML.Expat.SAX ( ParseOptions(..)
-                          , XMLParseException(..)
-                          , SAXEvent(..)
-                          , defaultParseOptions
-                          , textFromCString
-                          , parseSAX
-                          , parseSAXLocations
-                          , parseSAXLocationsThrowing
-                          , parseSAXThrowing
+import Text.XML.Expat.SAX ( Encoding(..)
                           , GenericXMLString(..)
-                          , setEntityDecoder
-                          , ParserOptions
-                          , defaultParserOptions )
+                          , ParseOptions(..)
+                          , defaultParseOptions
+                          , SAXEvent(..)
+                          , XMLParseError(..)
+                          , XMLParseException(..)
+                          , XMLParseLocation(..) )
 import qualified Text.XML.Expat.SAX as SAX
 import Text.XML.Expat.Internal.Namespaced
 import Text.XML.Expat.Internal.NodeClass
 import Text.XML.Expat.Internal.Qualified
 
 import Control.Arrow
-import Control.Monad (forM, mplus, mzero)
+import Control.Monad (mplus, mzero)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Lazy as L
-import Data.IORef
 import Data.List.Class
 import Data.Monoid (Monoid,mempty,mappend)
 import Control.DeepSeq
-import System.IO.Unsafe
 
 
 -- | The tree representation of the XML document.
 --
--- @c@ is the container type for the element's children, which is [] in the
--- @hexpat@ package, and a monadic list type for @hexpat-iteratee@.
+-- @c@ is the container type for the element's children, which would normally be [],
+-- but could potentially be a monadic list type to allow for chunked I/O.
 --
 -- @tag@ is the tag type, which can either be one of several string types,
 -- or a special type from the @Text.XML.Expat.Namespaced@ or
@@ -221,46 +196,17 @@
 -- @ListOf (UNode Text)@.
 type Node tag text = NodeG [] tag text
 
-eAttrs :: Node tag text -> [(tag, text)]
-{-# DEPRECATED eAttrs "use eAttributes instead" #-}
-eAttrs = eAttributes
-
 instance (NFData tag, NFData text) => NFData (NodeG [] tag text) where
     rnf (Element nam att chi) = rnf (nam, att, chi)
     rnf (Text txt) = rnf txt
 
--- | DEPRECATED: Use [Node tag text] instead.
---
--- Type alias for nodes.
-type Nodes tag text = [Node tag text]
-{-# DEPRECATED Nodes "use [Node tag text] instead" #-}
-
--- | DEPRECATED: Use [UNode text] instead.
---
--- Type alias for nodes with unqualified tag names where tag and
--- text are the same string type. DEPRECATED.
-type UNodes text = Nodes text text
-{-# DEPRECATED UNodes "use [UNode text] instead" #-}
-
 -- | Type alias for a node with unqualified tag names where tag and
 -- text are the same string type.
 type UNode text = Node text text
 
--- | DEPRECATED: Use [QNode text] instead.
---
--- Type alias for nodes where qualified names are used for tags
-{-# DEPRECATED QNodes "use [QNode text] instead" #-}
-type QNodes text = [Node (QName text) text]
-
 -- | Type alias for a node where qualified names are used for tags
 type QNode text = Node (QName text) text
 
--- | DEPRECATED: Use [NNode text] instead.
---
--- Type alias for nodes where namespaced names are used for tags.
-{-# DEPRECATED NNodes "use [NNode text] instead" #-}
-type NNodes text = [Node (NName text) text]
-
 -- | Type alias for a node where namespaced names are used for tags
 type NNode text = Node (NName text) text
 
@@ -328,65 +274,9 @@
           ParseOptions tag text  -- ^ Parse options
        -> ByteString              -- ^ Input text (a strict ByteString)
        -> Either XMLParseError (Node tag text)
-parse' opts doc = unsafePerformIO $ runParse where
-  runParse = do
-    let enc = overrideEncoding opts
-    let mEntityDecoder = entityDecoder opts
-
-    parser <- newParser enc
-
-    -- We maintain the invariant that the stack always has one element,
-    -- whose only child at the end of parsing is the root of the actual tree.
-    let emptyString = gxFromString ""
-    stack <- newIORef [Element emptyString [] []]
-
-    case mEntityDecoder of
-        Just deco -> setEntityDecoder parser deco $ \_ txt -> do
-            modifyIORef stack (text txt)
-        Nothing -> return ()
-
-    setStartElementHandler parser $ \_ cName cAttrs -> do
-        name <- textFromCString cName
-        attrs <- forM cAttrs $ \(cAttrName,cAttrValue) -> do
-            attrName <- textFromCString cAttrName
-            attrValue <- textFromCString cAttrValue
-            return (attrName, attrValue)
-        modifyIORef stack (start name attrs)
-        return True
-    setEndElementHandler parser $ \_ _ -> do
-        modifyIORef stack end
-        return True
-    setCharacterDataHandler parser $ \_ cText -> do
-        txt <- gxFromCStringLen cText
-        modifyIORef stack (text txt)
-        return True
-    mError <- IO.parse' parser doc
-    case mError of
-        Just err -> return $ Left err
-        Nothing -> do
-            [Element _ _ [root]] <- readIORef stack
-            return $ Right root
-
-  start name attrs stack = Element name attrs [] : stack
-  text str (cur:rest) = modifyChildren (Text str:) cur : rest
-  text _ [] = impossible
-  end (cur:parent:rest) =
-    let node = modifyChildren reverse cur in
-    modifyChildren (node:) parent : rest
-  end _ = impossible
-  impossible = error "parse' impossible"
-
-
--- | DEPRECATED: use 'parse' instead.
---
--- Strictly parse XML to tree. Returns error message or valid parsed tree.
-parseTree' :: (GenericXMLString tag, GenericXMLString text) =>
-              Maybe Encoding      -- ^ Optional encoding override
-           -> ByteString          -- ^ Input text (a strict ByteString)
-           -> Either XMLParseError (Node tag text)
-{-# DEPRECATED parseTree' "use Text.XML.Expat.parse' instead" #-}
-parseTree' enc = parse' (ParseOptions enc Nothing)
-
+parse' opts doc = case parse opts (L.fromChunks [doc]) of
+    (xml, Nothing) -> Right xml
+    (_, Just err) -> Left err
 
 -- | A lower level function that lazily converts a SAX stream into a tree structure.
 saxToTree :: GenericXMLString tag =>
@@ -414,34 +304,42 @@
 
 -- | A lower level function that converts a generalized SAX stream into a tree structure.
 -- Ignores parse errors.
-saxToTreeG :: (GenericXMLString tag, List l) =>
+saxToTreeG :: forall tag text l . (GenericXMLString tag, List l) =>
               l (SAXEvent tag text)
            -> ItemM l (NodeG l tag text)
 saxToTreeG events = do
-    (elts, _) <- process events
-    findRoot elts
+    li <- runList (process events)
+    case li of
+        Cons elt@(Element _ _ _ ) _ -> return elt
+        _                           -> return $ Element (gxFromString "") mzero mzero
   where
-    findRoot elts = do
-        li <- runList elts
-        case li of
-            Cons elt@(Element _ _ _ ) _ -> return elt
-            Cons _ rema -> findRoot rema
-            Nil -> return $ Element (gxFromString "") mzero mzero
-    process events = do
-        li <- runList events
-        case li of
-            Nil -> return (mzero, mzero)
-            Cons (StartElement name attrs) rema -> do
-                (children, rema') <- process rema
-                (out, rema'') <- process rema'
-                return (Element name attrs children `cons` out, rema'')
-            Cons (EndElement _) rema -> return (mzero, rema)
-            Cons (CharacterData txt) rema -> do
-                (out, rema') <- process rema
-                return (Text txt `cons` out, rema')
-            --Cons (FailDocument err) rema = (mzero, mzero)
-            Cons _ rema -> process rema
+    process :: l (SAXEvent tag text) -> l (NodeG l tag text)
+    process events = joinL $ process_ events
+      where
+        process_ :: l (SAXEvent tag text) -> ItemM l (l (NodeG l tag text))
+        process_ events = do
+            li <- runList events
+            case li of
+                Nil -> return mzero
+                Cons (StartElement name attrs) rema -> do
+                    return $ Element name attrs (process rema) `cons` process (stripElement rema)
+                Cons (EndElement _) _ -> return mzero
+                Cons (CharacterData txt) rema -> return $ Text txt `cons` process rema
+                Cons _ rema -> process_ rema
 
+    stripElement :: l (SAXEvent tag text) -> l (SAXEvent tag text)
+    stripElement events = joinL $ stripElement_ 0 events
+      where
+        stripElement_ :: Int -> l (SAXEvent tag text) -> ItemM l (l (SAXEvent tag text))
+        stripElement_ level events = level `seq` do
+            li <- runList events
+            case li of
+                Nil -> return mzero
+                Cons (StartElement _ _) rema -> stripElement_ (level+1) rema
+                Cons (EndElement _) rema -> if level == 0 then return rema 
+                                                          else stripElement_ (level-1) rema
+                Cons _ rema -> stripElement_ level rema
+
 -- | Lazily parse XML to tree. Note that forcing the XMLParseError return value
 -- will force the entire parse.  Therefore, to ensure lazy operation, don't
 -- check the error status until you have processed the tree.
@@ -460,19 +358,6 @@
        -> ItemM l (NodeG l tag text)
 parseG opts = saxToTreeG . SAX.parseG opts
 
--- | DEPREACTED: Use 'parse' instead.
---
--- Lazily parse XML to tree. Note that forcing the XMLParseError return value
--- will force the entire parse.  Therefore, to ensure lazy operation, don't
--- check the error status until you have processed the tree.
-parseTree :: (GenericXMLString tag, GenericXMLString text) =>
-             Maybe Encoding      -- ^ Optional encoding override
-          -> L.ByteString        -- ^ Input text (a lazy ByteString)
-          -> (Node tag text, Maybe XMLParseError)
-{-# DEPRECATED parseTree "use Text.XML.Expat.Tree.parse instead" #-}
-parseTree mEnc = parse (ParseOptions mEnc Nothing)
-
-
 -- | Lazily parse XML to tree. In the event of an error, throw 'XMLParseException'.
 --
 -- @parseThrowing@ can throw an exception from pure code, which is generally a bad
@@ -485,14 +370,3 @@
       -> L.ByteString           -- ^ Input text (a lazy ByteString)
       -> Node tag text
 parseThrowing opts bs = fst $ saxToTree $ SAX.parseThrowing opts bs
-
-
--- | DEPRECATED: Use 'parseThrowing' instead.
---
--- Lazily parse XML to tree. In the event of an error, throw 'XMLParseException'.
-parseTreeThrowing :: (GenericXMLString tag, GenericXMLString text) =>
-             Maybe Encoding      -- ^ Optional encoding override
-          -> L.ByteString        -- ^ Input text (a lazy ByteString)
-          -> Node tag text
-{-# DEPRECATED parseTreeThrowing "use Text.XML.Expat.Tree.parseThrowing instead" #-}
-parseTreeThrowing mEnc = parseThrowing (ParseOptions mEnc Nothing)
diff --git a/cbits/README b/cbits/README
new file mode 100644
--- /dev/null
+++ b/cbits/README
@@ -0,0 +1,139 @@
+
+                        Expat, Release 2.2.1
+
+This is Expat, a C library for parsing XML, written by James Clark.
+Expat is a stream-oriented XML parser.  This means that you register
+handlers with the parser before starting the parse.  These handlers
+are called when the parser discovers the associated structures in the
+document being parsed.  A start tag is an example of the kind of
+structures for which you may register handlers.
+
+Windows users should use the expat_win32bin package, which includes
+both precompiled libraries and executables, and source code for
+developers.
+
+Expat is free software.  You may copy, distribute, and modify it under
+the terms of the License contained in the file COPYING distributed
+with this package.  This license is the same as the MIT/X Consortium
+license.
+
+Versions of Expat that have an odd minor version (the middle number in
+the release above), are development releases and should be considered
+as beta software.  Releases with even minor version numbers are
+intended to be production grade software.
+
+If you are building Expat from a check-out from the CVS repository,
+you need to run a script that generates the configure script using the
+GNU autoconf and libtool tools.  To do this, you need to have
+autoconf 2.58 or newer. Run the script like this:
+
+        ./buildconf.sh
+
+Once this has been done, follow the same instructions as for building
+from a source distribution.
+
+To build Expat from a source distribution, you first run the
+configuration shell script in the top level distribution directory:
+
+        ./configure
+
+There are many options which you may provide to configure (which you
+can discover by running configure with the --help option).  But the
+one of most interest is the one that sets the installation directory.
+By default, the configure script will set things up to install
+libexpat into /usr/local/lib, expat.h into /usr/local/include, and
+xmlwf into /usr/local/bin.  If, for example, you'd prefer to install
+into /home/me/mystuff/lib, /home/me/mystuff/include, and
+/home/me/mystuff/bin, you can tell configure about that with:
+
+        ./configure --prefix=/home/me/mystuff
+        
+Another interesting option is to enable 64-bit integer support for
+line and column numbers and the over-all byte index:
+
+        ./configure CPPFLAGS=-DXML_LARGE_SIZE
+        
+However, such a modification would be a breaking change to the ABI
+and is therefore not recommended for general use - e.g. as part of
+a Linux distribution - but rather for builds with special requirements.
+
+After running the configure script, the "make" command will build
+things and "make install" will install things into their proper
+location.  Have a look at the "Makefile" to learn about additional
+"make" options.  Note that you need to have write permission into
+the directories into which things will be installed.
+
+If you are interested in building Expat to provide document
+information in UTF-16 encoding rather than the default UTF-8, follow
+these instructions (after having run "make distclean"):
+
+        1. For UTF-16 output as unsigned short (and version/error
+           strings as char), run:
+
+               ./configure CPPFLAGS=-DXML_UNICODE
+
+           For UTF-16 output as wchar_t (incl. version/error strings),
+           run:
+
+               ./configure CFLAGS="-g -O2 -fshort-wchar" \
+                           CPPFLAGS=-DXML_UNICODE_WCHAR_T
+
+        2. Edit the MakeFile, changing:
+
+               LIBRARY = libexpat.la
+
+           to:
+
+               LIBRARY = libexpatw.la
+
+           (Note the additional "w" in the library name.)
+
+        3. Run "make buildlib" (which builds the library only).
+           Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
+
+        4. Run "make installlib" (which installs the library only).
+           Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
+           
+Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
+value for DESTDIR, and the rest of the make file using only DESTDIR.
+It works as follows:
+   $ make install DESTDIR=/path/to/image
+overrides the in-makefile set DESTDIR, while both
+   $ INSTALL_ROOT=/path/to/image make install
+   $ make install INSTALL_ROOT=/path/to/image
+use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
+environment, because variable-setting priority is
+1) commandline
+2) in-makefile
+3) environment  
+
+Note: This only applies to the Expat library itself, building UTF-16 versions
+of xmlwf and the tests is currently not supported.         
+
+Note for Solaris users:  The "ar" command is usually located in
+"/usr/ccs/bin", which is not in the default PATH.  You will need to
+add this to your path for the "make" command, and probably also switch
+to GNU make (the "make" found in /usr/ccs/bin does not seem to work
+properly -- apparently it does not understand .PHONY directives).  If
+you're using ksh or bash, use this command to build:
+
+        PATH=/usr/ccs/bin:$PATH make
+
+When using Expat with a project using autoconf for configuration, you
+can use the probing macro in conftools/expat.m4 to determine how to
+include Expat.  See the comments at the top of that file for more
+information.
+
+A reference manual is available in the file doc/reference.html in this
+distribution.
+
+The homepage for this project is http://www.libexpat.org/.  There
+are links there to connect you to the bug reports page.  If you need
+to report a bug when you don't have access to a browser, you may also
+send a bug report by email to expat-bugs@mail.libexpat.org.
+
+Discussion related to the direction of future expat development takes
+place on expat-discuss@mail.libexpat.org.  Archives of this list and
+other Expat-related lists may be found at:
+
+        http://mail.libexpat.org/mailman/listinfo/
diff --git a/cbits/amigaconfig.h b/cbits/amigaconfig.h
deleted file mode 100644
--- a/cbits/amigaconfig.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 */
diff --git a/cbits/expat.h b/cbits/expat.h
--- a/cbits/expat.h
+++ b/cbits/expat.h
@@ -95,7 +95,9 @@
   /* Added in 2.0. */
   XML_ERROR_RESERVED_PREFIX_XML,
   XML_ERROR_RESERVED_PREFIX_XMLNS,
-  XML_ERROR_RESERVED_NAMESPACE_URI
+  XML_ERROR_RESERVED_NAMESPACE_URI,
+  /* Added in 2.2.1. */
+  XML_ERROR_INVALID_ARGUMENT
 };
 
 enum XML_Content_Type {
@@ -342,7 +344,7 @@
                          XML_EntityDeclHandler handler);
 
 /* OBSOLETE -- OBSOLETE -- OBSOLETE
-   This handler has been superceded by the EntityDeclHandler above.
+   This handler has been superseded by the EntityDeclHandler above.
    It is provided here for backward compatibility.
 
    This is called for a declaration of an unparsed (NDATA) entity.
@@ -706,6 +708,7 @@
      be called, despite an external subset being parsed.
    Note: If XML_DTD is not defined when Expat is compiled, returns
      XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+   Note: If parser == NULL, returns XML_ERROR_INVALID_ARGUMENT.
 */
 XMLPARSEAPI(enum XML_Error)
 XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
@@ -729,19 +732,43 @@
    to the XML_StartElementHandler that were specified in the start-tag
    rather than defaulted. Each attribute/value pair counts as 2; thus
    this correspondds to an index into the atts array passed to the
-   XML_StartElementHandler.
+   XML_StartElementHandler.  Returns -1 if parser == NULL.
 */
 XMLPARSEAPI(int)
 XML_GetSpecifiedAttributeCount(XML_Parser parser);
 
 /* Returns the index of the ID attribute passed in the last call to
-   XML_StartElementHandler, or -1 if there is no ID attribute.  Each
-   attribute/value pair counts as 2; thus this correspondds to an
-   index into the atts array passed to the XML_StartElementHandler.
+   XML_StartElementHandler, or -1 if there is no ID attribute or
+   parser == NULL.  Each attribute/value pair counts as 2; thus this
+   correspondds to an index into the atts array passed to the
+   XML_StartElementHandler.
 */
 XMLPARSEAPI(int)
 XML_GetIdAttributeIndex(XML_Parser parser);
 
+#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).
@@ -878,11 +905,22 @@
    entities is requested; otherwise it will return non-zero.
    Note: If XML_SetParamEntityParsing is called after XML_Parse or
       XML_ParseBuffer, then it has no effect and will always return 0.
+   Note: If parser == NULL, the function will do nothing and return 0.
 */
 XMLPARSEAPI(int)
 XML_SetParamEntityParsing(XML_Parser parser,
                           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.
+   Note: If parser == NULL, the function will do nothing and return 0.
+*/
+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.
 */
@@ -904,6 +942,10 @@
    the location is the location of the character at which the error
    was detected; otherwise the location is the location of the last
    parse event, as described above.
+
+   Note: XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber
+   return 0 to indicate an error.
+   Note: XML_GetCurrentByteIndex returns -1 to indicate an error.
 */
 XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
 XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
@@ -941,9 +983,12 @@
 
 /* Exposing the memory handling functions used in Expat */
 XMLPARSEAPI(void *)
+XML_ATTR_MALLOC
+XML_ATTR_ALLOC_SIZE(2)
 XML_MemMalloc(XML_Parser parser, size_t size);
 
 XMLPARSEAPI(void *)
+XML_ATTR_ALLOC_SIZE(3)
 XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
 
 XMLPARSEAPI(void)
@@ -984,7 +1029,8 @@
   XML_FEATURE_SIZEOF_XML_CHAR,
   XML_FEATURE_SIZEOF_XML_LCHAR,
   XML_FEATURE_NS,
-  XML_FEATURE_LARGE_SIZE
+  XML_FEATURE_LARGE_SIZE,
+  XML_FEATURE_ATTR_INFO
   /* Additional features must be added to the end of this enum. */
 };
 
@@ -998,13 +1044,11 @@
 XML_GetFeatureList(void);
 
 
-/* Expat follows the GNU/Linux convention of odd number minor version for
-   beta/development releases and even number minor version for stable
-   releases. Micro is bumped with each release, and set to 0 with each
-   change to major or minor version.
+/* Expat follows the semantic versioning convention.
+   See http://semver.org.
 */
 #define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 0
+#define XML_MINOR_VERSION 2
 #define XML_MICRO_VERSION 1
 
 #ifdef __cplusplus
diff --git a/cbits/expat_external.h b/cbits/expat_external.h
--- a/cbits/expat_external.h
+++ b/cbits/expat_external.h
@@ -65,13 +65,27 @@
 #endif
 #endif  /* not defined XML_STATIC */
 
+#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
+#define XMLIMPORT __attribute__ ((visibility ("default")))
+#endif
 
 /* If we didn't define it above, define it away: */
 #ifndef XMLIMPORT
 #define XMLIMPORT
 #endif
 
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#define XML_ATTR_MALLOC __attribute__((__malloc__))
+#else
+#define XML_ATTR_MALLOC
+#endif
 
+#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+#define XML_ATTR_ALLOC_SIZE(x)  __attribute__((__alloc_size__(x)))
+#else
+#define XML_ATTR_ALLOC_SIZE(x)
+#endif
+
 #define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
 
 #ifdef __cplusplus
@@ -79,7 +93,10 @@
 #endif
 
 #ifdef XML_UNICODE_WCHAR_T
-#define XML_UNICODE
+# define XML_UNICODE
+# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
+#  error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+# endif
 #endif
 
 #ifdef XML_UNICODE     /* Information is UTF-16 encoded. */
diff --git a/cbits/internal.h b/cbits/internal.h
--- a/cbits/internal.h
+++ b/cbits/internal.h
@@ -71,3 +71,25 @@
 #define inline
 #endif
 #endif
+
+#ifndef UNUSED_P
+# ifdef __GNUC__
+#  define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
+# else
+#  define UNUSED_P(p) UNUSED_ ## p
+# endif
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cbits/macconfig.h b/cbits/macconfig.h
deleted file mode 100644
--- a/cbits/macconfig.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*================================================================
-** 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 */
diff --git a/cbits/siphash.h b/cbits/siphash.h
new file mode 100644
--- /dev/null
+++ b/cbits/siphash.h
@@ -0,0 +1,344 @@
+/* ==========================================================================
+ * siphash.h - SipHash-2-4 in a single header file
+ * --------------------------------------------------------------------------
+ * Derived by William Ahern from the reference implementation[1] published[2]
+ * by Jean-Philippe Aumasson and Daniel J. Berstein. Licensed in kind.
+ * by Jean-Philippe Aumasson and Daniel J. Berstein.
+ * Minimal changes by Sebastian Pipping on top, details below.
+ * Licensed under the CC0 Public Domain Dedication license.
+ *
+ * 1. https://www.131002.net/siphash/siphash24.c
+ * 2. https://www.131002.net/siphash/
+ * --------------------------------------------------------------------------
+ * HISTORY:
+ *
+ * 2017-06-10  (Sebastian Pipping)
+ *   - Clarify license note in the header
+ *   - Address C89 issues:
+ *     - Stop using inline keyword (and let compiler decide)
+ *     - Turn integer suffix ULL to UL
+ *     - Replace _Bool by int
+ *     - Turn macro siphash24 into a function
+ *     - Address invalid conversion (void pointer) by explicit cast
+ *   - Always expose sip24_valid (for self-tests)
+ *
+ * 2012-11-04 - Born.  (William Ahern)
+ * --------------------------------------------------------------------------
+ * USAGE:
+ *
+ * SipHash-2-4 takes as input two 64-bit words as the key, some number of
+ * message bytes, and outputs a 64-bit word as the message digest. This
+ * implementation employs two data structures: a struct sipkey for
+ * representing the key, and a struct siphash for representing the hash
+ * state.
+ *
+ * For converting a 16-byte unsigned char array to a key, use either the
+ * macro sip_keyof or the routine sip_tokey. The former instantiates a
+ * compound literal key, while the latter requires a key object as a
+ * parameter.
+ *
+ * 	unsigned char secret[16];
+ * 	arc4random_buf(secret, sizeof secret);
+ * 	struct sipkey *key = sip_keyof(secret);
+ *
+ * For hashing a message, use either the convenience macro siphash24 or the
+ * routines sip24_init, sip24_update, and sip24_final.
+ *
+ * 	struct siphash state;
+ * 	void *msg;
+ * 	size_t len;
+ * 	uint64_t hash;
+ *
+ * 	sip24_init(&state, key);
+ * 	sip24_update(&state, msg, len);
+ * 	hash = sip24_final(&state);
+ *
+ * or
+ *
+ * 	hash = siphash24(msg, len, key);
+ *
+ * To convert the 64-bit hash value to a canonical 8-byte little-endian
+ * binary representation, use either the macro sip_binof or the routine
+ * sip_tobin. The former instantiates and returns a compound literal array,
+ * while the latter requires an array object as a parameter.
+ * --------------------------------------------------------------------------
+ * NOTES:
+ *
+ * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers
+ *   lacking compound literal support. Instead, you must use the lower-level
+ *   interfaces which take as parameters the temporary state objects.
+ *
+ * o Uppercase macros may evaluate parameters more than once. Lowercase
+ *   macros should not exhibit any such side effects.
+ * ==========================================================================
+ */
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include <stddef.h> /* size_t */
+#include <stdint.h> /* uint64_t uint32_t uint8_t */
+
+
+#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ( (x) >> (64 - (b))))
+
+#define SIP_U32TO8_LE(p, v) \
+	(p)[0] = (uint8_t)((v) >>  0); (p)[1] = (uint8_t)((v) >>  8); \
+	(p)[2] = (uint8_t)((v) >> 16); (p)[3] = (uint8_t)((v) >> 24);
+
+#define SIP_U64TO8_LE(p, v) \
+	SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >>  0)); \
+	SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
+
+#define SIP_U8TO64_LE(p) \
+	(((uint64_t)((p)[0]) <<  0) | \
+	 ((uint64_t)((p)[1]) <<  8) | \
+	 ((uint64_t)((p)[2]) << 16) | \
+	 ((uint64_t)((p)[3]) << 24) | \
+	 ((uint64_t)((p)[4]) << 32) | \
+	 ((uint64_t)((p)[5]) << 40) | \
+	 ((uint64_t)((p)[6]) << 48) | \
+	 ((uint64_t)((p)[7]) << 56))
+
+
+#define SIPHASH_INITIALIZER { 0, 0, 0, 0, { 0 }, 0, 0 }
+
+struct siphash {
+	uint64_t v0, v1, v2, v3;
+
+	unsigned char buf[8], *p;
+	uint64_t c;
+}; /* struct siphash */
+
+
+#define SIP_KEYLEN 16
+
+struct sipkey {
+	uint64_t k[2];
+}; /* struct sipkey */
+
+#define sip_keyof(k) sip_tokey(&(struct sipkey){ { 0 } }, (k))
+
+static struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
+	key->k[0] = SIP_U8TO64_LE((const unsigned char *)src);
+	key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8);
+	return key;
+} /* sip_tokey() */
+
+
+#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
+
+static void *sip_tobin(void *dst, uint64_t u64) {
+	SIP_U64TO8_LE((unsigned char *)dst, u64);
+	return dst;
+} /* sip_tobin() */
+
+
+static void sip_round(struct siphash *H, const int rounds) {
+	int i;
+
+	for (i = 0; i < rounds; i++) {
+		H->v0 += H->v1;
+		H->v1 = SIP_ROTL(H->v1, 13);
+		H->v1 ^= H->v0;
+		H->v0 = SIP_ROTL(H->v0, 32);
+
+		H->v2 += H->v3;
+		H->v3 = SIP_ROTL(H->v3, 16);
+		H->v3 ^= H->v2;
+
+		H->v0 += H->v3;
+		H->v3 = SIP_ROTL(H->v3, 21);
+		H->v3 ^= H->v0;
+
+		H->v2 += H->v1;
+		H->v1 = SIP_ROTL(H->v1, 17);
+		H->v1 ^= H->v2;
+		H->v2 = SIP_ROTL(H->v2, 32);
+	}
+} /* sip_round() */
+
+
+static struct siphash *sip24_init(struct siphash *H, const struct sipkey *key) {
+	H->v0 = 0x736f6d6570736575UL ^ key->k[0];
+	H->v1 = 0x646f72616e646f6dUL ^ key->k[1];
+	H->v2 = 0x6c7967656e657261UL ^ key->k[0];
+	H->v3 = 0x7465646279746573UL ^ key->k[1];
+
+	H->p = H->buf;
+	H->c = 0;
+
+	return H;
+} /* sip24_init() */
+
+
+#define sip_endof(a) (&(a)[sizeof (a) / sizeof *(a)])
+
+static struct siphash *sip24_update(struct siphash *H, const void *src, size_t len) {
+	const unsigned char *p = (const unsigned char *)src, *pe = p + len;
+	uint64_t m;
+
+	do {
+		while (p < pe && H->p < sip_endof(H->buf))
+			*H->p++ = *p++;
+
+		if (H->p < sip_endof(H->buf))
+			break;
+
+		m = SIP_U8TO64_LE(H->buf);
+		H->v3 ^= m;
+		sip_round(H, 2);
+		H->v0 ^= m;
+
+		H->p = H->buf;
+		H->c += 8;
+	} while (p < pe);
+
+	return H;
+} /* sip24_update() */
+
+
+static uint64_t sip24_final(struct siphash *H) {
+	char left = H->p - H->buf;
+	uint64_t b = (H->c + left) << 56;
+
+	switch (left) {
+	case 7: b |= (uint64_t)H->buf[6] << 48;
+	case 6: b |= (uint64_t)H->buf[5] << 40;
+	case 5: b |= (uint64_t)H->buf[4] << 32;
+	case 4: b |= (uint64_t)H->buf[3] << 24;
+	case 3: b |= (uint64_t)H->buf[2] << 16;
+	case 2: b |= (uint64_t)H->buf[1] << 8;
+	case 1: b |= (uint64_t)H->buf[0] << 0;
+	case 0: break;
+	}
+
+	H->v3 ^= b;
+	sip_round(H, 2);
+	H->v0 ^= b;
+	H->v2 ^= 0xff;
+	sip_round(H, 4);
+
+	return H->v0 ^ H->v1 ^ H->v2  ^ H->v3;
+} /* sip24_final() */
+
+
+static uint64_t siphash24(const void *src, size_t len, const struct sipkey *key) {
+	struct siphash state = SIPHASH_INITIALIZER;
+	return sip24_final(sip24_update(sip24_init(&state, key), src, len));
+} /* siphash24() */
+
+
+/*
+ * SipHash-2-4 output with
+ * k = 00 01 02 ...
+ * and
+ * in = (empty string)
+ * in = 00 (1 byte)
+ * in = 00 01 (2 bytes)
+ * in = 00 01 02 (3 bytes)
+ * ...
+ * in = 00 01 02 ... 3e (63 bytes)
+ */
+static int sip24_valid(void) {
+	static const unsigned char vectors[64][8] = {
+		{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+		{ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+		{ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+		{ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+		{ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+		{ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+		{ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+		{ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+		{ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+		{ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+		{ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+		{ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+		{ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+		{ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+		{ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+		{ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+		{ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+		{ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+		{ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+		{ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+		{ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+		{ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+		{ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+		{ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+		{ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+		{ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+		{ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+		{ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+		{ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+		{ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+		{ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+		{ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+		{ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+		{ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+		{ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+		{ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+		{ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+		{ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+		{ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+		{ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+		{ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+		{ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+		{ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+		{ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+		{ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+		{ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+		{ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+		{ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+		{ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+		{ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+		{ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+		{ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+		{ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+		{ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+		{ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+		{ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+		{ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+		{ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+		{ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+		{ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+		{ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+		{ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+		{ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+		{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+	};
+	unsigned char in[64];
+	struct sipkey k;
+	size_t i;
+
+	sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017");
+
+	for (i = 0; i < sizeof in; ++i) {
+		in[i] = i;
+
+		if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i]))
+			return 0;
+	}
+
+	return 1;
+} /* sip24_valid() */
+
+
+#if SIPHASH_MAIN
+
+#include <stdio.h>
+
+int main(void) {
+	int ok = sip24_valid();
+
+	if (ok)
+		puts("OK");
+	else
+		puts("FAIL");
+
+	return !ok;
+} /* main() */
+
+#endif /* SIPHASH_MAIN */
+
+
+#endif /* SIPHASH_H */
diff --git a/cbits/winconfig.h b/cbits/winconfig.h
--- a/cbits/winconfig.h
+++ b/cbits/winconfig.h
@@ -17,6 +17,12 @@
 #include <memory.h>
 #include <string.h>
 
+
+#if defined(HAVE_EXPAT_CONFIG_H)  /* e.g. MinGW */
+# include <expat_config.h>
+#else  /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+
 #define XML_NS 1
 #define XML_DTD 1
 #define XML_CONTEXT_BYTES 1024
@@ -26,5 +32,9 @@
 
 /* Windows has memmove() available. */
 #define HAVE_MEMMOVE
+
+
+#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
+
 
 #endif /* ndef WINCONFIG_H */
diff --git a/cbits/xmlparse.c b/cbits/xmlparse.c
--- a/cbits/xmlparse.c
+++ b/cbits/xmlparse.c
@@ -1,6279 +1,6821 @@
 /* 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>
-
-#define XML_BUILDING_EXPAT 1
-
-#ifdef COMPILED_FROM_DSP
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos4__)
-#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(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
-static int
-copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
-
-static NAMED *
-lookup(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 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;
-  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
-};
-
-#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 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 */
-
-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'
-};
-
-XML_Parser XMLCALL
-XML_ParserCreate_MM(const XML_Char *encodingName,
-                    const XML_Memory_Handling_Suite *memsuite,
-                    const XML_Char *nameSep)
-{
-  XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL);
-  if (parser != NULL && ns) {
-    /* implicit context only set for root parser, since child
-       parsers (i.e. external entity parsers) will inherit it
-    */
-    if (!setContext(parser, implicitContext)) {
-      XML_ParserFree(parser);
-      return NULL;
-    }
-  }
-  return parser;
-}
-
-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;
-  }
-  dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
-  if (dataBuf == NULL) {
-    FREE(atts);
-    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);
-      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
-}
-
-/* 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 setContext(parser, implicitContext);
-}
-
-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;
-
-#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;
-  parentParser = oldParser;
-#ifdef XML_DTD
-  paramEntityParsing = oldParamEntityParsing;
-  prologState.inEntityValue = oldInEntityValue;
-  if (context) {
-#endif /* XML_DTD */
-    if (!dtdCopy(_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);
-  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;
-}
-
-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
-}
-
-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;
-  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:
-        result = XML_STATUS_OK;
-        if (isFinal) {
-          ps_parsing = XML_FINISHED;
-          return result;
-        }
-      }
-    }
-
-    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;
-          return XML_STATUS_ERROR;
-        }
-        buffer = temp;
-        if (!buffer) {
-          errorCode = XML_ERROR_NO_MEMORY;
-          eventPtr = eventEndPtr = NULL;
-          processor = errorProcessor;
-          return XML_STATUS_ERROR;
-        }
-        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;
-  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 */
-    }
-  }
-  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    
-    {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(&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(&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(&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;
-    attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
-    temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
-    if (temp == NULL)
-      return XML_ERROR_NO_MEMORY;
-    atts = temp;
-    if (n > oldAttsSize)
-      XmlGetAttributes(enc, attStr, n, atts);
-  }
-
-  appAtts = (const XML_Char **)atts;
-  for (i = 0; i < n; i++) {
-    /* add the name and value to the attribute list */
-    ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
-                                         atts[i].name
-                                         + XmlNameLength(enc, atts[i].name));
-    if (!attId)
-      return XML_ERROR_NO_MEMORY;
-    /* 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 = 0;
-        ((XML_Char *)s)[-1] = 0;  /* clear flag */
-        id = (ATTRIBUTE_ID *)lookup(&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(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_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(&dtd->paramEntities,
-                                    externalSubsetName,
-                                    sizeof(ENTITY));
-      if (!declEntity)
-        return XML_ERROR_NO_MEMORY;
-#endif /* XML_DTD */
-      dtd->hasParamEntityRefs = XML_TRUE;
-      if (startDoctypeDeclHandler) {
-        if (!XmlIsPublicId(enc, s, next, eventPP))
-          return XML_ERROR_PUBLICID;
-        doctypePubid = poolStoreString(&tempPool, enc,
-                                       s + enc->minBytesPerChar,
-                                       next - enc->minBytesPerChar);
-        if (!doctypePubid)
-          return XML_ERROR_NO_MEMORY;
-        normalizePublicId((XML_Char *)doctypePubid);
-        poolFinish(&tempPool);
-        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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(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(&(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(&(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(&(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(&(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(&(newDtd->attributeIds), oldE->idAtt->name, 0);
-    newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
-    if (oldE->prefix)
-      newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes),
-                                      oldE->prefix->name, 0);
-    for (i = 0; i < newE->nDefaultAtts; i++) {
-      newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
-          lookup(&(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(&(newDtd->generalEntities),
-                       &(newDtd->pool),
-                       &(oldDtd->generalEntities)))
-      return 0;
-
-#ifdef XML_DTD
-  if (!copyEntityTable(&(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(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(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(KEY s)
-{
-  unsigned long h = 0;
-  while (*s)
-    h = CHAR_HASH(h, *s++);
-  return h;
-}
-
-static NAMED *
-lookup(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(name) & ((unsigned long)table->size - 1);
-  }
-  else {
-    unsigned long h = hash(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(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;
-    pool->blocks = (BLOCK *)
-      pool->mem->realloc_fcn(pool->blocks,
-                             (offsetof(BLOCK, s)
-                              + blockSize * sizeof(XML_Char)));
-    if (pool->blocks == NULL)
-      return XML_FALSE;
-    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(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+
+   77fea421d361dca90041d0040ecf1dca651167fadf2af79e990e35168d70d933 (2.2.1+)
+*/
+
+#define _GNU_SOURCE                     /* syscall prototype */
+
+#include <stddef.h>
+#include <string.h>                     /* memset(), memcpy() */
+#include <assert.h>
+#include <limits.h>                     /* UINT_MAX */
+#include <stdio.h>                      /* fprintf */
+#include <stdlib.h>                     /* getenv */
+
+#ifdef _WIN32
+#define getpid GetCurrentProcessId
+#else
+#include <sys/time.h>                   /* gettimeofday() */
+#include <sys/types.h>                  /* getpid() */
+#include <unistd.h>                     /* getpid() */
+#endif
+
+#define XML_BUILDING_EXPAT 1
+
+#ifdef _WIN32
+#include "winconfig.h"
+#elif defined(HAVE_EXPAT_CONFIG_H)
+#include <expat_config.h>
+#endif /* ndef _WIN32 */
+
+#include "ascii.h"
+#include "expat.h"
+#include "siphash.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;
+
+static size_t
+keylen(KEY s);
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key);
+
+/* For probing (after a collision) we need a step size relative prime
+   to the hash table size, which is a power of 2. We use double-hashing,
+   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 void
+freeBindings(XML_Parser parser, BINDING *bindings);
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+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(XML_Parser parser);
+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'
+};
+
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+# include <errno.h>
+
+# if defined(HAVE_GETRANDOM)
+#  include <sys/random.h>    /* getrandom */
+# else
+#  include <unistd.h>        /* syscall */
+#  include <sys/syscall.h>   /* SYS_getrandom */
+# endif
+
+/* Obtain entropy on Linux 3.17+ */
+static int
+writeRandomBytes_getrandom(void * target, size_t count) {
+  int success = 0;  /* full count bytes written? */
+  size_t bytesWrittenTotal = 0;
+  const unsigned int getrandomFlags = 0;
+
+  do {
+    void * const currentTarget = (void*)((char*)target + bytesWrittenTotal);
+    const size_t bytesToWrite = count - bytesWrittenTotal;
+
+    const int bytesWrittenMore =
+#if defined(HAVE_GETRANDOM)
+        getrandom(currentTarget, bytesToWrite, getrandomFlags);
+#else
+        syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags);
+#endif
+
+    if (bytesWrittenMore > 0) {
+      bytesWrittenTotal += bytesWrittenMore;
+      if (bytesWrittenTotal >= count)
+        success = 1;
+    }
+  } while (! success && (errno == EINTR || errno == EAGAIN));
+
+  return success;
+}
+
+#endif  /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+
+#ifdef _WIN32
+
+typedef BOOLEAN (APIENTRY *RTLGENRANDOM_FUNC)(PVOID, ULONG);
+
+/* Obtain entropy on Windows XP / Windows Server 2003 and later.
+ * Hint on RtlGenRandom and the following article from libsodioum.
+ *
+ * Michael Howard: Cryptographically Secure Random number on Windows without using CryptoAPI
+ * https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/
+ */
+static int
+writeRandomBytes_RtlGenRandom(void * target, size_t count) {
+  int success = 0;  /* full count bytes written? */
+  const HMODULE advapi32 = LoadLibrary("ADVAPI32.DLL");
+
+  if (advapi32) {
+    const RTLGENRANDOM_FUNC RtlGenRandom
+        = (RTLGENRANDOM_FUNC)GetProcAddress(advapi32, "SystemFunction036");
+    if (RtlGenRandom) {
+      if (RtlGenRandom((PVOID)target, (ULONG)count) == TRUE) {
+        success = 1;
+      }
+    }
+    FreeLibrary(advapi32);
+  }
+
+  return success;
+}
+
+#endif /* _WIN32 */
+
+
+static unsigned long
+gather_time_entropy(void)
+{
+#ifdef _WIN32
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft); /* never fails */
+  return ft.dwHighDateTime ^ ft.dwLowDateTime;
+#else
+  struct timeval tv;
+  int gettimeofday_res;
+
+  gettimeofday_res = gettimeofday(&tv, NULL);
+  assert (gettimeofday_res == 0);
+
+  /* Microseconds time is <20 bits entropy */
+  return tv.tv_usec;
+#endif
+}
+
+#if defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_LIBBSD)
+# include <bsd/stdlib.h>
+#endif
+
+static unsigned long
+ENTROPY_DEBUG(const char * label, unsigned long entropy) {
+  const char * const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
+  if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
+    fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n",
+        label,
+        (int)sizeof(entropy) * 2, entropy,
+        (unsigned long)sizeof(entropy));
+  }
+  return entropy;
+}
+
+static unsigned long
+generate_hash_secret_salt(XML_Parser parser)
+{
+  unsigned long entropy;
+  (void)parser;
+#if defined(HAVE_ARC4RANDOM_BUF) || defined(__CloudABI__)
+  (void)gather_time_entropy;
+  arc4random_buf(&entropy, sizeof(entropy));
+  return ENTROPY_DEBUG("arc4random_buf", entropy);
+#else
+  /* Try high quality providers first .. */
+#ifdef _WIN32
+  if (writeRandomBytes_RtlGenRandom((void *)&entropy, sizeof(entropy))) {
+    return ENTROPY_DEBUG("RtlGenRandom", entropy);
+  }
+#elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+  if (writeRandomBytes_getrandom((void *)&entropy, sizeof(entropy))) {
+    return ENTROPY_DEBUG("getrandom", entropy);
+  }
+#endif
+  /* .. and self-made low quality for backup: */
+
+  /* Process ID is 0 bits entropy if attacker has local access */
+  entropy = gather_time_entropy() ^ getpid();
+
+  /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
+  if (sizeof(unsigned long) == 4) {
+    return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
+  } else {
+    return ENTROPY_DEBUG("fallback(8)",
+        entropy * (unsigned long)2305843009213693951);
+  }
+#endif
+}
+
+static unsigned long
+get_hash_secret_salt(XML_Parser parser) {
+  if (parser->m_parentParser != NULL)
+    return get_hash_secret_salt(parser->m_parentParser);
+  return parser->m_hash_secret_salt;
+}
+
+static XML_Bool  /* only valid for root parser */
+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(parser);
+    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 (parser == NULL)
+      return XML_FALSE;
+
+  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)
+{
+  if (parser == NULL)
+      return XML_STATUS_ERROR;
+  /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+     XXX There's no way for the caller to determine which of the
+     XXX possible error cases caused the XML_STATUS_ERROR return.
+  */
+  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;
+  XML_StartElementHandler oldStartElementHandler;
+  XML_EndElementHandler oldEndElementHandler;
+  XML_CharacterDataHandler oldCharacterDataHandler;
+  XML_ProcessingInstructionHandler oldProcessingInstructionHandler;
+  XML_CommentHandler oldCommentHandler;
+  XML_StartCdataSectionHandler oldStartCdataSectionHandler;
+  XML_EndCdataSectionHandler oldEndCdataSectionHandler;
+  XML_DefaultHandler oldDefaultHandler;
+  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler;
+  XML_NotationDeclHandler oldNotationDeclHandler;
+  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler;
+  XML_NotStandaloneHandler oldNotStandaloneHandler;
+  XML_ExternalEntityRefHandler oldExternalEntityRefHandler;
+  XML_SkippedEntityHandler oldSkippedEntityHandler;
+  XML_UnknownEncodingHandler oldUnknownEncodingHandler;
+  XML_ElementDeclHandler oldElementDeclHandler;
+  XML_AttlistDeclHandler oldAttlistDeclHandler;
+  XML_EntityDeclHandler oldEntityDeclHandler;
+  XML_XmlDeclHandler oldXmlDeclHandler;
+  ELEMENT_TYPE * oldDeclElementType;
+
+  void *oldUserData;
+  void *oldHandlerArg;
+  XML_Bool oldDefaultExpandInternalEntities;
+  XML_Parser oldExternalEntityRefHandlerArg;
+#ifdef XML_DTD
+  enum XML_ParamEntityParsing oldParamEntityParsing;
+  int oldInEntityValue;
+#endif
+  XML_Bool oldns_triplets;
+  /* Note that the new parser shares the same hash secret as the old
+     parser, so that dtdCopy and copyEntityTable can lookup values
+     from hash tables associated with either parser without us having
+     to worry which hash secrets each table has.
+  */
+  unsigned long oldhash_secret_salt;
+
+  /* Validate the oldParser parameter before we pull everything out of it */
+  if (oldParser == NULL)
+    return NULL;
+
+  /* Stash the original parser contents on the stack */
+  oldDtd = _dtd;
+  oldStartElementHandler = startElementHandler;
+  oldEndElementHandler = endElementHandler;
+  oldCharacterDataHandler = characterDataHandler;
+  oldProcessingInstructionHandler = processingInstructionHandler;
+  oldCommentHandler = commentHandler;
+  oldStartCdataSectionHandler = startCdataSectionHandler;
+  oldEndCdataSectionHandler = endCdataSectionHandler;
+  oldDefaultHandler = defaultHandler;
+  oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
+  oldNotationDeclHandler = notationDeclHandler;
+  oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
+  oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
+  oldNotStandaloneHandler = notStandaloneHandler;
+  oldExternalEntityRefHandler = externalEntityRefHandler;
+  oldSkippedEntityHandler = skippedEntityHandler;
+  oldUnknownEncodingHandler = unknownEncodingHandler;
+  oldElementDeclHandler = elementDeclHandler;
+  oldAttlistDeclHandler = attlistDeclHandler;
+  oldEntityDeclHandler = entityDeclHandler;
+  oldXmlDeclHandler = xmlDeclHandler;
+  oldDeclElementType = declElementType;
+
+  oldUserData = userData;
+  oldHandlerArg = handlerArg;
+  oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+  oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+  oldParamEntityParsing = paramEntityParsing;
+  oldInEntityValue = prologState.inEntityValue;
+#endif
+  oldns_triplets = ns_triplets;
+  /* Note that the new parser shares the same hash secret as the old
+     parser, so that dtdCopy and copyEntityTable can lookup values
+     from hash tables associated with either parser without us having
+     to worry which hash secrets each table has.
+  */
+  oldhash_secret_salt = hash_secret_salt;
+
+#ifdef XML_DTD
+  if (!context)
+    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)
+{
+  if (parser != NULL)
+    handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+  if (parser == NULL)
+    return XML_ERROR_INVALID_ARGUMENT;
+#ifdef XML_DTD
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    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)
+{
+  if (parser == NULL)
+    return;
+  /* 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 (parser == NULL)
+    return;
+  if (handlerArg == userData)
+    handlerArg = userData = p;
+  else
+    userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
+  if (p) {
+    p = poolCopyString(&_dtd->pool, p);
+    if (!p)
+      return XML_STATUS_ERROR;
+    curBase = p;
+  }
+  else
+    curBase = NULL;
+  return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+  if (parser == NULL)
+    return NULL;
+  return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+  if (parser == NULL)
+    return -1;
+  return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+  if (parser == NULL)
+    return -1;
+  return idAttIndex;
+}
+
+#ifdef XML_ATTR_INFO
+const XML_AttrInfo * XMLCALL
+XML_GetAttributeInfo(XML_Parser parser)
+{
+  if (parser == NULL)
+    return NULL;
+  return attInfo;
+}
+#endif
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+                      XML_StartElementHandler start,
+                      XML_EndElementHandler end)
+{
+  if (parser == NULL)
+    return;
+  startElementHandler = start;
+  endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+                           XML_StartElementHandler start) {
+  if (parser != NULL)
+    startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+                         XML_EndElementHandler end) {
+  if (parser != NULL)
+    endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+                            XML_CharacterDataHandler handler)
+{
+  if (parser != NULL)
+    characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+                                    XML_ProcessingInstructionHandler handler)
+{
+  if (parser != NULL)
+    processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+                      XML_CommentHandler handler)
+{
+  if (parser != NULL)
+    commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+                           XML_StartCdataSectionHandler start,
+                           XML_EndCdataSectionHandler end)
+{
+  if (parser == NULL)
+    return;
+  startCdataSectionHandler = start;
+  endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+                                XML_StartCdataSectionHandler start) {
+  if (parser != NULL)
+    startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+                              XML_EndCdataSectionHandler end) {
+  if (parser != NULL)
+    endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+                      XML_DefaultHandler handler)
+{
+  if (parser == NULL)
+    return;
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+                            XML_DefaultHandler handler)
+{
+  if (parser == NULL)
+    return;
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+                          XML_StartDoctypeDeclHandler start,
+                          XML_EndDoctypeDeclHandler end)
+{
+  if (parser == NULL)
+    return;
+  startDoctypeDeclHandler = start;
+  endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+                               XML_StartDoctypeDeclHandler start) {
+  if (parser != NULL)
+    startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+                             XML_EndDoctypeDeclHandler end) {
+  if (parser != NULL)
+    endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+                                 XML_UnparsedEntityDeclHandler handler)
+{
+  if (parser != NULL)
+    unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+                           XML_NotationDeclHandler handler)
+{
+  if (parser != NULL)
+    notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+                            XML_StartNamespaceDeclHandler start,
+                            XML_EndNamespaceDeclHandler end)
+{
+  if (parser == NULL)
+    return;
+  startNamespaceDeclHandler = start;
+  endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+                                 XML_StartNamespaceDeclHandler start) {
+  if (parser != NULL)
+    startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+                               XML_EndNamespaceDeclHandler end) {
+  if (parser != NULL)
+    endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+                            XML_NotStandaloneHandler handler)
+{
+  if (parser != NULL)
+    notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+                                XML_ExternalEntityRefHandler handler)
+{
+  if (parser != NULL)
+    externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+  if (parser == NULL)
+    return;
+  if (arg)
+    externalEntityRefHandlerArg = (XML_Parser)arg;
+  else
+    externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+                            XML_SkippedEntityHandler handler)
+{
+  if (parser != NULL)
+    skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+                              XML_UnknownEncodingHandler handler,
+                              void *data)
+{
+  if (parser == NULL)
+    return;
+  unknownEncodingHandler = handler;
+  unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+                          XML_ElementDeclHandler eldecl)
+{
+  if (parser != NULL)
+    elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+                          XML_AttlistDeclHandler attdecl)
+{
+  if (parser != NULL)
+    attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+                         XML_EntityDeclHandler handler)
+{
+  if (parser != NULL)
+    entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+                      XML_XmlDeclHandler handler) {
+  if (parser != NULL)
+    xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+                          enum XML_ParamEntityParsing peParsing)
+{
+  if (parser == NULL)
+    return 0;
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+#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)
+{
+  if (parser == NULL)
+    return 0;
+  if (parser->m_parentParser)
+    return XML_SetHashSalt(parser->m_parentParser, hash_salt);
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+  hash_secret_salt = hash_salt;
+  return 1;
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+  if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) {
+    errorCode = XML_ERROR_INVALID_ARGUMENT;
+    return XML_STATUS_ERROR;
+  }
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    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_Status result;
+    /* Detect overflow (a+b > MAX <==> b > MAX-a) */
+    if (len > ((XML_Size)-1) / 2 - parseEndByteIndex) {
+       errorCode = XML_ERROR_NO_MEMORY;
+       eventPtr = eventEndPtr = NULL;
+       processor = errorProcessor;
+       return XML_STATUS_ERROR;
+    }
+    parseEndByteIndex += len;
+    positionPtr = s;
+    ps_finalBuffer = (XML_Bool)isFinal;
+
+    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) {
+        /* avoid _signed_ integer overflow */
+        char *temp = NULL;
+        const int bytesToAllocate = (int)((unsigned)len * 2U);
+        if (bytesToAllocate > 0) {
+          temp = (buffer == NULL
+                ? (char *)MALLOC(bytesToAllocate)
+                : (char *)REALLOC(buffer, bytesToAllocate));
+        }
+        if (temp == NULL) {
+          errorCode = XML_ERROR_NO_MEMORY;
+          eventPtr = eventEndPtr = NULL;
+          processor = errorProcessor;
+          return XML_STATUS_ERROR;
+        }
+        buffer = temp;
+        bufferLim = buffer + bytesToAllocate;
+      }
+      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;
+
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
+  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)
+{
+  if (parser == NULL)
+    return NULL;
+  if (len < 0) {
+    errorCode = XML_ERROR_NO_MEMORY;
+    return NULL;
+  }
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return NULL;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return NULL;
+  default: ;
+  }
+
+  if (len > bufferLim - bufferEnd) {
+#ifdef XML_CONTEXT_BYTES
+    int keep;
+#endif  /* defined XML_CONTEXT_BYTES */
+    /* Do not invoke signed arithmetic overflow: */
+    int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
+    if (neededSize < 0) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return NULL;
+    }
+#ifdef XML_CONTEXT_BYTES
+    keep = (int)(bufferPtr - buffer);
+    if (keep > XML_CONTEXT_BYTES)
+      keep = XML_CONTEXT_BYTES;
+    neededSize += keep;
+#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 {
+        /* Do not invoke signed arithmetic overflow: */
+        bufferSize = (int) (2U * (unsigned) bufferSize);
+      } while (bufferSize < neededSize && bufferSize > 0);
+      if (bufferSize <= 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        return NULL;
+      }
+      newBuf = (char *)MALLOC(bufferSize);
+      if (newBuf == 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        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)
+{
+  if (parser == NULL)
+    return XML_STATUS_ERROR;
+  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 (parser == NULL)
+    return XML_STATUS_ERROR;
+  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)
+{
+  if (parser == NULL)
+    return;
+  assert(status != NULL);
+  *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+  if (parser == NULL)
+    return XML_ERROR_INVALID_ARGUMENT;
+  return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+  if (parser == NULL)
+    return -1;
+  if (eventPtr)
+    return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
+  return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+  if (parser == NULL)
+    return 0;
+  if (eventEndPtr && eventPtr)
+    return (int)(eventEndPtr - eventPtr);
+  return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+  if (parser == NULL)
+    return NULL;
+  if (eventPtr && buffer) {
+    if (offset != NULL)
+      *offset = (int)(eventPtr - buffer);
+    if (size != NULL)
+      *size   = (int)(bufferEnd - buffer);
+    return buffer;
+  }
+#else
+  (void)parser;
+  (void)offset;
+  (void)size;
+#endif /* defined XML_CONTEXT_BYTES */
+  return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+  if (parser == NULL)
+    return 0;
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+  if (parser == NULL)
+    return 0;
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+  if (parser != NULL)
+    FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+  if (parser == NULL)
+    return NULL;
+  return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+  if (parser == NULL)
+    return NULL;
+  return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+  if (parser != NULL)
+    FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+  if (parser == NULL)
+    return;
+  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;
+            const enum XML_Convert_Result convert_res = XmlConvert(enc,
+                       &fromPtr, rawNameEnd,
+                       (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+            convLen = (int)(toPtr - (XML_Char *)tag->buf);
+            if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
+              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 != XML_ERROR_NONE) {
+          freeBindings(parser, bindings);
+          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);
+        freeBindings(parser, bindings);
+      }
+      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;
+              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = s;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+                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 */
+}
+
+/* This function does not call free() on the allocated memory, merely
+ * moving it to the parser's freeBindingList where it can be freed or
+ * reused as appropriate.
+ */
+static void
+freeBindings(XML_Parser parser, BINDING *bindings)
+{
+  while (bindings) {
+    BINDING *b = bindings;
+
+    /* startNamespaceDeclHandler will have been called for this
+     * binding in addBindings(), so call the end handler now.
+     */
+    if (endNamespaceDeclHandler)
+        endNamespaceDeclHandler(handlerArg, b->prefix->name);
+
+    bindings = bindings->nextTagBinding;
+    b->nextTagBinding = freeBindingList;
+    freeBindingList = b;
+    b->prefix->binding = b->prevPrefixBinding;
+  }
+}
+
+/* Precondition: all arguments must be non-NULL;
+   Purpose:
+   - normalize attributes
+   - 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;
+        struct siphash sip_state;
+        struct sipkey sip_key;
+
+        copy_salt_to_sipkey(parser, &sip_key);
+        sip24_init(&sip_state, &sip_key);
+
+        ((XML_Char *)s)[-1] = 0;  /* clear flag */
+        id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+        if (!id || !id->prefix)
+          return XML_ERROR_NO_MEMORY;
+        b = id->prefix->binding;
+        if (!b)
+          return XML_ERROR_UNBOUND_PREFIX;
+
+        for (j = 0; j < b->uriLen; j++) {
+          const XML_Char c = b->uri[j];
+          if (!poolAppendChar(&tempPool, c))
+            return XML_ERROR_NO_MEMORY;
+        }
+
+        sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
+
+        while (*s++ != XML_T(ASCII_COLON))
+          ;
+
+        sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
+
+        do {  /* copies null terminator */
+          if (!poolAppendChar(&tempPool, *s))
+            return XML_ERROR_NO_MEMORY;
+        } while (*s++);
+
+        uriHash = (unsigned long)sip24_final(&sip_state);
+
+        { /* Check hash table for duplicate of expanded name (uriName).
+             Derived from code in lookup(parser, HASH_TABLE *table, ...).
+          */
+          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;
+              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = next;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+                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;
+    }
+    /* If we get this token, we have the start of what might be a
+       normal tag, but not a declaration (i.e. it doesn't begin with
+       "<!").  In a DTD context, that isn't legal.
+    */
+    else if (tok == XML_TOK_INSTANCE_START) {
+      *nextPtr = next;
+      return XML_ERROR_SYNTAX;
+    }
+    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);
+  /* Set a safe default value in case 'next' does not get set */
+  next = textStart;
+
+#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);
+  /* Set a safe default value in case 'next' does not get set */
+  next = textStart;
+
+#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 *UNUSED_P(s),
+               const char *UNUSED_P(end),
+               const char **UNUSED_P(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)) {
+    enum XML_Convert_Result convert_res;
+    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;
+      convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+      *eventEndPP = s;
+      defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+      *eventPP = s;
+    } while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
+  }
+  else
+    defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+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)
+            return NULL;
+          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) {
+        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 size_t
+keylen(KEY s)
+{
+  size_t len = 0;
+  for (; *s; s++, len++);
+  return len;
+}
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key)
+{
+  key->k[0] = 0;
+  key->k[1] = get_hash_secret_salt(parser);
+}
+
+static unsigned long FASTCALL
+hash(XML_Parser parser, KEY s)
+{
+  struct siphash state;
+  struct sipkey key;
+  (void)sip_tobin;
+  (void)sip24_valid;
+  copy_salt_to_sipkey(parser, &key);
+  sip24_init(&state, &key);
+  sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
+  return (unsigned long)sip24_final(&state);
+}
+
+static NAMED *
+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 (;;) {
+    const enum XML_Convert_Result convert_res = XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+    if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+      break;
+    if (!poolGrow(pool))
+      return NULL;
+  }
+  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 size_t
+poolBytesToAllocateFor(int blockSize)
+{
+  /* Unprotected math would be:
+  ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
+  **
+  ** Detect overflow, avoiding _signed_ overflow undefined behavior
+  ** For a + b * c we check b * c in isolation first, so that addition of a
+  ** on top has no chance of making us accept a small non-negative number
+  */
+  const size_t stretch = sizeof(XML_Char);  /* can be 4 bytes */
+
+  if (blockSize <= 0)
+    return 0;
+
+  if (blockSize > (int)(INT_MAX / stretch))
+    return 0;
+
+  {
+    const int stretchedBlockSize = blockSize * (int)stretch;
+    const int bytesToAllocate = (int)(
+        offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
+    if (bytesToAllocate < 0)
+      return 0;
+
+    return (size_t)bytesToAllocate;
+  }
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+  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) {
+    BLOCK *temp;
+    int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
+    size_t bytesToAllocate;
+
+    if (blockSize < 0)
+      return XML_FALSE;
+
+    bytesToAllocate = poolBytesToAllocateFor(blockSize);
+    if (bytesToAllocate == 0)
+      return XML_FALSE;
+
+    temp = (BLOCK *)
+      pool->mem->realloc_fcn(pool->blocks, (unsigned)bytesToAllocate);
+    if (temp == NULL)
+      return XML_FALSE;
+    pool->blocks = temp;
+    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);
+    size_t bytesToAllocate;
+
+    if (blockSize < 0)
+      return XML_FALSE;
+
+    if (blockSize < INIT_BLOCK_SIZE)
+      blockSize = INIT_BLOCK_SIZE;
+    else {
+      /* Detect overflow, avoiding _signed_ overflow undefined behavior */
+      if ((int)((unsigned)blockSize * 2U) < 0) {
+        return XML_FALSE;
+      }
+      blockSize *= 2;
+    }
+
+    bytesToAllocate = poolBytesToAllocateFor(blockSize);
+    if (bytesToAllocate == 0)
+      return XML_FALSE;
+
+    tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
+    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)
diff --git a/cbits/xmlrole.c b/cbits/xmlrole.c
--- a/cbits/xmlrole.c
+++ b/cbits/xmlrole.c
@@ -4,19 +4,13 @@
 
 #include <stddef.h>
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos4__)
-#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 */
+#endif /* ndef _WIN32 */
 
 #include "expat_external.h"
 #include "internal.h"
@@ -195,9 +189,9 @@
 static int PTRCALL
 prolog2(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -216,9 +210,9 @@
 static int PTRCALL
 doctype0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -264,9 +258,9 @@
 static int PTRCALL
 doctype2(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -281,9 +275,9 @@
 static int PTRCALL
 doctype3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -298,9 +292,9 @@
 static int PTRCALL
 doctype4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -318,9 +312,9 @@
 static int PTRCALL
 doctype5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -437,9 +431,9 @@
 static int PTRCALL
 entity0(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -457,9 +451,9 @@
 static int PTRCALL
 entity1(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -502,9 +496,9 @@
 static int PTRCALL
 entity3(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -519,9 +513,9 @@
 static int PTRCALL
 entity4(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -559,9 +553,9 @@
 static int PTRCALL
 entity6(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -605,9 +599,9 @@
 static int PTRCALL
 entity8(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -622,9 +616,9 @@
 static int PTRCALL
 entity9(PROLOG_STATE *state,
         int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
+        const char *UNUSED_P(ptr),
+        const char *UNUSED_P(end),
+        const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -639,9 +633,9 @@
 static int PTRCALL
 entity10(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -656,9 +650,9 @@
 static int PTRCALL
 notation0(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -697,9 +691,9 @@
 static int PTRCALL
 notation2(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -714,9 +708,9 @@
 static int PTRCALL
 notation3(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -732,9 +726,9 @@
 static int PTRCALL
 notation4(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -753,9 +747,9 @@
 static int PTRCALL
 attlist0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -771,9 +765,9 @@
 static int PTRCALL
 attlist1(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -833,9 +827,9 @@
 static int PTRCALL
 attlist3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -852,9 +846,9 @@
 static int PTRCALL
 attlist4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -872,9 +866,9 @@
 static int PTRCALL
 attlist5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -889,9 +883,9 @@
 static int PTRCALL
 attlist6(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -906,9 +900,9 @@
 static int PTRCALL
 attlist7(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -967,9 +961,9 @@
 static int PTRCALL
 attlist9(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -984,9 +978,9 @@
 static int PTRCALL
 element0(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1072,9 +1066,9 @@
 static int PTRCALL
 element3(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1097,9 +1091,9 @@
 static int PTRCALL
 element4(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1115,9 +1109,9 @@
 static int PTRCALL
 element5(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1136,9 +1130,9 @@
 static int PTRCALL
 element6(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1166,9 +1160,9 @@
 static int PTRCALL
 element7(PROLOG_STATE *state,
          int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
+         const char *UNUSED_P(ptr),
+         const char *UNUSED_P(end),
+         const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1240,9 +1234,9 @@
 static int PTRCALL
 condSect1(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1258,9 +1252,9 @@
 static int PTRCALL
 condSect2(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1277,9 +1271,9 @@
 static int PTRCALL
 declClose(PROLOG_STATE *state,
           int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
+          const char *UNUSED_P(ptr),
+          const char *UNUSED_P(end),
+          const ENCODING *UNUSED_P(enc))
 {
   switch (tok) {
   case XML_TOK_PROLOG_S:
@@ -1292,11 +1286,11 @@
 }
 
 static int PTRCALL
-error(PROLOG_STATE *state,
-      int tok,
-      const char *ptr,
-      const char *end,
-      const ENCODING *enc)
+error(PROLOG_STATE *UNUSED_P(state),
+      int UNUSED_P(tok),
+      const char *UNUSED_P(ptr),
+      const char *UNUSED_P(end),
+      const ENCODING *UNUSED_P(enc))
 {
   return XML_ROLE_NONE;
 }
diff --git a/cbits/xmltok.c b/cbits/xmltok.c
--- a/cbits/xmltok.c
+++ b/cbits/xmltok.c
@@ -4,19 +4,13 @@
 
 #include <stddef.h>
 
-#ifdef COMPILED_FROM_DSP
+#ifdef _WIN32
 #include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos4__)
-#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 */
+#endif /* ndef _WIN32 */
 
 #include "expat_external.h"
 #include "internal.h"
@@ -46,7 +40,7 @@
 #define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
 
 #define UCS2_GET_NAMING(pages, hi, lo) \
-   (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+   (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo) & 0x1F)))
 
 /* A 2 byte UTF-8 representation splits the characters 11 bits between
    the bottom 5 and 6 bits of the bytes.  We need 8 bits to index into
@@ -56,7 +50,7 @@
     (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
                       + ((((byte)[0]) & 3) << 1) \
                       + ((((byte)[1]) >> 5) & 1)] \
-         & (1 << (((byte)[1]) & 0x1F)))
+         & (1u << (((byte)[1]) & 0x1F)))
 
 /* A 3 byte UTF-8 representation splits the characters 16 bits between
    the bottom 4, 6 and 6 bits of the bytes.  We need 8 bits to index
@@ -69,7 +63,7 @@
                        << 3) \
                       + ((((byte)[1]) & 3) << 1) \
                       + ((((byte)[2]) >> 5) & 1)] \
-         & (1 << (((byte)[2]) & 0x1F)))
+         & (1u << (((byte)[2]) & 0x1F)))
 
 #define UTF8_GET_NAMING(pages, p, n) \
   ((n) == 2 \
@@ -122,19 +116,19 @@
     ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
 
 static int PTRFASTCALL
-isNever(const ENCODING *enc, const char *p)
+isNever(const ENCODING *UNUSED_P(enc), const char *UNUSED_P(p))
 {
   return 0;
 }
 
 static int PTRFASTCALL
-utf8_isName2(const ENCODING *enc, const char *p)
+utf8_isName2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isName3(const ENCODING *enc, const char *p)
+utf8_isName3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
 }
@@ -142,13 +136,13 @@
 #define utf8_isName4 isNever
 
 static int PTRFASTCALL
-utf8_isNmstrt2(const ENCODING *enc, const char *p)
+utf8_isNmstrt2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isNmstrt3(const ENCODING *enc, const char *p)
+utf8_isNmstrt3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
 }
@@ -156,19 +150,19 @@
 #define utf8_isNmstrt4 isNever
 
 static int PTRFASTCALL
-utf8_isInvalid2(const ENCODING *enc, const char *p)
+utf8_isInvalid2(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID2((const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isInvalid3(const ENCODING *enc, const char *p)
+utf8_isInvalid3(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID3((const unsigned char *)p);
 }
 
 static int PTRFASTCALL
-utf8_isInvalid4(const ENCODING *enc, const char *p)
+utf8_isInvalid4(const ENCODING *UNUSED_P(enc), const char *p)
 {
   return UTF8_INVALID4((const unsigned char *)p);
 }
@@ -222,6 +216,17 @@
  E ## isInvalid3, \
  E ## isInvalid4
 
+#define NULL_VTABLE \
+ /* isName2 */ NULL, \
+ /* isName3 */ NULL, \
+ /* isName4 */ NULL, \
+ /* isNmstrt2 */ NULL, \
+ /* isNmstrt3 */ NULL, \
+ /* isNmstrt4 */ NULL, \
+ /* isInvalid2 */ NULL, \
+ /* isInvalid3 */ NULL, \
+ /* isInvalid4 */ NULL
+
 static int FASTCALL checkCharRefNumber(int);
 
 #include "xmltok_impl.h"
@@ -318,39 +323,89 @@
   UTF8_cval4 = 0xf0
 };
 
-static void PTRCALL
-utf8_toUtf8(const ENCODING *enc,
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
+{
+  const char * fromLim = *fromLimRef;
+  size_t walked = 0;
+  for (; fromLim > from; fromLim--, walked++) {
+    const unsigned char prev = (unsigned char)fromLim[-1];
+    if ((prev & 0xf8u) == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */
+      if (walked + 1 >= 4) {
+        fromLim += 4 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0xf0u) == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */
+      if (walked + 1 >= 3) {
+        fromLim += 3 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0xe0u) == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */
+      if (walked + 1 >= 2) {
+        fromLim += 2 - 1;
+        break;
+      } else {
+        walked = 0;
+      }
+    } else if ((prev & 0x80u) == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */
+      break;
+    }
+  }
+  *fromLimRef = fromLim;
+}
+
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf8(const ENCODING *UNUSED_P(enc),
             const char **fromP, const char *fromLim,
             char **toP, const char *toLim)
 {
   char *to;
   const char *from;
-  if (fromLim - *fromP > toLim - *toP) {
-    /* Avoid copying partial characters. */
-    for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
-      if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
-        break;
-  }
-  for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+  const char *fromLimInitial = fromLim;
+
+  /* Avoid copying partial characters. */
+  align_limit_to_full_utf8_characters(*fromP, &fromLim);
+
+  for (to = *toP, from = *fromP; (from < fromLim) && (to < toLim); from++, to++)
     *to = *from;
   *fromP = from;
   *toP = to;
+
+  if (fromLim < fromLimInitial)
+    return XML_CONVERT_INPUT_INCOMPLETE;
+  else if ((to == toLim) && (from < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 utf8_toUtf16(const ENCODING *enc,
              const char **fromP, const char *fromLim,
              unsigned short **toP, const unsigned short *toLim)
 {
+  enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
   unsigned short *to = *toP;
   const char *from = *fromP;
-  while (from != fromLim && to != toLim) {
+  while (from < fromLim && to < toLim) {
     switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
     case BT_LEAD2:
+      if (fromLim - from < 2) {
+        res = XML_CONVERT_INPUT_INCOMPLETE;
+        goto after;
+      }
       *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
       from += 2;
       break;
     case BT_LEAD3:
+      if (fromLim - from < 3) {
+        res = XML_CONVERT_INPUT_INCOMPLETE;
+        goto after;
+      }
       *to++ = (unsigned short)(((from[0] & 0xf) << 12)
                                | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
       from += 3;
@@ -358,8 +413,14 @@
     case BT_LEAD4:
       {
         unsigned long n;
-        if (to + 1 == toLim)
+        if (toLim - to < 2) {
+          res = XML_CONVERT_OUTPUT_EXHAUSTED;
           goto after;
+        }
+        if (fromLim - from < 4) {
+          res = XML_CONVERT_INPUT_INCOMPLETE;
+          goto after;
+        }
         n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
             | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
         n -= 0x10000;
@@ -374,9 +435,12 @@
       break;
     }
   }
+  if (from < fromLim)
+    res = XML_CONVERT_OUTPUT_EXHAUSTED;
 after:
   *fromP = from;
   *toP = to;
+  return res;
 }
 
 #ifdef XML_NS
@@ -425,38 +489,43 @@
   STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
 };
 
-static void PTRCALL
-latin1_toUtf8(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf8(const ENCODING *UNUSED_P(enc),
               const char **fromP, const char *fromLim,
               char **toP, const char *toLim)
 {
   for (;;) {
     unsigned char c;
     if (*fromP == fromLim)
-      break;
+      return XML_CONVERT_COMPLETED;
     c = (unsigned char)**fromP;
     if (c & 0x80) {
       if (toLim - *toP < 2)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
       *(*toP)++ = (char)((c & 0x3f) | 0x80);
       (*fromP)++;
     }
     else {
       if (*toP == toLim)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       *(*toP)++ = *(*fromP)++;
     }
   }
 }
 
-static void PTRCALL
-latin1_toUtf16(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf16(const ENCODING *UNUSED_P(enc),
                const char **fromP, const char *fromLim,
                unsigned short **toP, const unsigned short *toLim)
 {
-  while (*fromP != fromLim && *toP != toLim)
+  while (*fromP < fromLim && *toP < toLim)
     *(*toP)++ = (unsigned char)*(*fromP)++;
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 #ifdef XML_NS
@@ -467,7 +536,7 @@
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 #endif
@@ -480,16 +549,21 @@
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
-static void PTRCALL
-ascii_toUtf8(const ENCODING *enc,
+static enum XML_Convert_Result PTRCALL
+ascii_toUtf8(const ENCODING *UNUSED_P(enc),
              const char **fromP, const char *fromLim,
              char **toP, const char *toLim)
 {
-  while (*fromP != fromLim && *toP != toLim)
+  while (*fromP < fromLim && *toP < toLim)
     *(*toP)++ = *(*fromP)++;
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 #ifdef XML_NS
@@ -500,7 +574,7 @@
 #include "asciitab.h"
 /* BT_NONXML == 0 */
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 #endif
@@ -513,7 +587,7 @@
 #undef BT_COLON
 /* BT_NONXML == 0 */
   },
-  STANDARD_VTABLE(sb_)
+  STANDARD_VTABLE(sb_) NULL_VTABLE
 };
 
 static int PTRFASTCALL
@@ -536,13 +610,14 @@
 }
 
 #define DEFINE_UTF16_TO_UTF8(E) \
-static void  PTRCALL \
-E ## toUtf8(const ENCODING *enc, \
+static enum XML_Convert_Result  PTRCALL \
+E ## toUtf8(const ENCODING *UNUSED_P(enc), \
             const char **fromP, const char *fromLim, \
             char **toP, const char *toLim) \
 { \
-  const char *from; \
-  for (from = *fromP; from != fromLim; from += 2) { \
+  const char *from = *fromP; \
+  fromLim = from + (((fromLim - from) >> 1) << 1);  /* shrink to even */ \
+  for (; from < fromLim; from += 2) { \
     int plane; \
     unsigned char lo2; \
     unsigned char lo = GET_LO(from); \
@@ -552,7 +627,7 @@
       if (lo < 0x80) { \
         if (*toP == toLim) { \
           *fromP = from; \
-          return; \
+          return XML_CONVERT_OUTPUT_EXHAUSTED; \
         } \
         *(*toP)++ = lo; \
         break; \
@@ -562,7 +637,7 @@
     case 0x4: case 0x5: case 0x6: case 0x7: \
       if (toLim -  *toP < 2) { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
       } \
       *(*toP)++ = ((lo >> 6) | (hi << 2) |  UTF8_cval2); \
       *(*toP)++ = ((lo & 0x3f) | 0x80); \
@@ -570,7 +645,7 @@
     default: \
       if (toLim -  *toP < 3)  { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
       } \
       /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
       *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
@@ -580,8 +655,12 @@
     case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
       if (toLim -  *toP < 4) { \
         *fromP = from; \
-        return; \
+        return XML_CONVERT_OUTPUT_EXHAUSTED; \
       } \
+      if (fromLim - from < 4) { \
+        *fromP = from; \
+        return XML_CONVERT_INPUT_INCOMPLETE; \
+      } \
       plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
       *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
       *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
@@ -596,20 +675,32 @@
     } \
   } \
   *fromP = from; \
+  if (from < fromLim) \
+    return XML_CONVERT_INPUT_INCOMPLETE; \
+  else \
+    return XML_CONVERT_COMPLETED; \
 }
 
 #define DEFINE_UTF16_TO_UTF16(E) \
-static void  PTRCALL \
-E ## toUtf16(const ENCODING *enc, \
+static enum XML_Convert_Result  PTRCALL \
+E ## toUtf16(const ENCODING *UNUSED_P(enc), \
              const char **fromP, const char *fromLim, \
              unsigned short **toP, const unsigned short *toLim) \
 { \
+  enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
+  fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1);  /* shrink to even */ \
   /* Avoid copying first half only of surrogate */ \
   if (fromLim - *fromP > ((toLim - *toP) << 1) \
-      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
     fromLim -= 2; \
-  for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+    res = XML_CONVERT_INPUT_INCOMPLETE; \
+  } \
+  for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
     *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+  if ((*toP == toLim) && (*fromP < fromLim)) \
+    return XML_CONVERT_OUTPUT_EXHAUSTED; \
+  else \
+    return res; \
 }
 
 #define SET2(ptr, ch) \
@@ -726,7 +817,7 @@
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -745,7 +836,7 @@
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #if BYTEORDER != 4321
@@ -758,7 +849,7 @@
 #include "iasciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -771,7 +862,7 @@
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(little2_)
+  STANDARD_VTABLE(little2_) NULL_VTABLE
 };
 
 #endif
@@ -867,7 +958,7 @@
 #include "asciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -886,7 +977,7 @@
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #if BYTEORDER != 1234
@@ -899,7 +990,7 @@
 #include "iasciitab.h"
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -912,7 +1003,7 @@
 #undef BT_COLON
 #include "latin1tab.h"
   },
-  STANDARD_VTABLE(big2_)
+  STANDARD_VTABLE(big2_) NULL_VTABLE
 };
 
 #endif
@@ -938,7 +1029,7 @@
 }
 
 static void PTRCALL
-initUpdatePosition(const ENCODING *enc, const char *ptr,
+initUpdatePosition(const ENCODING *UNUSED_P(enc), const char *ptr,
                    const char *end, POSITION *pos)
 {
   normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
@@ -1288,7 +1379,7 @@
   return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 unknown_toUtf8(const ENCODING *enc,
                const char **fromP, const char *fromLim,
                char **toP, const char *toLim)
@@ -1299,21 +1390,21 @@
     const char *utf8;
     int n;
     if (*fromP == fromLim)
-      break;
+      return XML_CONVERT_COMPLETED;
     utf8 = uenc->utf8[(unsigned char)**fromP];
     n = *utf8++;
     if (n == 0) {
       int c = uenc->convert(uenc->userData, *fromP);
       n = XmlUtf8Encode(c, buf);
       if (n > toLim - *toP)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       utf8 = buf;
       *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
                  - (BT_LEAD2 - 2));
     }
     else {
       if (n > toLim - *toP)
-        break;
+        return XML_CONVERT_OUTPUT_EXHAUSTED;
       (*fromP)++;
     }
     do {
@@ -1322,13 +1413,13 @@
   }
 }
 
-static void PTRCALL
+static enum XML_Convert_Result PTRCALL
 unknown_toUtf16(const ENCODING *enc,
                 const char **fromP, const char *fromLim,
                 unsigned short **toP, const unsigned short *toLim)
 {
   const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  while (*fromP != fromLim && *toP != toLim) {
+  while (*fromP < fromLim && *toP < toLim) {
     unsigned short c = uenc->utf16[(unsigned char)**fromP];
     if (c == 0) {
       c = (unsigned short)
@@ -1340,12 +1431,17 @@
       (*fromP)++;
     *(*toP)++ = c;
   }
+
+  if ((*toP == toLim) && (*fromP < fromLim))
+    return XML_CONVERT_OUTPUT_EXHAUSTED;
+  else
+    return XML_CONVERT_COMPLETED;
 }
 
 ENCODING *
 XmlInitUnknownEncoding(void *mem,
                        int *table,
-                       CONVERTER convert, 
+                       CONVERTER convert,
                        void *userData)
 {
   int i;
@@ -1503,7 +1599,7 @@
 {
   const ENCODING **encPtr;
 
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   encPtr = enc->encPtr;
   if (ptr + 1 == end) {
@@ -1639,7 +1735,7 @@
 ENCODING *
 XmlInitUnknownEncodingNS(void *mem,
                          int *table,
-                         CONVERTER convert, 
+                         CONVERTER convert,
                          void *userData)
 {
   ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
diff --git a/cbits/xmltok.h b/cbits/xmltok.h
--- a/cbits/xmltok.h
+++ b/cbits/xmltok.h
@@ -130,6 +130,12 @@
                                const char *,
                                const char **);
 
+enum XML_Convert_Result {
+  XML_CONVERT_COMPLETED = 0,
+  XML_CONVERT_INPUT_INCOMPLETE = 1,
+  XML_CONVERT_OUTPUT_EXHAUSTED = 2  /* and therefore potentially input remaining as well */
+};
+
 struct encoding {
   SCANNER scanners[XML_N_STATES];
   SCANNER literalScanners[XML_N_LITERAL_TYPES];
@@ -158,12 +164,12 @@
                             const char *ptr,
                             const char *end,
                             const char **badPtr);
-  void (PTRCALL *utf8Convert)(const ENCODING *enc,
+  enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
                               const char **fromP,
                               const char *fromLim,
                               char **toP,
                               const char *toLim);
-  void (PTRCALL *utf16Convert)(const ENCODING *enc,
+  enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
                                const char **fromP,
                                const char *fromLim,
                                unsigned short **toP,
diff --git a/cbits/xmltok_impl.c b/cbits/xmltok_impl.c
--- a/cbits/xmltok_impl.c
+++ b/cbits/xmltok_impl.c
@@ -87,27 +87,45 @@
 #define PREFIX(ident) ident
 #endif
 
+
+#define HAS_CHARS(enc, ptr, end, count) \
+    (end - ptr >= count * MINBPC(enc))
+
+#define HAS_CHAR(enc, ptr, end) \
+    HAS_CHARS(enc, ptr, end, 1)
+
+#define REQUIRE_CHARS(enc, ptr, end, count) \
+    { \
+      if (! HAS_CHARS(enc, ptr, end, count)) { \
+        return XML_TOK_PARTIAL; \
+      } \
+    }
+
+#define REQUIRE_CHAR(enc, ptr, end) \
+    REQUIRE_CHARS(enc, ptr, end, 1)
+
+
 /* ptr points to character following "<!-" */
 
 static int PTRCALL
 PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
                     const char *end, const char **nextTokPtr)
 {
-  if (ptr != end) {
+  if (HAS_CHAR(enc, ptr, end)) {
     if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
       *nextTokPtr = ptr;
       return XML_TOK_INVALID;
     }
     ptr += MINBPC(enc);
-    while (ptr != end) {
+    while (HAS_CHAR(enc, ptr, end)) {
       switch (BYTE_TYPE(enc, ptr)) {
       INVALID_CASES(ptr, nextTokPtr)
       case BT_MINUS:
-        if ((ptr += MINBPC(enc)) == end)
-          return XML_TOK_PARTIAL;
+        ptr += MINBPC(enc);
+        REQUIRE_CHAR(enc, ptr, end);
         if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
-          if ((ptr += MINBPC(enc)) == end)
-            return XML_TOK_PARTIAL;
+          ptr += MINBPC(enc);
+          REQUIRE_CHAR(enc, ptr, end);
           if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
             *nextTokPtr = ptr;
             return XML_TOK_INVALID;
@@ -131,8 +149,7 @@
 PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
                  const char *end, const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   case BT_MINUS:
     return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -147,11 +164,10 @@
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_PERCNT:
-      if (ptr + MINBPC(enc) == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHARS(enc, ptr, end, 2);
       /* 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:
@@ -175,7 +191,7 @@
 }
 
 static int PTRCALL
-PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
+PREFIX(checkPiTarget)(const ENCODING *UNUSED_P(enc), const char *ptr,
                       const char *end, int *tokPtr)
 {
   int upper = 0;
@@ -225,15 +241,14 @@
 {
   int tok;
   const char *target = ptr;
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_S: case BT_CR: case BT_LF:
@@ -242,13 +257,12 @@
         return XML_TOK_INVALID;
       }
       ptr += MINBPC(enc);
-      while (ptr != end) {
+      while (HAS_CHAR(enc, ptr, end)) {
         switch (BYTE_TYPE(enc, ptr)) {
         INVALID_CASES(ptr, nextTokPtr)
         case BT_QUEST:
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
             *nextTokPtr = ptr + MINBPC(enc);
             return tok;
@@ -266,8 +280,7 @@
         return XML_TOK_INVALID;
       }
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
         *nextTokPtr = ptr + MINBPC(enc);
         return tok;
@@ -282,15 +295,14 @@
 }
 
 static int PTRCALL
-PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
+PREFIX(scanCdataSection)(const ENCODING *UNUSED_P(enc), const char *ptr,
                          const char *end, const char **nextTokPtr)
 {
   static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
                                      ASCII_T, ASCII_A, ASCII_LSQB };
   int i;
   /* CDATA[ */
-  if (end - ptr < 6 * MINBPC(enc))
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHARS(enc, ptr, end, 6);
   for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
     if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
       *nextTokPtr = ptr;
@@ -305,7 +317,7 @@
 PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
                         const char *end, const char **nextTokPtr)
 {
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -319,13 +331,11 @@
   switch (BYTE_TYPE(enc, ptr)) {
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
       break;
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
       ptr -= MINBPC(enc);
       break;
@@ -334,8 +344,7 @@
     return XML_TOK_CDATA_SECT_CLOSE;
   case BT_CR:
     ptr += MINBPC(enc);
-    if (ptr == end)
-      return XML_TOK_PARTIAL;
+    REQUIRE_CHAR(enc, ptr, end);
     if (BYTE_TYPE(enc, ptr) == BT_LF)
       ptr += MINBPC(enc);
     *nextTokPtr = ptr;
@@ -348,7 +357,7 @@
     ptr += MINBPC(enc);
     break;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -383,19 +392,18 @@
 PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
                    const char *end, const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_S: case BT_CR: case BT_LF:
-      for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+      for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
         switch (BYTE_TYPE(enc, ptr)) {
         case BT_S: case BT_CR: case BT_LF:
           break;
@@ -432,7 +440,7 @@
 PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
                        const char *end, const char **nextTokPtr)
 {
-  if (ptr != end) {
+  if (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_DIGIT:
     case BT_HEX:
@@ -441,7 +449,7 @@
       *nextTokPtr = ptr;
       return XML_TOK_INVALID;
     }
-    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_DIGIT:
       case BT_HEX:
@@ -464,7 +472,7 @@
 PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
                     const char *end, const char **nextTokPtr)
 {
-  if (ptr != end) {
+  if (HAS_CHAR(enc, ptr, end)) {
     if (CHAR_MATCHES(enc, ptr, ASCII_x))
       return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
     switch (BYTE_TYPE(enc, ptr)) {
@@ -474,7 +482,7 @@
       *nextTokPtr = ptr;
       return XML_TOK_INVALID;
     }
-    for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_DIGIT:
         break;
@@ -496,8 +504,7 @@
 PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
                 const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_NUM:
@@ -506,7 +513,7 @@
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_SEMI:
@@ -529,7 +536,7 @@
 #ifdef XML_NS
   int hadColon = 0;
 #endif
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
 #ifdef XML_NS
@@ -540,8 +547,7 @@
       }
       hadColon = 1;
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
       default:
@@ -555,8 +561,7 @@
         int t;
 
         ptr += MINBPC(enc);
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         t = BYTE_TYPE(enc, ptr);
         if (t == BT_EQUALS)
           break;
@@ -579,8 +584,7 @@
 #endif
         for (;;) {
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           open = BYTE_TYPE(enc, ptr);
           if (open == BT_QUOT || open == BT_APOS)
             break;
@@ -598,8 +602,7 @@
         /* in attribute value */
         for (;;) {
           int t;
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           t = BYTE_TYPE(enc, ptr);
           if (t == open)
             break;
@@ -624,8 +627,7 @@
           }
         }
         ptr += MINBPC(enc);
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         switch (BYTE_TYPE(enc, ptr)) {
         case BT_S:
         case BT_CR:
@@ -642,8 +644,7 @@
         /* ptr points to closing quote */
         for (;;) {
           ptr += MINBPC(enc);
-          if (ptr == end)
-            return XML_TOK_PARTIAL;
+          REQUIRE_CHAR(enc, ptr, end);
           switch (BYTE_TYPE(enc, ptr)) {
           CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
           case BT_S: case BT_CR: case BT_LF:
@@ -655,8 +656,7 @@
           case BT_SOL:
           sol:
             ptr += MINBPC(enc);
-            if (ptr == end)
-              return XML_TOK_PARTIAL;
+            REQUIRE_CHAR(enc, ptr, end);
             if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
               *nextTokPtr = ptr;
               return XML_TOK_INVALID;
@@ -688,13 +688,12 @@
 #ifdef XML_NS
   int hadColon;
 #endif
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_EXCL:
-    if ((ptr += MINBPC(enc)) == end)
-      return XML_TOK_PARTIAL;
+    ptr += MINBPC(enc);
+    REQUIRE_CHAR(enc, ptr, end);
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_MINUS:
       return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -716,7 +715,7 @@
   hadColon = 0;
 #endif
   /* we have a start-tag */
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
 #ifdef XML_NS
@@ -727,8 +726,7 @@
       }
       hadColon = 1;
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
       default:
@@ -740,7 +738,7 @@
     case BT_S: case BT_CR: case BT_LF:
       {
         ptr += MINBPC(enc);
-        while (ptr != end) {
+        while (HAS_CHAR(enc, ptr, end)) {
           switch (BYTE_TYPE(enc, ptr)) {
           CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
           case BT_GT:
@@ -765,8 +763,7 @@
     case BT_SOL:
     sol:
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
         *nextTokPtr = ptr;
         return XML_TOK_INVALID;
@@ -785,7 +782,7 @@
 PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
                    const char **nextTokPtr)
 {
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -803,7 +800,7 @@
     return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
   case BT_CR:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_CR;
     if (BYTE_TYPE(enc, ptr) == BT_LF)
       ptr += MINBPC(enc);
@@ -814,12 +811,12 @@
     return XML_TOK_DATA_NEWLINE;
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_RSQB;
     if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
       break;
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return XML_TOK_TRAILING_RSQB;
     if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
       ptr -= MINBPC(enc);
@@ -832,7 +829,7 @@
     ptr += MINBPC(enc);
     break;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -845,12 +842,12 @@
     LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
 #undef LEAD_CASE
     case BT_RSQB:
-      if (ptr + MINBPC(enc) != end) {
+      if (HAS_CHARS(enc, ptr, end, 2)) {
          if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
            ptr += MINBPC(enc);
            break;
          }
-         if (ptr + 2*MINBPC(enc) != end) {
+         if (HAS_CHARS(enc, ptr, end, 3)) {
            if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
              ptr += MINBPC(enc);
              break;
@@ -884,8 +881,7 @@
 PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
                     const char **nextTokPtr)
 {
-  if (ptr == end)
-    return -XML_TOK_PERCENT;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
@@ -895,7 +891,7 @@
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_SEMI:
@@ -913,15 +909,14 @@
 PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
                       const char **nextTokPtr)
 {
-  if (ptr == end)
-    return XML_TOK_PARTIAL;
+  REQUIRE_CHAR(enc, ptr, end);
   switch (BYTE_TYPE(enc, ptr)) {
   CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
   default:
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_CR: case BT_LF: case BT_S:
@@ -941,7 +936,7 @@
                 const char *ptr, const char *end,
                 const char **nextTokPtr)
 {
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     int t = BYTE_TYPE(enc, ptr);
     switch (t) {
     INVALID_CASES(ptr, nextTokPtr)
@@ -950,7 +945,7 @@
       ptr += MINBPC(enc);
       if (t != open)
         break;
-      if (ptr == end)
+      if (! HAS_CHAR(enc, ptr, end))
         return -XML_TOK_LITERAL;
       *nextTokPtr = ptr;
       switch (BYTE_TYPE(enc, ptr)) {
@@ -973,7 +968,7 @@
                   const char **nextTokPtr)
 {
   int tok;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
   if (MINBPC(enc) > 1) {
     size_t n = end - ptr;
@@ -992,8 +987,7 @@
   case BT_LT:
     {
       ptr += MINBPC(enc);
-      if (ptr == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHAR(enc, ptr, end);
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_EXCL:
         return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -1021,7 +1015,7 @@
   case BT_S: case BT_LF:
     for (;;) {
       ptr += MINBPC(enc);
-      if (ptr == end)
+      if (! HAS_CHAR(enc, ptr, end))
         break;
       switch (BYTE_TYPE(enc, ptr)) {
       case BT_S: case BT_LF:
@@ -1048,11 +1042,10 @@
     return XML_TOK_OPEN_BRACKET;
   case BT_RSQB:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return -XML_TOK_CLOSE_BRACKET;
     if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-      if (ptr + MINBPC(enc) == end)
-        return XML_TOK_PARTIAL;
+      REQUIRE_CHARS(enc, ptr, end, 2);
       if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
         *nextTokPtr = ptr + 2*MINBPC(enc);
         return XML_TOK_COND_SECT_CLOSE;
@@ -1065,7 +1058,7 @@
     return XML_TOK_OPEN_PAREN;
   case BT_RPAR:
     ptr += MINBPC(enc);
-    if (ptr == end)
+    if (! HAS_CHAR(enc, ptr, end))
       return -XML_TOK_CLOSE_PAREN;
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_AST:
@@ -1141,7 +1134,7 @@
     *nextTokPtr = ptr;
     return XML_TOK_INVALID;
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
     case BT_GT: case BT_RPAR: case BT_COMMA:
@@ -1154,8 +1147,7 @@
       ptr += MINBPC(enc);
       switch (tok) {
       case XML_TOK_NAME:
-        if (ptr == end)
-          return XML_TOK_PARTIAL;
+        REQUIRE_CHAR(enc, ptr, end);
         tok = XML_TOK_PREFIXED_NAME;
         switch (BYTE_TYPE(enc, ptr)) {
         CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
@@ -1204,10 +1196,12 @@
                           const char *end, const char **nextTokPtr)
 {
   const char *start;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
+  else if (! HAS_CHAR(enc, ptr, end))
+    return XML_TOK_PARTIAL;
   start = ptr;
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: ptr += n; break;
@@ -1232,7 +1226,7 @@
     case BT_CR:
       if (ptr == start) {
         ptr += MINBPC(enc);
-        if (ptr == end)
+        if (! HAS_CHAR(enc, ptr, end))
           return XML_TOK_TRAILING_CR;
         if (BYTE_TYPE(enc, ptr) == BT_LF)
           ptr += MINBPC(enc);
@@ -1262,10 +1256,12 @@
                        const char *end, const char **nextTokPtr)
 {
   const char *start;
-  if (ptr == end)
+  if (ptr >= end)
     return XML_TOK_NONE;
+  else if (! HAS_CHAR(enc, ptr, end))
+    return XML_TOK_PARTIAL;
   start = ptr;
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: ptr += n; break;
@@ -1294,7 +1290,7 @@
     case BT_CR:
       if (ptr == start) {
         ptr += MINBPC(enc);
-        if (ptr == end)
+        if (! HAS_CHAR(enc, ptr, end))
           return XML_TOK_TRAILING_CR;
         if (BYTE_TYPE(enc, ptr) == BT_LF)
           ptr += MINBPC(enc);
@@ -1326,15 +1322,15 @@
       end = ptr + n;
     }
   }
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
     INVALID_CASES(ptr, nextTokPtr)
     case BT_LT:
-      if ((ptr += MINBPC(enc)) == end)
-        return XML_TOK_PARTIAL;
+      ptr += MINBPC(enc);
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
-        if ((ptr += MINBPC(enc)) == end)
-          return XML_TOK_PARTIAL;
+        ptr += MINBPC(enc);
+        REQUIRE_CHAR(enc, ptr, end);
         if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
           ++level;
           ptr += MINBPC(enc);
@@ -1342,11 +1338,11 @@
       }
       break;
     case BT_RSQB:
-      if ((ptr += MINBPC(enc)) == end)
-        return XML_TOK_PARTIAL;
+      ptr += MINBPC(enc);
+      REQUIRE_CHAR(enc, ptr, end);
       if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-        if ((ptr += MINBPC(enc)) == end)
-          return XML_TOK_PARTIAL;
+        ptr += MINBPC(enc);
+        REQUIRE_CHAR(enc, ptr, end);
         if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
           ptr += MINBPC(enc);
           if (level == 0) {
@@ -1373,7 +1369,7 @@
 {
   ptr += MINBPC(enc);
   end -= MINBPC(enc);
-  for (; ptr != end; ptr += MINBPC(enc)) {
+  for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
     switch (BYTE_TYPE(enc, ptr)) {
     case BT_DIGIT:
     case BT_HEX:
@@ -1521,7 +1517,7 @@
 }
 
 static int PTRFASTCALL
-PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+PREFIX(charRefNumber)(const ENCODING *UNUSED_P(enc), const char *ptr)
 {
   int result = 0;
   /* skip &# */
@@ -1565,7 +1561,7 @@
 }
 
 static int PTRCALL
-PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
+PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
                              const char *end)
 {
   switch ((end - ptr)/MINBPC(enc)) {
@@ -1683,11 +1679,11 @@
 }
 
 static int PTRCALL
-PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
+PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
                          const char *end1, const char *ptr2)
 {
   for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
-    if (ptr1 == end1)
+    if (end1 - ptr1 < MINBPC(enc))
       return 0;
     if (!CHAR_MATCHES(enc, ptr1, *ptr2))
       return 0;
@@ -1744,7 +1740,7 @@
                        const char *end,
                        POSITION *pos)
 {
-  while (ptr != end) {
+  while (HAS_CHAR(enc, ptr, end)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #define LEAD_CASE(n) \
     case BT_LEAD ## n: \
@@ -1760,7 +1756,7 @@
     case BT_CR:
       pos->lineNumber++;
       ptr += MINBPC(enc);
-      if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+      if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
         ptr += MINBPC(enc);
       pos->columnNumber = (XML_Size)-1;
       break;
diff --git a/hexpat.cabal b/hexpat.cabal
--- a/hexpat.cabal
+++ b/hexpat.cabal
@@ -1,6 +1,6 @@
 Cabal-Version: >= 1.6
 Name: hexpat
-Version: 0.19.10
+Version: 0.20.13
 Synopsis: XML parser/formatter based on expat
 Description:
   This package provides a general purpose Haskell XML library using Expat to
@@ -23,24 +23,21 @@
   If you want to do interactive I\/O, an obvious option is to use lazy parsing
   with one of the lazy I\/O functions such as hGetContents.  However, this can be
   problematic in some applications because it doesn't handle I\/O errors properly
-  and can give no guarantee of timely resource cleanup.  In these cases, chunked
-  I\/O is a better approach: Take a look at the /hexpat-enumerator/ package.
+  and can give no guarantee of timely resource cleanup. Because of the generalized
+  list, Hexpat is designed to allow for chunked I/O, but as of this writing I haven't
+  done a nice integration with enumerator and friends.
   .
   /IO/ is filed under /Internal/ because it's low-level and most users won't want
   it.  The other /Internal/ modules are re-exported by /Annotated/, /Tree/ and /Extended/,
   so you won't need to import them directly.
   .
+  If you have trouble building on Windows, you can try the bundle flag. This will
+  make it build from the source of libexpat bundled inside the hexpat package:
+  cabal install -f bundle hexpat
+  .
   Credits to Iavor Diatchki and the @xml@ (XML.Light) package for /Proc/ and /Cursor/.
   Thanks to the many contributors.
   .
-  BOUND VS. UNBOUND THREADS: GHC (at least versions 6.12.X) will spawn threads
-  if you call a safe FFI callback from an unbound thread.  This can get out of
-  control in a busy application.  To avoid this, from version 0.19.1 we now delegate
-  processing to a single worker thread if the calling thread is not bound.
-  This essentially means that hexpat currently won't exploit multicores very well.
-  It also means that hexpat may be more efficient on threads spawned with forkOS
-  (to give you a bound thread) rather than forkIO.
-  .
   ChangeLog: 0.15 changes intended to fix a (rare) \"error: a C finalizer called back into Haskell.\"
     that seemed only to happen only on ghc6.12.X; 0.15.1 Fix broken Annotated parse;
     0.16 switch from mtl to transformers; 0.17 fix mapNodeContainer & rename some things.;
@@ -52,7 +49,16 @@
     which broke entity parsing; 0.19.4 bump version constraint for text; 0.19.5 bump text
     to < 0.12 and fix text-0.10.0.1 breakage; 0.19.6 dependency breakage with List;
     0.19.7 ghc-7.2.1 compatibility; 0.19.8 fix space leak on lazy parse under ghc-7.2.1;
-    0.19.9 fix formatting of > character + improve performance; 0.9.10 ghc-7.4.x compatibility.
+    0.19.9 fix formatting of > character + improve performance; 0.19.10 ghc-7.4.x compatibility;
+    0.20.1 fix an unfortunate crash when used in parallel processing and greatly improve
+    performance; 0.20.2 make parseSaxG lazier; 0.20.3 minor build issues; 0.20.4 remove
+    dependency on extensible-exceptions; 0.20.5 bump text upper bound; 0.20.6 bump text again
+    to include 1.1.x.x; 0.20.7 bump text again for 1.2.x.x; 0.20.8 bump utf8-string dep;
+    0.20.9 bump deepseq dep/ghc-7.10 compatibility.; 0.20.10 increase dependency upper bounds;
+    0.20.11 update to libexpat-2.2.1 which includes several security fixes;
+    0.20.12 use the system libexpat by default, but provide a bundle flag to allow a bundled
+    copy of expat to be used, which might make life easier on Windows: cabal install -f bundle
+    hexpat; 0.20.13 Fix some mistakes made in 0.20.12 cabal file.
 Category: XML
 License: BSD3
 License-File: LICENSE
@@ -65,7 +71,7 @@
   Kevin Jardine,
   Jacob Stanley,
   Simon Hengel
-Maintainer: http://blacksapphire.com/antispam/
+Maintainer: Stephen Blackheath <hexpat2.stephen@blacksapphire.com>
 Copyright:
   (c) 2009 Doug Beardsley <mightybyte@gmail.com>,
   (c) 2009-2012 Stephen Blackheath <http://blacksapphire.com/antispam/>,
@@ -95,48 +101,58 @@
   test/hexpat-leak/Parse.hs,
   test/hexpat-leak/run.sh,
   test/hexpat-leak/build.sh
-  cbits/amigaconfig.h,
-  cbits/asciitab.h,
-  cbits/expat.h,
-  cbits/internal.h,
-  cbits/macconfig.h,
-  cbits/utf8tab.h,
-  cbits/xmlrole.h,
-  cbits/xmltok_impl.h,
-  cbits/ascii.h,
-  cbits/expat_external.h,
-  cbits/iasciitab.h,
-  cbits/latin1tab.h,
-  cbits/nametab.h,
+  test/readRoads.hs,
+  test/ROADS.xml,
   cbits/winconfig.h,
   cbits/xmltok.h
+  cbits/winconfig.h
+  cbits/xmltok_ns.c
+  cbits/internal.h
+  cbits/utf8tab.h
+  cbits/siphash.h
+  cbits/latin1tab.h
+  cbits/xmltok.h
+  cbits/expat.h
+  cbits/xmltok.c
+  cbits/iasciitab.h
+  cbits/asciitab.h
+  cbits/README
+  cbits/xmlparse.c
+  cbits/xmltok_impl.h
+  cbits/xmltok_impl.c
+  cbits/xmlrole.c
+  cbits/xmlrole.h
+  cbits/expat_external.h
+  cbits/ascii.h
+  cbits/nametab.h
+
 Build-Type: Simple
 Stability: beta
 source-repository head
-    type:     darcs
-    location: http://code.haskell.org/hexpat/
+    type:     git
+    location: https://github.com/the-real-blackh/hexpat
 
+Flag bundle {
+  Description: Use bundled libexpat
+  Default:     False
+}
+
 Library
   Build-Depends:
     base >= 3 && < 5,
     bytestring,
     transformers,
-    text >= 0.5 && < 0.12,
-    utf8-string == 0.3.*,
-    deepseq >= 1.1.0.0 && < 1.4.0.0,
+    text >= 0.5.0.0 && < 1.3.0.0,
+    utf8-string >= 0.3 && < 1.1,
+    deepseq >= 1.1.0.0 && < 1.5.0.0,
     containers,
-    extensible-exceptions == 0.1.*,
-    List >= 0.4.2 && < 0.5
+    List >= 0.4.2 && < 0.7
   Exposed-Modules:
     Text.XML.Expat.Annotated,
     Text.XML.Expat.Cursor,
     Text.XML.Expat.Extended,
     Text.XML.Expat.Format,
-    Text.XML.Expat.IO,
-    Text.XML.Expat.Namespaced,
-    Text.XML.Expat.NodeClass,
     Text.XML.Expat.Proc,
-    Text.XML.Expat.Qualified,
     Text.XML.Expat.SAX,
     Text.XML.Expat.Tree,
     Text.XML.Expat.Internal.DocumentClass,
@@ -146,12 +162,19 @@
     Text.XML.Expat.Internal.Qualified
   ghc-options: -Wall -fno-warn-name-shadowing
 
-  include-dirs: cbits
-  c-sources:
-    cbits/xmlparse.c,
-    cbits/xmlrole.c,
-    cbits/xmltok.c,
-    cbits/xmltok_impl.c,
-    cbits/xmltok_ns.c
-  cc-options: -DHAVE_MEMMOVE -DXML_NS -DXML_DTD
-
+  if flag(bundle) {
+    include-dirs: cbits
+    c-sources:
+      cbits/xmlparse.c,
+      cbits/xmlrole.c,
+      cbits/xmltok.c,
+      cbits/xmltok_impl.c,
+      cbits/xmltok_ns.c,
+      Text/XML/Expat/Internal/Glue.c
+    cc-options: -DHAVE_MEMMOVE -DXML_NS -DXML_DTD
+  }
+  else {
+    c-sources:
+      Text/XML/Expat/Internal/Glue.c
+    extra-libraries: expat
+  }
diff --git a/test/ROADS.xml b/test/ROADS.xml
new file mode 100644
--- /dev/null
+++ b/test/ROADS.xml
@@ -0,0 +1,1008 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<shapes>
+  <shape shapeType="polyLine" id="0" ADD_L_DIR="-1" ADD_L_MAX="17" ADD_L_MIN="3" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="26" ADD_R_MIN="6" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="WAIMEA LANE" ID="64" ISLAND="North Island" NAME="WAIMEA LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64414" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Remuera" TOWN="Auckland" TURNRESLNK="ak66" URBANRURAL="U" ID1="1">
+    <vertices>
+      <vertex X="174.800917" Y="-36.874316"/>
+      <vertex X="174.800705" Y="-36.874296"/>
+      <vertex X="174.798671" Y="-36.874107"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="1" ADD_L_DIR="1" ADD_L_MAX="25" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="DENARIUS LANE" ID="65" ISLAND="North Island" NAME="DENARIUS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64413" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glendene" TOWN="Waitakere" TURNRESLNK="ak67" URBANRURAL="U" ID1="2">
+    <vertices>
+      <vertex X="174.657551" Y="-36.889236"/>
+      <vertex X="174.656120" Y="-36.888354"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="2" ADD_L_DIR="1" ADD_L_MAX="46" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="BOARDMAN LANE" ID="66" ISLAND="North Island" NAME="BOARDMAN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64412" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak92" URBANRURAL="U" ID1="3">
+    <vertices>
+      <vertex X="174.757249" Y="-36.857860"/>
+      <vertex X="174.757058" Y="-36.857463"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="3" ADD_L_DIR="1" ADD_L_MAX="20" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="13" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="GARDEN LANE" ID="35" ISLAND="North Island" NAME="GARDEN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64411" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Northcross" TOWN="North Shore" TURNRESLNK="ak35" URBANRURAL="U" ID1="4">
+    <vertices>
+      <vertex X="174.735888" Y="-36.707362"/>
+      <vertex X="174.736360" Y="-36.707260"/>
+      <vertex X="174.736581" Y="-36.707229"/>
+      <vertex X="174.737098" Y="-36.707092"/>
+      <vertex X="174.737294" Y="-36.706989"/>
+      <vertex X="174.737303" Y="-36.706958"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="4" ADD_L_DIR="1" ADD_L_MAX="10" ADD_L_MIN="2" ADD_L_TYPE="M" ADD_R_DIR="1" ADD_R_MAX="3" ADD_R_MIN="3" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="EMILY LANE" ID="36" ISLAND="North Island" NAME="EMILY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64409" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Cuthill" TOWN="North Shore" TURNRESLNK="ak36" URBANRURAL="U" ID1="5">
+    <vertices>
+      <vertex X="174.704080" Y="-36.764450"/>
+      <vertex X="174.703525" Y="-36.764050"/>
+      <vertex X="174.703360" Y="-36.763845"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="5" ADD_L_DIR="1" ADD_L_MAX="22" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="15" ADD_R_MIN="5" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="DENE COURT LANE" ID="37" ISLAND="North Island" NAME="DENE COURT LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64408" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Cuthill" TOWN="North Shore" TURNRESLNK="ak37" URBANRURAL="U" ID1="6">
+    <vertices>
+      <vertex X="174.706178" Y="-36.762460"/>
+      <vertex X="174.707042" Y="-36.763011"/>
+      <vertex X="174.707911" Y="-36.763718"/>
+      <vertex X="174.708126" Y="-36.764282"/>
+      <vertex X="174.708057" Y="-36.764526"/>
+      <vertex X="174.707982" Y="-36.764789"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="6" ADD_L_DIR="1" ADD_L_MAX="22" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="23" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="REDFERN LANE" ID="38" ISLAND="North Island" NAME="REDFERN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64407" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glenfield" TOWN="North Shore" TURNRESLNK="ak38" URBANRURAL="U" ID1="7">
+    <vertices>
+      <vertex X="174.708554" Y="-36.786916"/>
+      <vertex X="174.709059" Y="-36.786575"/>
+      <vertex X="174.709234" Y="-36.786400"/>
+      <vertex X="174.709373" Y="-36.786128"/>
+      <vertex X="174.709438" Y="-36.785949"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="7" ADD_L_DIR="-1" ADD_L_MAX="15" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="14" ADD_R_MIN="4" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="GLADFIELD LANE" ID="39" ISLAND="North Island" NAME="GLADFIELD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64405" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak39" URBANRURAL="U" ID1="8">
+    <vertices>
+      <vertex X="174.649093" Y="-36.835993"/>
+      <vertex X="174.648993" Y="-36.836069"/>
+      <vertex X="174.648946" Y="-36.836104"/>
+      <vertex X="174.648276" Y="-36.836606"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="8" ADD_L_DIR="-1" ADD_L_MAX="9" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="10" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="GLENFORD LANE" ID="40" ISLAND="North Island" NAME="GLENFORD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64404" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak40" URBANRURAL="U" ID1="9">
+    <vertices>
+      <vertex X="174.646092" Y="-36.834602"/>
+      <vertex X="174.645978" Y="-36.834622"/>
+      <vertex X="174.645450" Y="-36.834975"/>
+      <vertex X="174.645188" Y="-36.835258"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="9" ADD_L_DIR="-1" ADD_L_MAX="5" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="6" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="BRAEBANK LANE" ID="41" ISLAND="North Island" NAME="BRAEBANK LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64403" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu South" TOWN="Waitakere" TURNRESLNK="ak41" URBANRURAL="U" ID1="10">
+    <vertices>
+      <vertex X="174.654567" Y="-36.860195"/>
+      <vertex X="174.654041" Y="-36.861186"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="10" ADD_L_DIR="-1" ADD_L_MAX="8" ADD_L_MIN="4" ADD_L_TYPE="E" ADD_R_DIR="-1" ADD_R_MAX="7" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="SUNRISE LANE" ID="42" ISLAND="North Island" NAME="SUNRISE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64402" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu South" TOWN="Waitakere" TURNRESLNK="ak42" URBANRURAL="U" ID1="11">
+    <vertices>
+      <vertex X="174.651493" Y="-36.861550"/>
+      <vertex X="174.650956" Y="-36.862099"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="11" ADD_L_DIR="-1" ADD_L_MAX="11" ADD_L_MIN="3" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="10" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="GANE LANE" ID="43" ISLAND="North Island" NAME="GANE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64399" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak45" URBANRURAL="U" ID1="12">
+    <vertices>
+      <vertex X="174.648910" Y="-36.846895"/>
+      <vertex X="174.648532" Y="-36.847487"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="12" ADD_L_DIR="-1" ADD_L_MAX="7" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="6" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="GLENVIL LANE" ID="44" ISLAND="North Island" NAME="GLENVIL LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64398" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak46" URBANRURAL="U" ID1="13">
+    <vertices>
+      <vertex X="174.648767" Y="-36.849879"/>
+      <vertex X="174.648673" Y="-36.849839"/>
+      <vertex X="174.648157" Y="-36.849209"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="13" ADD_L_DIR="-1" ADD_L_MAX="11" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="16" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="SPRINGBANK LANE" ID="45" ISLAND="North Island" NAME="SPRINGBANK LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64397" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak47" URBANRURAL="U" ID1="14">
+    <vertices>
+      <vertex X="174.644889" Y="-36.843879"/>
+      <vertex X="174.646215" Y="-36.843489"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="14" ADD_L_DIR="-1" ADD_L_MAX="11" ADD_L_MIN="3" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="14" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="SHAMROCK LANE" ID="46" ISLAND="North Island" NAME="SHAMROCK LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64396" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak48" URBANRURAL="U" ID1="15">
+    <vertices>
+      <vertex X="174.649589" Y="-36.838069"/>
+      <vertex X="174.649551" Y="-36.838033"/>
+      <vertex X="174.648642" Y="-36.837629"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="15" ADD_L_DIR="-1" ADD_L_MAX="9" ADD_L_MIN="3" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="10" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="BEAUFIELD LANE" ID="47" ISLAND="North Island" NAME="BEAUFIELD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64395" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak49" URBANRURAL="U" ID1="16">
+    <vertices>
+      <vertex X="174.647448" Y="-36.837864"/>
+      <vertex X="174.648140" Y="-36.838223"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="16" ADD_L_DIR="1" ADD_L_MAX="22" ADD_L_MIN="4" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="25" ADD_R_MIN="3" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="ELISA LANE" ID="48" ISLAND="North Island" NAME="ELISA LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64394" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Ranui" TOWN="Waitakere" TURNRESLNK="ak50" URBANRURAL="U" ID1="17">
+    <vertices>
+      <vertex X="174.602145" Y="-36.861159"/>
+      <vertex X="174.602659" Y="-36.861093"/>
+      <vertex X="174.603003" Y="-36.861153"/>
+      <vertex X="174.603023" Y="-36.861149"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="17" ADD_L_DIR="-1" ADD_L_MAX="23" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="6" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="CONSTABLE LANE" ID="49" ISLAND="North Island" NAME="CONSTABLE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64393" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="West Harbour" TOWN="Waitakere" TURNRESLNK="ak51" URBANRURAL="U" ID1="18">
+    <vertices>
+      <vertex X="174.642384" Y="-36.818826"/>
+      <vertex X="174.642240" Y="-36.818688"/>
+      <vertex X="174.642098" Y="-36.818540"/>
+      <vertex X="174.642057" Y="-36.818473"/>
+      <vertex X="174.642042" Y="-36.818390"/>
+      <vertex X="174.642085" Y="-36.818272"/>
+      <vertex X="174.642163" Y="-36.818113"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="18" ADD_L_DIR="-1" ADD_L_MAX="9" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="8" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="STAFSON LANE" ID="50" ISLAND="North Island" NAME="STAFSON LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64392" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Te Atatu Peninsula" TOWN="Waitakere" TURNRESLNK="ak52" URBANRURAL="U" ID1="19">
+    <vertices>
+      <vertex X="174.645498" Y="-36.829736"/>
+      <vertex X="174.645394" Y="-36.829932"/>
+      <vertex X="174.644814" Y="-36.830599"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="19" ADD_L_DIR="-1" ADD_L_MAX="3" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="2" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SPROSTON AVENUE" ID="83" ISLAND="North Island" NAME="SPROSTON AVE" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64391" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Ellerslie" TOWN="Auckland" TURNRESLNK="ak109" URBANRURAL="U" ID1="20">
+    <vertices>
+      <vertex X="174.804846" Y="-36.893312"/>
+      <vertex X="174.805949" Y="-36.893695"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="20" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SHELLY BEACH ROAD" ID="84" ISLAND="North Island" NAME="SHELLY BEACH RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64388" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Saint Marys Bay" TOWN="Auckland" TURNRESLNK="ak110" URBANRURAL="U" ID1="21">
+    <vertices>
+      <vertex X="174.742966" Y="-36.835312"/>
+      <vertex X="174.742938" Y="-36.835373"/>
+      <vertex X="174.742907" Y="-36.835428"/>
+      <vertex X="174.742885" Y="-36.835464"/>
+      <vertex X="174.742868" Y="-36.835504"/>
+      <vertex X="174.742830" Y="-36.835629"/>
+      <vertex X="174.742809" Y="-36.835687"/>
+      <vertex X="174.742779" Y="-36.835746"/>
+      <vertex X="174.742666" Y="-36.835944"/>
+      <vertex X="174.742452" Y="-36.836289"/>
+      <vertex X="174.742391" Y="-36.836391"/>
+      <vertex X="174.742328" Y="-36.836503"/>
+      <vertex X="174.742293" Y="-36.836577"/>
+      <vertex X="174.742261" Y="-36.836648"/>
+      <vertex X="174.742233" Y="-36.836717"/>
+      <vertex X="174.742211" Y="-36.836777"/>
+      <vertex X="174.742183" Y="-36.836868"/>
+      <vertex X="174.742153" Y="-36.836985"/>
+      <vertex X="174.742136" Y="-36.837071"/>
+      <vertex X="174.742106" Y="-36.837292"/>
+      <vertex X="174.742080" Y="-36.837419"/>
+      <vertex X="174.742054" Y="-36.837504"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="21" ADD_L_DIR="1" ADD_L_MAX="20" ADD_L_MIN="8" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="30" ADD_R_MIN="30" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="WHITAKER PLACE" ID="85" ISLAND="North Island" NAME="WHITAKER PL" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64386" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak111" URBANRURAL="U" ID1="22">
+    <vertices>
+      <vertex X="174.766871" Y="-36.856923"/>
+      <vertex X="174.766970" Y="-36.856946"/>
+      <vertex X="174.767088" Y="-36.856905"/>
+      <vertex X="174.767243" Y="-36.856747"/>
+      <vertex X="174.767260" Y="-36.856668"/>
+      <vertex X="174.766999" Y="-36.856464"/>
+      <vertex X="174.767445" Y="-36.856063"/>
+      <vertex X="174.767785" Y="-36.855951"/>
+      <vertex X="174.768032" Y="-36.855830"/>
+      <vertex X="174.768469" Y="-36.855183"/>
+      <vertex X="174.768525" Y="-36.854709"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="22" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DOMAIN DRIVE" ID="86" ISLAND="North Island" NAME="DOMAIN DR" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64385" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak112" URBANRURAL="U" ID1="23">
+    <vertices>
+      <vertex X="174.774820" Y="-36.858931"/>
+      <vertex X="174.774130" Y="-36.858981"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="23" ADD_L_DIR="-1" ADD_L_MAX="14" ADD_L_MIN="7" ADD_L_TYPE="M" ADD_R_DIR="1" ADD_R_MAX="6" ADD_R_MIN="1" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="DAVERN LANE" ID="90" ISLAND="North Island" NAME="DAVERN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64383" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="New Lynn" TOWN="Waitakere" TURNRESLNK="ak71" URBANRURAL="U" ID1="24">
+    <vertices>
+      <vertex X="174.673713" Y="-36.920832"/>
+      <vertex X="174.672945" Y="-36.920079"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="24" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="CLUB LANE" ID="1" ISLAND="North Island" NAME="CLUB LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64382" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Takapuna Beach" TOWN="North Shore" TURNRESLNK="ak91" URBANRURAL="U" ID1="25">
+    <vertices>
+      <vertex X="174.773774" Y="-36.790392"/>
+      <vertex X="174.773267" Y="-36.789750"/>
+      <vertex X="174.773144" Y="-36.789551"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="25" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="CENOTAPH ROAD" ID="2" ISLAND="North Island" NAME="CENOTAPH RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64380" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak1" URBANRURAL="U" ID1="26">
+    <vertices>
+      <vertex X="174.776349" Y="-36.859527"/>
+      <vertex X="174.777016" Y="-36.859524"/>
+      <vertex X="174.777847" Y="-36.859529"/>
+      <vertex X="174.778229" Y="-36.859538"/>
+      <vertex X="174.778380" Y="-36.859585"/>
+      <vertex X="174.778588" Y="-36.859740"/>
+      <vertex X="174.778668" Y="-36.859853"/>
+      <vertex X="174.778713" Y="-36.859979"/>
+      <vertex X="174.778710" Y="-36.860295"/>
+      <vertex X="174.778704" Y="-36.860951"/>
+      <vertex X="174.778656" Y="-36.861033"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="26" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MUSEUM CIRCUIT" ID="3" ISLAND="North Island" NAME="MUSEUM CIRCUIT" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64379" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak2" URBANRURAL="U" ID1="27">
+    <vertices>
+      <vertex X="174.777198" Y="-36.860080"/>
+      <vertex X="174.776455" Y="-36.860071"/>
+      <vertex X="174.776317" Y="-36.860009"/>
+      <vertex X="174.776212" Y="-36.859899"/>
+      <vertex X="174.776200" Y="-36.859756"/>
+      <vertex X="174.776239" Y="-36.859658"/>
+      <vertex X="174.776291" Y="-36.859564"/>
+      <vertex X="174.776349" Y="-36.859527"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="27" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="KIOSK ROAD" ID="5" ISLAND="North Island" NAME="KIOSK RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64378" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak4" URBANRURAL="U" ID1="28">
+    <vertices>
+      <vertex X="174.774677" Y="-36.859587"/>
+      <vertex X="174.774392" Y="-36.859701"/>
+      <vertex X="174.774214" Y="-36.859776"/>
+      <vertex X="174.773644" Y="-36.860015"/>
+      <vertex X="174.773341" Y="-36.860152"/>
+      <vertex X="174.773183" Y="-36.860250"/>
+      <vertex X="174.773065" Y="-36.860346"/>
+      <vertex X="174.772994" Y="-36.860449"/>
+      <vertex X="174.772941" Y="-36.860568"/>
+      <vertex X="174.772880" Y="-36.860701"/>
+      <vertex X="174.772806" Y="-36.860780"/>
+      <vertex X="174.772722" Y="-36.860833"/>
+      <vertex X="174.772635" Y="-36.860870"/>
+      <vertex X="174.772509" Y="-36.860898"/>
+      <vertex X="174.771892" Y="-36.860896"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="28" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="THE CRESCENT" ID="6" ISLAND="North Island" NAME="THE CRESCENT" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64376" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak5" URBANRURAL="U" ID1="29">
+    <vertices>
+      <vertex X="174.775859" Y="-36.859622"/>
+      <vertex X="174.775569" Y="-36.859700"/>
+      <vertex X="174.775344" Y="-36.859728"/>
+      <vertex X="174.775129" Y="-36.859719"/>
+      <vertex X="174.774952" Y="-36.859688"/>
+      <vertex X="174.774677" Y="-36.859587"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="29" ADD_L_DIR="1" ADD_L_MAX="2" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="13" ADD_R_MIN="3" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MERCURY LANE" ID="7" ISLAND="North Island" NAME="MERCURY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="3" RD_SEG_LNK="63668" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Newton" TOWN="Auckland" TURNRESLNK="ak6" URBANRURAL="U" ID1="30">
+    <vertices>
+      <vertex X="174.759046" Y="-36.857703"/>
+      <vertex X="174.759010" Y="-36.858434"/>
+      <vertex X="174.759055" Y="-36.858534"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="30" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="2" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="FREYBERG PLACE" ID="13" ISLAND="North Island" NAME="FREYBERG PL" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63666" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak12" URBANRURAL="U" ID1="31">
+    <vertices>
+      <vertex X="174.766620" Y="-36.847670"/>
+      <vertex X="174.767098" Y="-36.847748"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="31" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SAINT JAMES STREET" ID="14" ISLAND="North Island" NAME="ST JAMES ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63662" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak13" URBANRURAL="U" ID1="32">
+    <vertices>
+      <vertex X="174.757675" Y="-36.856022"/>
+      <vertex X="174.757645" Y="-36.855944"/>
+      <vertex X="174.757642" Y="-36.855650"/>
+      <vertex X="174.757668" Y="-36.855191"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="32" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DOMAIN DRIVE" ID="15" ISLAND="North Island" NAME="DOMAIN DR" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="64385" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak14" URBANRURAL="U" ID1="33">
+    <vertices>
+      <vertex X="174.771892" Y="-36.860896"/>
+      <vertex X="174.771686" Y="-36.860869"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="33" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DOMAIN DRIVE" ID="16" ISLAND="North Island" NAME="DOMAIN DR" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64385" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak15" URBANRURAL="U" ID1="34">
+    <vertices>
+      <vertex X="174.770486" Y="-36.862104"/>
+      <vertex X="174.771000" Y="-36.861930"/>
+      <vertex X="174.771237" Y="-36.861723"/>
+      <vertex X="174.771503" Y="-36.861320"/>
+      <vertex X="174.771660" Y="-36.860995"/>
+      <vertex X="174.771686" Y="-36.860869"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="34" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DOMAIN DRIVE" ID="17" ISLAND="North Island" NAME="DOMAIN DR" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="64385" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Grafton" TOWN="Auckland" TURNRESLNK="ak16" URBANRURAL="U" ID1="35">
+    <vertices>
+      <vertex X="174.771686" Y="-36.860869"/>
+      <vertex X="174.771735" Y="-36.860556"/>
+      <vertex X="174.771747" Y="-36.860486"/>
+      <vertex X="174.771949" Y="-36.860006"/>
+      <vertex X="174.771972" Y="-36.859972"/>
+      <vertex X="174.772085" Y="-36.859815"/>
+      <vertex X="174.772274" Y="-36.859625"/>
+      <vertex X="174.772397" Y="-36.859522"/>
+      <vertex X="174.772529" Y="-36.859425"/>
+      <vertex X="174.772670" Y="-36.859344"/>
+      <vertex X="174.773031" Y="-36.859209"/>
+      <vertex X="174.773325" Y="-36.859123"/>
+      <vertex X="174.773592" Y="-36.859043"/>
+      <vertex X="174.773705" Y="-36.859018"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="35" ADD_L_DIR="1" ADD_L_MAX="76" ADD_L_MIN="70" ADD_L_TYPE="E" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SALE STREET" ID="19" ISLAND="North Island" NAME="SALE ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63657" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Freemans Bay" TOWN="Auckland" TURNRESLNK="ak18" URBANRURAL="U" ID1="36">
+    <vertices>
+      <vertex X="174.755025" Y="-36.849591"/>
+      <vertex X="174.754814" Y="-36.849627"/>
+      <vertex X="174.754580" Y="-36.849690"/>
+      <vertex X="174.754515" Y="-36.849738"/>
+      <vertex X="174.754489" Y="-36.849789"/>
+      <vertex X="174.754489" Y="-36.849846"/>
+      <vertex X="174.754505" Y="-36.849907"/>
+      <vertex X="174.754562" Y="-36.849995"/>
+      <vertex X="174.754712" Y="-36.850189"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="36" ADD_L_DIR="-1" ADD_L_MAX="47" ADD_L_MIN="31" ADD_L_TYPE="O" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SALE STREET" ID="20" ISLAND="North Island" NAME="SALE ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63657" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Freemans Bay" TOWN="Auckland" TURNRESLNK="ak19" URBANRURAL="U" ID1="37">
+    <vertices>
+      <vertex X="174.753766" Y="-36.849635"/>
+      <vertex X="174.753836" Y="-36.849684"/>
+      <vertex X="174.753920" Y="-36.849716"/>
+      <vertex X="174.753985" Y="-36.849723"/>
+      <vertex X="174.755015" Y="-36.849549"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="37" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="22" ADD_R_MIN="22" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DUNLOP LANE" ID="21" ISLAND="North Island" NAME="DUNLOP LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63651" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Panmure" TOWN="Auckland" TURNRESLNK="ak20" URBANRURAL="U" ID1="38">
+    <vertices>
+      <vertex X="174.851563" Y="-36.898649"/>
+      <vertex X="174.851600" Y="-36.898659"/>
+      <vertex X="174.854052" Y="-36.899122"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="38" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="KORMA LANE" ID="22" ISLAND="North Island" NAME="KORMA LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63650" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Panmure" TOWN="Auckland" TURNRESLNK="ak21" URBANRURAL="U" ID1="39">
+    <vertices>
+      <vertex X="174.853639" Y="-36.899839"/>
+      <vertex X="174.853685" Y="-36.899839"/>
+      <vertex X="174.853737" Y="-36.899847"/>
+      <vertex X="174.854524" Y="-36.900038"/>
+      <vertex X="174.854544" Y="-36.900065"/>
+      <vertex X="174.854302" Y="-36.900260"/>
+      <vertex X="174.854560" Y="-36.900441"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="39" ADD_L_DIR="-1" ADD_L_MAX="15" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Manukau City" FULL_NAME="FULTON CRESCENT" ID="23" ISLAND="North Island" NAME="FULTON CRES" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63649" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Otara" TOWN="Manukau" TURNRESLNK="ak22" URBANRURAL="U" ID1="40">
+    <vertices>
+      <vertex X="174.873543" Y="-36.962569"/>
+      <vertex X="174.873564" Y="-36.962848"/>
+      <vertex X="174.873522" Y="-36.962913"/>
+      <vertex X="174.873430" Y="-36.962932"/>
+      <vertex X="174.872717" Y="-36.962731"/>
+      <vertex X="174.872602" Y="-36.962681"/>
+      <vertex X="174.872539" Y="-36.962627"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="40" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="BOLLARD AVENUE" ID="24" ISLAND="North Island" NAME="BOLLARD AVE" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="0" OWNERSHIP="0" RC="6" RD_SEG_LNK="63647" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="2" SUBURB="One Tree Hill" TOWN="Auckland" TURNRESLNK="ak23" URBANRURAL="U" ID1="41">
+    <vertices>
+      <vertex X="174.787861" Y="-36.902871"/>
+      <vertex X="174.788213" Y="-36.903178"/>
+      <vertex X="174.788414" Y="-36.903353"/>
+      <vertex X="174.788708" Y="-36.903665"/>
+      <vertex X="174.788835" Y="-36.903807"/>
+      <vertex X="174.788923" Y="-36.903984"/>
+      <vertex X="174.788965" Y="-36.904094"/>
+      <vertex X="174.788972" Y="-36.904131"/>
+      <vertex X="174.789040" Y="-36.904486"/>
+      <vertex X="174.789094" Y="-36.904569"/>
+      <vertex X="174.789159" Y="-36.904644"/>
+      <vertex X="174.789621" Y="-36.904889"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="41" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="BOLLARD AVENUE" ID="25" ISLAND="North Island" NAME="BOLLARD AVE" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="6" RD_SEG_LNK="63647" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="One Tree Hill" TOWN="Auckland" TURNRESLNK="ak24" URBANRURAL="U" ID1="42">
+    <vertices>
+      <vertex X="174.786526" Y="-36.902359"/>
+      <vertex X="174.786637" Y="-36.902407"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="42" ADD_L_DIR="1" ADD_L_MAX="34" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="41" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="HONEYSUCKLE LANE" ID="26" ISLAND="North Island" NAME="HONEYSUCKLE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63646" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Mairangi Bay" TOWN="North Shore" TURNRESLNK="ak25" URBANRURAL="U" ID1="43">
+    <vertices>
+      <vertex X="174.741128" Y="-36.736259"/>
+      <vertex X="174.741358" Y="-36.736481"/>
+      <vertex X="174.741422" Y="-36.736503"/>
+      <vertex X="174.741459" Y="-36.736506"/>
+      <vertex X="174.742485" Y="-36.736318"/>
+      <vertex X="174.742653" Y="-36.736325"/>
+      <vertex X="174.744429" Y="-36.736584"/>
+      <vertex X="174.744678" Y="-36.736644"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="43" ADD_L_DIR="1" ADD_L_MAX="47" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="1" ADD_R_MAX="42" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="PALLISER LANE" ID="27" ISLAND="North Island" NAME="PALLISER LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63643" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Browns Bay" TOWN="North Shore" TURNRESLNK="ak26" URBANRURAL="U" ID1="44">
+    <vertices>
+      <vertex X="174.728908" Y="-36.723964"/>
+      <vertex X="174.728860" Y="-36.724225"/>
+      <vertex X="174.728827" Y="-36.724343"/>
+      <vertex X="174.728794" Y="-36.724425"/>
+      <vertex X="174.728743" Y="-36.724477"/>
+      <vertex X="174.728285" Y="-36.724653"/>
+      <vertex X="174.727985" Y="-36.724765"/>
+      <vertex X="174.727794" Y="-36.724862"/>
+      <vertex X="174.727023" Y="-36.725360"/>
+      <vertex X="174.726975" Y="-36.725391"/>
+      <vertex X="174.726550" Y="-36.725542"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="44" ADD_L_DIR="1" ADD_L_MAX="43" ADD_L_MIN="33" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="44" ADD_R_MIN="36" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="BERENICE LANE" ID="67" ISLAND="North Island" NAME="BERENICE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63642" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Coatesville" TOWN="" TURNRESLNK="ak93" URBANRURAL="R" ID1="45">
+    <vertices>
+      <vertex X="174.609999" Y="-36.735115"/>
+      <vertex X="174.610605" Y="-36.734742"/>
+      <vertex X="174.613196" Y="-36.734630"/>
+      <vertex X="174.613911" Y="-36.734341"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="45" ADD_L_DIR="1" ADD_L_MAX="22" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="27" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="MARTIN JUGUM LANE" ID="68" ISLAND="North Island" NAME="MARTIN JUGUM LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63641" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Ranui" TOWN="Waitakere" TURNRESLNK="ak94" URBANRURAL="U" ID1="46">
+    <vertices>
+      <vertex X="174.607807" Y="-36.866540"/>
+      <vertex X="174.607892" Y="-36.866638"/>
+      <vertex X="174.608251" Y="-36.866944"/>
+      <vertex X="174.608487" Y="-36.867111"/>
+      <vertex X="174.608763" Y="-36.867248"/>
+      <vertex X="174.609359" Y="-36.867418"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="46" ADD_L_DIR="1" ADD_L_MAX="10" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="19" ADD_R_MIN="3" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="SUMMERFIELD LANE" ID="69" ISLAND="North Island" NAME="SUMMERFIELD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63640" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Albany" TOWN="North Shore" TURNRESLNK="ak95" URBANRURAL="U" ID1="47">
+    <vertices>
+      <vertex X="174.691313" Y="-36.734866"/>
+      <vertex X="174.690747" Y="-36.734736"/>
+      <vertex X="174.689931" Y="-36.734486"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="47" ADD_L_DIR="1" ADD_L_MAX="45" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="48" ADD_R_MIN="4" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="DYSART LANE" ID="70" ISLAND="North Island" NAME="DYSART LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63638" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Kumeu" TOWN="" TURNRESLNK="ak96" URBANRURAL="R" ID1="48">
+    <vertices>
+      <vertex X="174.540356" Y="-36.798417"/>
+      <vertex X="174.542820" Y="-36.794720"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="48" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="69" ADD_R_MIN="69" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="CHERRY BLOSSOM LANE" ID="71" ISLAND="North Island" NAME="CHERRY BLOSSOM LN" NAMED_AREA="" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63637" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Te Pua" TOWN="" TURNRESLNK="ak97" URBANRURAL="R" ID1="49">
+    <vertices>
+      <vertex X="174.408949" Y="-36.683874"/>
+      <vertex X="174.408647" Y="-36.684589"/>
+      <vertex X="174.408495" Y="-36.684653"/>
+      <vertex X="174.408054" Y="-36.684705"/>
+      <vertex X="174.407883" Y="-36.684785"/>
+      <vertex X="174.407781" Y="-36.684957"/>
+      <vertex X="174.407799" Y="-36.685343"/>
+      <vertex X="174.409682" Y="-36.689106"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="49" ADD_L_DIR="1" ADD_L_MAX="51" ADD_L_MIN="23" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="61" ADD_R_MIN="34" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="PIONEER LANE" ID="72" ISLAND="North Island" NAME="PIONEER LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63636" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Taupaki" TOWN="" TURNRESLNK="ak98" URBANRURAL="R" ID1="50">
+    <vertices>
+      <vertex X="174.521642" Y="-36.811908"/>
+      <vertex X="174.520775" Y="-36.812576"/>
+      <vertex X="174.519719" Y="-36.812978"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="50" ADD_L_DIR="1" ADD_L_MAX="81" ADD_L_MIN="45" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="82" ADD_R_MIN="50" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="ROSS LANE" ID="73" ISLAND="North Island" NAME="ROSS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63634" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Huapai" TOWN="" TURNRESLNK="ak99" URBANRURAL="R" ID1="51">
+    <vertices>
+      <vertex X="174.513874" Y="-36.792036"/>
+      <vertex X="174.509156" Y="-36.793528"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="51" ADD_L_DIR="1" ADD_L_MAX="25" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="41" ADD_R_MIN="2" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="SARAH TODD LANE" ID="74" ISLAND="North Island" NAME="SARAH TODD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63632" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Waimauku" TOWN="" TURNRESLNK="ak100" URBANRURAL="R" ID1="52">
+    <vertices>
+      <vertex X="174.491722" Y="-36.769882"/>
+      <vertex X="174.492339" Y="-36.770018"/>
+      <vertex X="174.492473" Y="-36.770058"/>
+      <vertex X="174.492585" Y="-36.770108"/>
+      <vertex X="174.492673" Y="-36.770145"/>
+      <vertex X="174.492751" Y="-36.770176"/>
+      <vertex X="174.492872" Y="-36.770220"/>
+      <vertex X="174.492974" Y="-36.770252"/>
+      <vertex X="174.493106" Y="-36.770287"/>
+      <vertex X="174.493237" Y="-36.770311"/>
+      <vertex X="174.493256" Y="-36.770314"/>
+      <vertex X="174.493276" Y="-36.770317"/>
+      <vertex X="174.493376" Y="-36.770323"/>
+      <vertex X="174.493492" Y="-36.770329"/>
+      <vertex X="174.493583" Y="-36.770329"/>
+      <vertex X="174.493612" Y="-36.770329"/>
+      <vertex X="174.493742" Y="-36.770330"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="52" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="44" ADD_R_MIN="6" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="POYNTER LANE" ID="75" ISLAND="North Island" NAME="POYNTER LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63631" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Pine Valley" TOWN="" TURNRESLNK="ak101" URBANRURAL="R" ID1="53">
+    <vertices>
+      <vertex X="174.626114" Y="-36.630809"/>
+      <vertex X="174.625650" Y="-36.630147"/>
+      <vertex X="174.624725" Y="-36.628828"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="53" ADD_L_DIR="1" ADD_L_MAX="40" ADD_L_MIN="14" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="22" ADD_R_MIN="22" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="PETERS LANE" ID="76" ISLAND="North Island" NAME="PETERS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63630" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Taupaki" TOWN="" TURNRESLNK="ak102" URBANRURAL="R" ID1="54">
+    <vertices>
+      <vertex X="174.536625" Y="-36.824937"/>
+      <vertex X="174.536109" Y="-36.823184"/>
+      <vertex X="174.534002" Y="-36.822798"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="54" ADD_L_DIR="1" ADD_L_MAX="10" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="15" ADD_R_MIN="11" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SIMMONDS LANE" ID="77" ISLAND="North Island" NAME="SIMMONDS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63628" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Mount Wellington" TOWN="Auckland" TURNRESLNK="ak103" URBANRURAL="U" ID1="55">
+    <vertices>
+      <vertex X="174.837888" Y="-36.905740"/>
+      <vertex X="174.837440" Y="-36.905565"/>
+      <vertex X="174.837366" Y="-36.905529"/>
+      <vertex X="174.837323" Y="-36.905485"/>
+      <vertex X="174.837285" Y="-36.905432"/>
+      <vertex X="174.837190" Y="-36.905230"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="55" ADD_L_DIR="1" ADD_L_MAX="19" ADD_L_MIN="8" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="7" ADD_R_MIN="1" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MARINE LANE" ID="78" ISLAND="North Island" NAME="MARINE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63627" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Panmure" TOWN="Auckland" TURNRESLNK="ak104" URBANRURAL="U" ID1="56">
+    <vertices>
+      <vertex X="174.851022" Y="-36.908243"/>
+      <vertex X="174.851100" Y="-36.908210"/>
+      <vertex X="174.851197" Y="-36.908185"/>
+      <vertex X="174.851424" Y="-36.908187"/>
+      <vertex X="174.851546" Y="-36.908196"/>
+      <vertex X="174.851632" Y="-36.908223"/>
+      <vertex X="174.851696" Y="-36.908275"/>
+      <vertex X="174.851731" Y="-36.908333"/>
+      <vertex X="174.851739" Y="-36.908399"/>
+      <vertex X="174.851736" Y="-36.908488"/>
+      <vertex X="174.851734" Y="-36.908601"/>
+      <vertex X="174.851747" Y="-36.908698"/>
+      <vertex X="174.851787" Y="-36.908818"/>
+      <vertex X="174.851886" Y="-36.909043"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="56" ADD_L_DIR="1" ADD_L_MAX="8" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="-1" ADD_R_MAX="12" ADD_R_MIN="10" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="CONVAMORE LANE" ID="79" ISLAND="North Island" NAME="CONVAMORE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="0" OWNERSHIP="1" RC="6" RD_SEG_LNK="63626" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Mount Wellington" TOWN="Auckland" TURNRESLNK="ak105" URBANRURAL="U" ID1="57">
+    <vertices>
+      <vertex X="174.850544" Y="-36.909363"/>
+      <vertex X="174.850607" Y="-36.908479"/>
+      <vertex X="174.850588" Y="-36.908421"/>
+      <vertex X="174.850526" Y="-36.908385"/>
+      <vertex X="174.850149" Y="-36.908363"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="57" ADD_L_DIR="-1" ADD_L_MAX="53" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="24" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="CONVOY LANE" ID="80" ISLAND="North Island" NAME="CONVOY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63625" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Otahuhu" TOWN="Auckland" TURNRESLNK="ak106" URBANRURAL="U" ID1="58">
+    <vertices>
+      <vertex X="174.854789" Y="-36.932748"/>
+      <vertex X="174.854754" Y="-36.933246"/>
+      <vertex X="174.854574" Y="-36.935832"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="58" ADD_L_DIR="-1" ADD_L_MAX="6" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="-1" ADD_R_MAX="11" ADD_R_MIN="1" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MELODY LANE" ID="81" ISLAND="North Island" NAME="MELODY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63624" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Otahuhu" TOWN="Auckland" TURNRESLNK="ak107" URBANRURAL="U" ID1="59">
+    <vertices>
+      <vertex X="174.853044" Y="-36.945118"/>
+      <vertex X="174.853225" Y="-36.945157"/>
+      <vertex X="174.853855" Y="-36.945035"/>
+      <vertex X="174.853956" Y="-36.944992"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="59" ADD_L_DIR="1" ADD_L_MAX="4" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="8" ADD_R_MIN="5" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="DEBORAH HATTON LANE" ID="82" ISLAND="North Island" NAME="DEBORAH HATTON LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="0" OWNERSHIP="1" RC="6" RD_SEG_LNK="63616" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Otahuhu" TOWN="Auckland" TURNRESLNK="ak108" URBANRURAL="U" ID1="60">
+    <vertices>
+      <vertex X="174.849189" Y="-36.930396"/>
+      <vertex X="174.849748" Y="-36.930387"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="60" ADD_L_DIR="-1" ADD_L_MAX="71" ADD_L_MIN="69" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="78" ADD_R_MIN="70" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="WOLVERTON STREET" ID="124" ISLAND="North Island" NAME="WOLVERTON ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="2" RD_SEG_LNK="63615" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Avondale" TOWN="Auckland" TURNRESLNK="ak254" URBANRURAL="U" ID1="61">
+    <vertices>
+      <vertex X="174.695523" Y="-36.909057"/>
+      <vertex X="174.696334" Y="-36.908654"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="61" ADD_L_DIR="1" ADD_L_MAX="13" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="33" ADD_R_MIN="17" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="COTSWOLD LANE" ID="51" ISLAND="North Island" NAME="COTSWOLD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63614" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Mount Wellington" TOWN="Auckland" TURNRESLNK="ak53" URBANRURAL="U" ID1="62">
+    <vertices>
+      <vertex X="174.823371" Y="-36.911283"/>
+      <vertex X="174.823512" Y="-36.911226"/>
+      <vertex X="174.824201" Y="-36.911003"/>
+      <vertex X="174.824304" Y="-36.910974"/>
+      <vertex X="174.824402" Y="-36.910955"/>
+      <vertex X="174.824497" Y="-36.910945"/>
+      <vertex X="174.824604" Y="-36.910939"/>
+      <vertex X="174.824727" Y="-36.910939"/>
+      <vertex X="174.824982" Y="-36.910949"/>
+      <vertex X="174.825108" Y="-36.910949"/>
+      <vertex X="174.825223" Y="-36.910943"/>
+      <vertex X="174.825305" Y="-36.910933"/>
+      <vertex X="174.825411" Y="-36.910905"/>
+      <vertex X="174.825519" Y="-36.910858"/>
+      <vertex X="174.825621" Y="-36.910806"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="62" ADD_L_DIR="1" ADD_L_MAX="14" ADD_L_MIN="4" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="13" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="LEASIDE LANE" ID="52" ISLAND="North Island" NAME="LEASIDE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63613" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glen Innes" TOWN="Auckland" TURNRESLNK="ak54" URBANRURAL="U" ID1="63">
+    <vertices>
+      <vertex X="174.866100" Y="-36.874944"/>
+      <vertex X="174.864949" Y="-36.874544"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="63" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="-1" ADD_R_MAX="4" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="HORNES LANE" ID="53" ISLAND="North Island" NAME="HORNES LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63612" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Onehunga" TOWN="Auckland" TURNRESLNK="ak55" URBANRURAL="U" ID1="64">
+    <vertices>
+      <vertex X="174.776373" Y="-36.922343"/>
+      <vertex X="174.776316" Y="-36.922307"/>
+      <vertex X="174.775964" Y="-36.922240"/>
+      <vertex X="174.775859" Y="-36.922257"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="64" ADD_L_DIR="1" ADD_L_MAX="1" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="LOWER MUNICIPAL PLACE" ID="54" ISLAND="North Island" NAME="LOWER MUNICIPAL PL" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63611" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Onehunga" TOWN="Auckland" TURNRESLNK="ak56" URBANRURAL="U" ID1="65">
+    <vertices>
+      <vertex X="174.783876" Y="-36.923053"/>
+      <vertex X="174.784036" Y="-36.924250"/>
+      <vertex X="174.784055" Y="-36.924297"/>
+      <vertex X="174.784084" Y="-36.924341"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="65" ADD_L_DIR="-1" ADD_L_MAX="11" ADD_L_MIN="3" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="10" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="TYNOR PLACE" ID="55" ISLAND="North Island" NAME="TYNOR PL" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63610" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Hillsborough" TOWN="Auckland" TURNRESLNK="ak57" URBANRURAL="U" ID1="66">
+    <vertices>
+      <vertex X="174.760577" Y="-36.923815"/>
+      <vertex X="174.760323" Y="-36.923977"/>
+      <vertex X="174.759957" Y="-36.924341"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="66" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="UPPER MUNICIPAL PLACE" ID="56" ISLAND="North Island" NAME="UPPER MUNICIPAL PL" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63609" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Onehunga" TOWN="Auckland" TURNRESLNK="ak58" URBANRURAL="U" ID1="67">
+    <vertices>
+      <vertex X="174.784562" Y="-36.922991"/>
+      <vertex X="174.784745" Y="-36.924290"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="67" ADD_L_DIR="1" ADD_L_MAX="18" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="11" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="GEORGE LAURENSON LANE" ID="57" ISLAND="North Island" NAME="GEORGE LAURENSON LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63608" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Waikowhai" TOWN="Auckland" TURNRESLNK="ak59" URBANRURAL="U" ID1="68">
+    <vertices>
+      <vertex X="174.732340" Y="-36.932485"/>
+      <vertex X="174.732194" Y="-36.932424"/>
+      <vertex X="174.732039" Y="-36.932357"/>
+      <vertex X="174.731943" Y="-36.932310"/>
+      <vertex X="174.731750" Y="-36.932199"/>
+      <vertex X="174.731692" Y="-36.932171"/>
+      <vertex X="174.731617" Y="-36.932139"/>
+      <vertex X="174.731547" Y="-36.932113"/>
+      <vertex X="174.731478" Y="-36.932081"/>
+      <vertex X="174.731427" Y="-36.932047"/>
+      <vertex X="174.731401" Y="-36.932005"/>
+      <vertex X="174.731383" Y="-36.931948"/>
+      <vertex X="174.731360" Y="-36.931834"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="68" ADD_L_DIR="-1" ADD_L_MAX="41" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="43" ADD_R_MIN="2" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="DANUBE LANE" ID="58" ISLAND="North Island" NAME="DANUBE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63607" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glen Eden" TOWN="Waitakere" TURNRESLNK="ak60" URBANRURAL="U" ID1="69">
+    <vertices>
+      <vertex X="174.631432" Y="-36.918479"/>
+      <vertex X="174.631385" Y="-36.918487"/>
+      <vertex X="174.630877" Y="-36.918290"/>
+      <vertex X="174.629824" Y="-36.917887"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="69" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="BAKERS LANE" ID="59" ISLAND="North Island" NAME="BAKERS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63606" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Whenuapai" TOWN="" TURNRESLNK="ak61" URBANRURAL="R" ID1="70">
+    <vertices>
+      <vertex X="174.602054" Y="-36.822786"/>
+      <vertex X="174.604625" Y="-36.820273"/>
+      <vertex X="174.604716" Y="-36.820154"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="70" ADD_L_DIR="1" ADD_L_MAX="8" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="11" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="RUBENS LANE" ID="60" ISLAND="North Island" NAME="RUBENS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63605" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="West Harbour" TOWN="Waitakere" TURNRESLNK="ak62" URBANRURAL="U" ID1="71">
+    <vertices>
+      <vertex X="174.635083" Y="-36.821030"/>
+      <vertex X="174.634745" Y="-36.820963"/>
+      <vertex X="174.634522" Y="-36.821011"/>
+      <vertex X="174.634200" Y="-36.821064"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="71" ADD_L_DIR="1" ADD_L_MAX="4" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="3" ADD_R_MIN="3" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Waitakere City" FULL_NAME="SWAN LANE" ID="61" ISLAND="North Island" NAME="SWAN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63604" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Henderson" TOWN="Waitakere" TURNRESLNK="ak63" URBANRURAL="U" ID1="72">
+    <vertices>
+      <vertex X="174.637982" Y="-36.870826"/>
+      <vertex X="174.637337" Y="-36.871554"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="72" ADD_L_DIR="-1" ADD_L_MAX="9" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="8" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="BASIN VIEW LANE" ID="62" ISLAND="North Island" NAME="BASIN VIEW LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63602" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Panmure" TOWN="Auckland" TURNRESLNK="ak64" URBANRURAL="U" ID1="73">
+    <vertices>
+      <vertex X="174.854626" Y="-36.900384"/>
+      <vertex X="174.855122" Y="-36.899952"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="73" ADD_L_DIR="-1" ADD_L_MAX="15" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="16" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="GLENTIES LANE" ID="63" ISLAND="North Island" NAME="GLENTIES LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63601" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Ellerslie" TOWN="Auckland" TURNRESLNK="ak65" URBANRURAL="U" ID1="74">
+    <vertices>
+      <vertex X="174.823038" Y="-36.889889"/>
+      <vertex X="174.823083" Y="-36.889757"/>
+      <vertex X="174.823292" Y="-36.889157"/>
+      <vertex X="174.823300" Y="-36.889114"/>
+      <vertex X="174.823301" Y="-36.889071"/>
+      <vertex X="174.823295" Y="-36.889021"/>
+      <vertex X="174.823238" Y="-36.888703"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="74" ADD_L_DIR="1" ADD_L_MAX="24" ADD_L_MIN="24" ADD_L_TYPE="E" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MERCURY LANE" ID="8" ISLAND="North Island" NAME="MERCURY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="3" RD_SEG_LNK="63668" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Newton" TOWN="Auckland" TURNRESLNK="ak7" URBANRURAL="U" ID1="75">
+    <vertices>
+      <vertex X="174.759225" Y="-36.858848"/>
+      <vertex X="174.759338" Y="-36.859103"/>
+      <vertex X="174.759415" Y="-36.859210"/>
+      <vertex X="174.759542" Y="-36.859290"/>
+      <vertex X="174.759672" Y="-36.859371"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="75" ADD_L_DIR="1" ADD_L_MAX="1" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="12" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SAINT MARTINS LANE" ID="9" ISLAND="North Island" NAME="ST MARTINS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63600" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak8" URBANRURAL="U" ID1="76">
+    <vertices>
+      <vertex X="174.764743" Y="-36.857990"/>
+      <vertex X="174.765292" Y="-36.857534"/>
+      <vertex X="174.764862" Y="-36.857203"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="76" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MARKET LANE" ID="10" ISLAND="North Island" NAME="MARKET LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63599" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak9" URBANRURAL="U" ID1="77">
+    <vertices>
+      <vertex X="174.762109" Y="-36.844683"/>
+      <vertex X="174.762082" Y="-36.844587"/>
+      <vertex X="174.762074" Y="-36.844527"/>
+      <vertex X="174.762076" Y="-36.844486"/>
+      <vertex X="174.762089" Y="-36.844443"/>
+      <vertex X="174.762166" Y="-36.844249"/>
+      <vertex X="174.762278" Y="-36.843958"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="77" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MARKET LANE" ID="11" ISLAND="North Island" NAME="MARKET LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63599" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak10" URBANRURAL="U" ID1="78">
+    <vertices>
+      <vertex X="174.762278" Y="-36.843958"/>
+      <vertex X="174.762447" Y="-36.843521"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="78" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="BRADNOR LANE" ID="12" ISLAND="North Island" NAME="BRADNOR LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63598" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Auckland City Centre" TOWN="Auckland" TURNRESLNK="ak11" URBANRURAL="U" ID1="79">
+    <vertices>
+      <vertex X="174.761602" Y="-36.845360"/>
+      <vertex X="174.761611" Y="-36.845392"/>
+      <vertex X="174.761629" Y="-36.845423"/>
+      <vertex X="174.761650" Y="-36.845446"/>
+      <vertex X="174.761692" Y="-36.845467"/>
+      <vertex X="174.762667" Y="-36.845767"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="79" ADD_L_DIR="1" ADD_L_MAX="14" ADD_L_MIN="4" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="15" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="SAINT THOMAS MORE LANE" ID="163" ISLAND="North Island" NAME="ST THOMAS MORE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63597" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glenfield" TOWN="North Shore" TURNRESLNK="ak146" URBANRURAL="U" ID1="80">
+    <vertices>
+      <vertex X="174.721762" Y="-36.770566"/>
+      <vertex X="174.722295" Y="-36.770628"/>
+      <vertex X="174.722843" Y="-36.771146"/>
+      <vertex X="174.722944" Y="-36.771241"/>
+      <vertex X="174.723064" Y="-36.771246"/>
+      <vertex X="174.723102" Y="-36.771201"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="80" ADD_L_DIR="1" ADD_L_MAX="28" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="11" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="TYBURN LANE" ID="164" ISLAND="North Island" NAME="TYBURN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63596" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Unsworth Heights" TOWN="North Shore" TURNRESLNK="ak147" URBANRURAL="U" ID1="81">
+    <vertices>
+      <vertex X="174.713292" Y="-36.759233"/>
+      <vertex X="174.713272" Y="-36.759544"/>
+      <vertex X="174.712937" Y="-36.759900"/>
+      <vertex X="174.712843" Y="-36.759922"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="81" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="ROSEBERRY LANE" ID="165" ISLAND="North Island" NAME="ROSEBERRY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63594" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Birkenhead" TOWN="North Shore" TURNRESLNK="ak148" URBANRURAL="U" ID1="82">
+    <vertices>
+      <vertex X="174.714800" Y="-36.809357"/>
+      <vertex X="174.715762" Y="-36.809337"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="82" ADD_L_DIR="1" ADD_L_MAX="14" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="11" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="PELICAN LANE" ID="166" ISLAND="North Island" NAME="PELICAN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63593" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="The Palms" TOWN="North Shore" TURNRESLNK="ak149" URBANRURAL="U" ID1="83">
+    <vertices>
+      <vertex X="174.716272" Y="-36.760730"/>
+      <vertex X="174.716504" Y="-36.760433"/>
+      <vertex X="174.716575" Y="-36.760095"/>
+      <vertex X="174.716642" Y="-36.760028"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="83" ADD_L_DIR="1" ADD_L_MAX="89" ADD_L_MIN="21" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="86" ADD_R_MIN="6" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="CROFT LANE" ID="167" ISLAND="North Island" NAME="CROFT LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63592" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Coatesville" TOWN="" TURNRESLNK="ak150" URBANRURAL="R" ID1="84">
+    <vertices>
+      <vertex X="174.608952" Y="-36.730269"/>
+      <vertex X="174.608998" Y="-36.728435"/>
+      <vertex X="174.611995" Y="-36.727512"/>
+      <vertex X="174.614542" Y="-36.727276"/>
+      <vertex X="174.616560" Y="-36.726837"/>
+      <vertex X="174.616910" Y="-36.726860"/>
+      <vertex X="174.617176" Y="-36.726997"/>
+      <vertex X="174.617228" Y="-36.727194"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="84" ADD_L_DIR="-1" ADD_L_MAX="7" ADD_L_MIN="5" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="4" ADD_R_MIN="1" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="LOGAN LANE" ID="168" ISLAND="North Island" NAME="LOGAN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="HIBISCUS COAST" NAMED_ARE2="WHANGAPARAOA PENINSULA" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63591" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Stanmore Bay" TOWN="Whangaparaoa" TURNRESLNK="ak151" URBANRURAL="U" ID1="85">
+    <vertices>
+      <vertex X="174.721974" Y="-36.620861"/>
+      <vertex X="174.722470" Y="-36.620454"/>
+      <vertex X="174.722548" Y="-36.620444"/>
+      <vertex X="174.722624" Y="-36.620466"/>
+      <vertex X="174.722668" Y="-36.620511"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="85" ADD_L_DIR="-1" ADD_L_MAX="18" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="-1" ADD_R_MAX="37" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="BAKEHOUSE LANE" ID="169" ISLAND="North Island" NAME="BAKEHOUSE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="HIBISCUS COAST" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63589" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Orewa" TOWN="Orewa" TURNRESLNK="ak152" URBANRURAL="U" ID1="86">
+    <vertices>
+      <vertex X="174.695998" Y="-36.587363"/>
+      <vertex X="174.695576" Y="-36.586401"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="86" ADD_L_DIR="1" ADD_L_MAX="81" ADD_L_MIN="31" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="88" ADD_R_MIN="44" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="BURNS LANE" ID="170" ISLAND="North Island" NAME="BURNS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="0" OWNERSHIP="1" RC="6" RD_SEG_LNK="63588" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Kumeu" TOWN="" TURNRESLNK="ak153" URBANRURAL="R" ID1="87">
+    <vertices>
+      <vertex X="174.556592" Y="-36.765629"/>
+      <vertex X="174.556029" Y="-36.765517"/>
+      <vertex X="174.555933" Y="-36.765481"/>
+      <vertex X="174.555869" Y="-36.765424"/>
+      <vertex X="174.551561" Y="-36.761151"/>
+      <vertex X="174.551470" Y="-36.761049"/>
+      <vertex X="174.551412" Y="-36.760920"/>
+      <vertex X="174.551402" Y="-36.760817"/>
+      <vertex X="174.551403" Y="-36.760670"/>
+      <vertex X="174.551464" Y="-36.760087"/>
+      <vertex X="174.551439" Y="-36.759710"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="87" ADD_L_DIR="1" ADD_L_MAX="60" ADD_L_MIN="15" ADD_L_TYPE="M" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Rodney" FULL_NAME="GOLDFLATS LANE" ID="171" ISLAND="North Island" NAME="GOLDFLATS LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63587" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Coatesville" TOWN="" TURNRESLNK="ak154" URBANRURAL="R" ID1="88">
+    <vertices>
+      <vertex X="174.623641" Y="-36.733450"/>
+      <vertex X="174.625973" Y="-36.736026"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="88" ADD_L_DIR="1" ADD_L_MAX="14" ADD_L_MIN="2" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="9" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="FALSTONE LANE" ID="172" ISLAND="North Island" NAME="FALSTONE LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63586" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Browns Bay" TOWN="North Shore" TURNRESLNK="ak155" URBANRURAL="U" ID1="89">
+    <vertices>
+      <vertex X="174.726189" Y="-36.721564"/>
+      <vertex X="174.725102" Y="-36.721261"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="89" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="53" ADD_R_MIN="53" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="PENCARROW AVENUE" ID="132" ISLAND="North Island" NAME="PENCARROW AVE" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63585" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Epsom" TOWN="Auckland" TURNRESLNK="ak115" URBANRURAL="U" ID1="90">
+    <vertices>
+      <vertex X="174.766126" Y="-36.889163"/>
+      <vertex X="174.766231" Y="-36.889204"/>
+      <vertex X="174.766327" Y="-36.889264"/>
+      <vertex X="174.766614" Y="-36.889485"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="90" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="17" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SELBY SQUARE" ID="133" ISLAND="North Island" NAME="SELBY SQ" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63583" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Saint Marys Bay" TOWN="Auckland" TURNRESLNK="ak116" URBANRURAL="U" ID1="91">
+    <vertices>
+      <vertex X="174.743485" Y="-36.845338"/>
+      <vertex X="174.743746" Y="-36.845500"/>
+      <vertex X="174.743776" Y="-36.845513"/>
+      <vertex X="174.743803" Y="-36.845518"/>
+      <vertex X="174.743826" Y="-36.845516"/>
+      <vertex X="174.743846" Y="-36.845512"/>
+      <vertex X="174.743862" Y="-36.845501"/>
+      <vertex X="174.743880" Y="-36.845484"/>
+      <vertex X="174.744105" Y="-36.845225"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="91" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="UNION STREET" ID="134" ISLAND="North Island" NAME="UNION ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63565" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Freemans Bay" TOWN="Auckland" TURNRESLNK="ak117" URBANRURAL="U" ID1="92">
+    <vertices>
+      <vertex X="174.754498" Y="-36.850543"/>
+      <vertex X="174.754557" Y="-36.850419"/>
+      <vertex X="174.754610" Y="-36.850378"/>
+      <vertex X="174.754695" Y="-36.850346"/>
+      <vertex X="174.754819" Y="-36.850324"/>
+      <vertex X="174.754952" Y="-36.850328"/>
+      <vertex X="174.755257" Y="-36.850394"/>
+      <vertex X="174.755372" Y="-36.850419"/>
+      <vertex X="174.755711" Y="-36.850433"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="92" ADD_L_DIR="1" ADD_L_MAX="10" ADD_L_MIN="6" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="9" ADD_R_MIN="1" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="YARBOROUGH STREET" ID="136" ISLAND="North Island" NAME="YARBOROUGH ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63562" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Saint Marys Bay" TOWN="Auckland" TURNRESLNK="ak119" URBANRURAL="U" ID1="93">
+    <vertices>
+      <vertex X="174.745114" Y="-36.845546"/>
+      <vertex X="174.744105" Y="-36.845225"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="93" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="SULTAN LANE" ID="87" ISLAND="North Island" NAME="SULTAN LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63561" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Ellerslie" TOWN="Auckland" TURNRESLNK="ak68" URBANRURAL="U" ID1="94">
+    <vertices>
+      <vertex X="174.807469" Y="-36.898926"/>
+      <vertex X="174.807974" Y="-36.898539"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="94" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="-1" ADD_R_MAX="250" ADD_R_MIN="240" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="TANIWHA STREET" ID="88" ISLAND="North Island" NAME="TANIWHA ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63555" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glen Innes" TOWN="Auckland" TURNRESLNK="ak69" URBANRURAL="U" ID1="95">
+    <vertices>
+      <vertex X="174.854332" Y="-36.878091"/>
+      <vertex X="174.854497" Y="-36.878020"/>
+      <vertex X="174.854715" Y="-36.877982"/>
+      <vertex X="174.854783" Y="-36.877963"/>
+      <vertex X="174.854823" Y="-36.877941"/>
+      <vertex X="174.854855" Y="-36.877909"/>
+      <vertex X="174.854876" Y="-36.877874"/>
+      <vertex X="174.854887" Y="-36.877834"/>
+      <vertex X="174.854889" Y="-36.877777"/>
+      <vertex X="174.854877" Y="-36.877733"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="95" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="STRATTON LANE" ID="89" ISLAND="North Island" NAME="STRATTON LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63554" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glen Innes" TOWN="Auckland" TURNRESLNK="ak70" URBANRURAL="U" ID1="96">
+    <vertices>
+      <vertex X="174.855619" Y="-36.879355"/>
+      <vertex X="174.855667" Y="-36.879556"/>
+      <vertex X="174.855826" Y="-36.879538"/>
+      <vertex X="174.856320" Y="-36.879634"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="96" ADD_L_DIR="1" ADD_L_MAX="13" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="1" ADD_R_MAX="12" ADD_R_MIN="2" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="TOSCA LANE" ID="143" ISLAND="North Island" NAME="TOSCA LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63553" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Point England" TOWN="Auckland" TURNRESLNK="ak126" URBANRURAL="U" ID1="97">
+    <vertices>
+      <vertex X="174.860267" Y="-36.879043"/>
+      <vertex X="174.860411" Y="-36.879063"/>
+      <vertex X="174.861071" Y="-36.879128"/>
+      <vertex X="174.861522" Y="-36.879087"/>
+      <vertex X="174.861436" Y="-36.878624"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="97" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="655" ADD_R_MIN="649" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MANUKAU ROAD" ID="110" ISLAND="North Island" NAME="MANUKAU RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="2" RD_SEG_LNK="63549" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Royal Oak" TOWN="Auckland" TURNRESLNK="ak239" URBANRURAL="U" ID1="98">
+    <vertices>
+      <vertex X="174.774915" Y="-36.906935"/>
+      <vertex X="174.775106" Y="-36.907725"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="98" ADD_L_DIR="1" ADD_L_MAX="104" ADD_L_MIN="96" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="119" ADD_R_MIN="115" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="NEWTON ROAD" ID="111" ISLAND="North Island" NAME="NEWTON RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="2" RD_SEG_LNK="63548" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Newton" TOWN="Auckland" TURNRESLNK="ak240" URBANRURAL="U" ID1="99">
+    <vertices>
+      <vertex X="174.757389" Y="-36.862992"/>
+      <vertex X="174.757958" Y="-36.863119"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="99" ADD_L_DIR="-1" ADD_L_MAX="579" ADD_L_MIN="573" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="522" ADD_R_MIN="504" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="HILLSBOROUGH ROAD" ID="112" ISLAND="North Island" NAME="HILLSBOROUGH RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="1" RD_SEG_LNK="63535" REGION="Auckland" ROUTE="Urban Route 15" SH_NO="" SPEED="50" SR="0" SUBURB="Lynfield" TOWN="Auckland" TURNRESLNK="ak241" URBANRURAL="U" ID1="100">
+    <vertices>
+      <vertex X="174.724347" Y="-36.925631"/>
+      <vertex X="174.724459" Y="-36.925724"/>
+      <vertex X="174.724634" Y="-36.925874"/>
+      <vertex X="174.724825" Y="-36.926035"/>
+      <vertex X="174.725776" Y="-36.926815"/>
+      <vertex X="174.725870" Y="-36.926887"/>
+      <vertex X="174.725942" Y="-36.926940"/>
+      <vertex X="174.726110" Y="-36.927055"/>
+      <vertex X="174.726393" Y="-36.927246"/>
+      <vertex X="174.726496" Y="-36.927315"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="100" ADD_L_DIR="-1" ADD_L_MAX="7" ADD_L_MIN="1" ADD_L_TYPE="O" ADD_R_DIR="-1" ADD_R_MAX="12" ADD_R_MIN="2" ADD_R_TYPE="E" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="TRISTRAM AVENUE" ID="113" ISLAND="North Island" NAME="TRISTRAM AVE" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="1" RD_SEG_LNK="63534" REGION="Auckland" ROUTE="Urban Route 21" SH_NO="" SPEED="50" SR="0" SUBURB="Forrest Hill" TOWN="North Shore" TURNRESLNK="ak243" URBANRURAL="U" ID1="101">
+    <vertices>
+      <vertex X="174.747826" Y="-36.770445"/>
+      <vertex X="174.749219" Y="-36.770040"/>
+      <vertex X="174.749250" Y="-36.770034"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="101" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="1" ADD_R_MAX="659" ADD_R_MIN="657" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="MANUKAU ROAD" ID="114" ISLAND="North Island" NAME="MANUKAU RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="2" RD_SEG_LNK="63549" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Royal Oak" TOWN="Auckland" TURNRESLNK="ak244" URBANRURAL="U" ID1="102">
+    <vertices>
+      <vertex X="174.775106" Y="-36.907725"/>
+      <vertex X="174.775199" Y="-36.908106"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="102" ADD_L_DIR="1" ADD_L_MAX="118" ADD_L_MIN="108" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="127" ADD_R_MIN="121" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Auckland City" FULL_NAME="NEWTON ROAD" ID="115" ISLAND="North Island" NAME="NEWTON RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="2" RD_SEG_LNK="63548" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Newton" TOWN="Auckland" TURNRESLNK="ak245" URBANRURAL="U" ID1="103">
+    <vertices>
+      <vertex X="174.757958" Y="-36.863119"/>
+      <vertex X="174.758606" Y="-36.863259"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="103" ADD_L_DIR="-1" ADD_L_MAX="8" ADD_L_MIN="1" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="11" ADD_R_MIN="9" ADD_R_TYPE="O" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="CHERRY LANE" ID="33" ISLAND="North Island" NAME="CHERRY LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="0" OWNERSHIP="1" RC="6" RD_SEG_LNK="63533" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Glenfield" TOWN="North Shore" TURNRESLNK="ak33" URBANRURAL="U" ID1="104">
+    <vertices>
+      <vertex X="174.745740" Y="-36.780780"/>
+      <vertex X="174.744841" Y="-36.779979"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="104" ADD_L_DIR="1" ADD_L_MAX="14" ADD_L_MIN="5" ADD_L_TYPE="M" ADD_R_DIR="-1" ADD_R_MAX="4" ADD_R_MIN="1" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="North Shore City" FULL_NAME="ELDERWOOD LANE" ID="34" ISLAND="North Island" NAME="ELDERWOOD LN" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="4" RD_SEG_LNK="63526" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Belmont" TOWN="North Shore" TURNRESLNK="ak34" URBANRURAL="U" ID1="105">
+    <vertices>
+      <vertex X="174.785128" Y="-36.803494"/>
+      <vertex X="174.784406" Y="-36.803101"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="105" ADD_L_DIR="0" ADD_L_MAX="0" ADD_L_MIN="0" ADD_L_TYPE="" ADD_R_DIR="0" ADD_R_MAX="0" ADD_R_MIN="0" ADD_R_TYPE="" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Manukau City" FULL_NAME="WATFORD STREET" ID="229" ISLAND="North Island" NAME="WATFORD ST" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="5" RD_SEG_LNK="63522" REGION="Auckland" ROUTE="" SH_NO="" SPEED="50" SR="0" SUBURB="Otara" TOWN="Manukau" TURNRESLNK="ak210" URBANRURAL="U" ID1="106">
+    <vertices>
+      <vertex X="174.872745" Y="-36.960379"/>
+      <vertex X="174.872738" Y="-36.960413"/>
+      <vertex X="174.872731" Y="-36.960486"/>
+      <vertex X="174.872746" Y="-36.960670"/>
+    </vertices>
+  </shape>
+  <shape shapeType="polyLine" id="106" ADD_L_DIR="1" ADD_L_MAX="484" ADD_L_MIN="140" ADD_L_TYPE="E" ADD_R_DIR="1" ADD_R_MAX="411" ADD_R_MIN="75" ADD_R_TYPE="M" ALTERNATE_="" BRIDGE_NAM="" DISTRICT="Papakura" FULL_NAME="HUNUA ROAD" ID="230" ISLAND="North Island" NAME="HUNUA RD" NAMED_AREA="GREATER AUCKLAND" NAMED_ARE1="" NAMED_ARE2="" OPEN_TO_PU="1" OWNERSHIP="0" RC="3" RD_SEG_LNK="63521" REGION="Auckland" ROUTE="" SH_NO="" SPEED="100" SR="0" SUBURB="Red Hill" TOWN="Papakura" TURNRESLNK="ak211" URBANRURAL="R" ID1="107">
+    <vertices>
+      <vertex X="174.975798" Y="-37.075472"/>
+      <vertex X="174.976585" Y="-37.075457"/>
+      <vertex X="174.976789" Y="-37.075536"/>
+      <vertex X="174.976827" Y="-37.075551"/>
+      <vertex X="174.977052" Y="-37.075638"/>
+      <vertex X="174.977470" Y="-37.075721"/>
+      <vertex X="174.978963" Y="-37.075603"/>
+      <vertex X="174.980279" Y="-37.075201"/>
+      <vertex X="174.980735" Y="-37.075021"/>
+      <vertex X="174.981142" Y="-37.074698"/>
+      <vertex X="174.981180" Y="-37.074427"/>
+      <vertex X="174.980887" Y="-37.073648"/>
+      <vertex X="174.980700" Y="-37.073390"/>
+      <vertex X="174.980648" Y="-37.073139"/>
+      <vertex X="174.980690" Y="-37.073039"/>
+      <vertex X="174.980847" Y="-37.073000"/>
+      <vertex X="174.981197" Y="-37.073075"/>
+      <vertex X="174.981701" Y="-37.072985"/>
+      <vertex X="174.981914" Y="-37.072972"/>
+      <vertex X="174.982619" Y="-37.072418"/>
+      <vertex X="174.982929" Y="-37.072250"/>
+      <vertex X="174.983356" Y="-37.072233"/>
+      <vertex X="174.983724" Y="-37.072524"/>
+      <vertex X="174.983981" Y="-37.072844"/>
+      <vertex X="174.984317" Y="-37.073586"/>
+      <vertex X="174.984488" Y="-37.073673"/>
+      <vertex X="174.985129" Y="-37.073679"/>
+      <vertex X="174.985819" Y="-37.073811"/>
+      <vertex X="174.987735" Y="-37.074740"/>
+      <vertex X="174.987897" Y="-37.074872"/>
+      <vertex X="174.988529" Y="-37.075753"/>
+      <vertex X="174.989204" Y="-37.076525"/>
+      <vertex X="174.989827" Y="-37.076685"/>
+      <vertex X="174.990158" Y="-37.076850"/>
+      <vertex X="174.990654" Y="-37.077283"/>
+      <vertex X="174.990747" Y="-37.077398"/>
+      <vertex X="174.990887" Y="-37.077558"/>
+      <vertex X="174.991457" Y="-37.077836"/>
+      <vertex X="174.991798" Y="-37.077938"/>
+      <vertex X="174.992227" Y="-37.078022"/>
+    </vertices>
+  </shape>
+</shapes>
diff --git a/test/hexpat-tests.cabal b/test/hexpat-tests.cabal
--- a/test/hexpat-tests.cabal
+++ b/test/hexpat-tests.cabal
@@ -9,16 +9,16 @@
 
   build-depends:
     HUnit < 1.3,
-    QuickCheck == 2.4.*,
+    QuickCheck >= 2.7.0.0,
     base >= 3 && < 5,
     bytestring,
     containers,
     transformers,
     deepseq >= 1.1.0.0,
-    parallel >= 3.1.0.0 && < 3.3.0.0,
-    test-framework > 0.3.0,
-    test-framework-hunit == 0.2.*,
-    test-framework-quickcheck2 == 0.2.*,
+    parallel >= 3.1.0.0,
+    test-framework,
+    test-framework-hunit,
+    test-framework-quickcheck2,
     text >= 0.5,
     utf8-string >= 0.3.3,
     List >= 0.4.2,
diff --git a/test/readRoads.hs b/test/readRoads.hs
new file mode 100644
--- /dev/null
+++ b/test/readRoads.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE OverloadedStrings #-}
+import Text.XML.Expat.Tree
+import Control.Monad
+import Data.Text (Text)
+import qualified Data.Text as T
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as L
+import Data.Maybe
+
+
+-- Reads the contents of ROADS.xml from stdin
+main :: IO ()
+main = do
+    bs <- L.getContents
+    let Element _ _ chs = parseThrowing defaultParseOptions bs :: UNode Text
+    forM_ chs $ \ch -> do
+        case ch of
+            elt@(Element "shape" _ _) -> do
+                putStrLn $ T.unpack $ fromMaybe "" $ getAttribute elt "FULL_NAME"
+            _ -> return ()
diff --git a/test/suite/Text/XML/Expat/Cursor/Tests.hs b/test/suite/Text/XML/Expat/Cursor/Tests.hs
--- a/test/suite/Text/XML/Expat/Cursor/Tests.hs
+++ b/test/suite/Text/XML/Expat/Cursor/Tests.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE BangPatterns, FlexibleContexts, OverloadedStrings #-}
 
 module Text.XML.Expat.Cursor.Tests (tests) where
 
@@ -159,6 +158,7 @@
 
         return (n', ch1, chN)
 
+    p :: (TNode, TNode, TNode) -> Bool
     p (node, ch1, chN) = p1 && p2
       where
         cursor = fromTree node
diff --git a/test/suite/Text/XML/Expat/ParallelTest.hs b/test/suite/Text/XML/Expat/ParallelTest.hs
--- a/test/suite/Text/XML/Expat/ParallelTest.hs
+++ b/test/suite/Text/XML/Expat/ParallelTest.hs
@@ -17,6 +17,7 @@
 import qualified Data.ByteString.Lazy.Char8 as L
 import Test.QuickCheck
 import Test.QuickCheck.Gen
+import Test.QuickCheck.Random
 import Test.HUnit hiding (Node)
 import System.IO
 import System.Random
@@ -47,19 +48,16 @@
 testParallel fork = do
     resultMVs <- replicateM nthreads $ do
         resultMV <- newEmptyMVar
-        fork $ do
-            g <- newStdGen
-            flip evalStateT g $ do
-                replicateM_ nloops $ do
-                    (g, g2) <- gets split
-                    put g
-                    let treeIn = normalizeText $ unGen (arbitrary :: Gen TNode) g 0
-                        xml = breakUp $ format' treeIn
-                        treeOut = normalizeText $ parseThrowing defaultParseOptions xml
-                    lift $ assertEqual "tree match" treeIn treeOut
-                      `catch` \exc -> do
-                          putStrLn $ "failing XML: "++concat (map B.unpack $ L.toChunks xml)
-                          throwIO (exc :: SomeException)
+        do
+            replicateM_ nloops $ do
+                g <- newQCGen
+                let treeIn = normalizeText $ unGen (arbitrary :: Gen TNode) g 30
+                    xml = breakUp $ format' treeIn
+                    treeOut = normalizeText $ parseThrowing defaultParseOptions xml
+                assertEqual "tree match" treeIn treeOut
+                  `catch` \exc -> do
+                      putStrLn $ "failing XML: "++concat (map B.unpack $ L.toChunks xml)
+                      throwIO (exc :: SomeException)
             putMVar resultMV Nothing
           `catch` \exc -> do
             putMVar resultMV $ Just (exc :: SomeException)
diff --git a/test/suite/Text/XML/Expat/ParseFormat.hs b/test/suite/Text/XML/Expat/ParseFormat.hs
--- a/test/suite/Text/XML/Expat/ParseFormat.hs
+++ b/test/suite/Text/XML/Expat/ParseFormat.hs
@@ -173,7 +173,7 @@
                                 sbDoc = normalizeText $ fromElement (getRoot $ pfDoc pf)
                             assertEqual "parse match" sbDoc (root :: Tree.UNode Text)
                             let sb = fromMaybe (pfXML pf) (impl `lookup` pfOutXML pf)
-                                bs = formatTree' root
+                                bs = format' root
                             assertEqual "format match" sb bs
             ]
         Annotated -> [
@@ -185,7 +185,7 @@
                                 sbDoc = normalizeText $ fromElement (getRoot $ pfDoc pf)
                             assertEqual "parse match" sbDoc (root :: Annotated.UNode () Text)
                             let sb = fromMaybe (pfXML pf) (impl `lookup` pfOutXML pf)
-                                bs = formatTree' root
+                                bs = format' root
                             assertEqual "format match" sb bs
             ]
         Extended  -> [
diff --git a/test/suite/Text/XML/Expat/UnitTests.hs b/test/suite/Text/XML/Expat/UnitTests.hs
--- a/test/suite/Text/XML/Expat/UnitTests.hs
+++ b/test/suite/Text/XML/Expat/UnitTests.hs
@@ -2,12 +2,14 @@
 
 import Text.XML.Expat.Tree hiding (parse)
 import qualified Text.XML.Expat.Tree as Tree
-import Text.XML.Expat.IO hiding (parse)
-import qualified Text.XML.Expat.IO as IO
+import Text.XML.Expat.SAX (SAXEvent(..))
+import qualified Text.XML.Expat.SAX as SAX
 import Text.XML.Expat.Cursor
 import Text.XML.Expat.Format
-import Text.XML.Expat.Qualified
+import Text.XML.Expat.Extended (LDocument)
+import qualified Text.XML.Expat.Extended as Extended
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as C
 import qualified Data.ByteString.Lazy.Char8 as LC
 import qualified Data.ByteString.Lazy as L
 import qualified Data.Text as T
@@ -16,8 +18,10 @@
 import Data.ByteString.Internal (c2w, w2c)
 import Data.Char
 import Data.Maybe
+import Data.Monoid
 import Data.IORef
 import Control.Applicative
+import Control.Arrow (first)
 import Control.Exception as E
 import Control.Monad
 import Control.DeepSeq
@@ -98,30 +102,6 @@
     assertEqual "error1" (Left $ XMLParseError "not well-formed (invalid token)"
         (XMLParseLocation 1 0 0 0)) eDoc
 
-test_parse :: IO ()
-test_parse = do
-    ref <- newIORef []
-    let lazy = L.fromChunks [
-            toByteString "<open><tes",
-            toByteString "t1>Hello</test",
-            toByteString "1><hello></he",
-            toByteString "llo></open>"]
-    parser <- newParser Nothing
-    setStartElementHandler parser $ \_ cname cattrs -> do
-        name <- peekCString cname
-        ref <- modifyIORef ref $ \l -> ("start "++name):l
-        return True
-    setEndElementHandler parser $ \_ cname -> do
-        name <- peekCString cname
-        ref <- modifyIORef ref $ \l -> ("end "++name):l
-        return True
-    IO.parse parser lazy
-    l <- reverse <$> readIORef ref
-    assertEqual "parse"
-        ["start open","start test1","end test1","start hello","end hello","end open"]
-        l
-
-
 test_entities1 = do
     assertEqual "parse error" merr Nothing
     assertEqual "entity substitution" (Text "foo") c
@@ -240,6 +220,68 @@
 data ParseFormatTest = ParseFormatTest {
     }
 
+test_xmlDecl1 :: IO ()
+test_xmlDecl1 = do
+    assertEqual "plain" [XMLDeclaration "1.0" Nothing Nothing,StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\"?><hello/>") :: [SAXEvent String String])
+    assertEqual "withEnc" [XMLDeclaration "1.0" (Just "UTF-8") Nothing,StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello/>") :: [SAXEvent String String])
+    assertEqual "SA0" [XMLDeclaration "1.0" Nothing (Just False),StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\" standalone=\"no\"?><hello/>") :: [SAXEvent String String])
+    assertEqual "SA1" [XMLDeclaration "1.0" Nothing (Just True),StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\" standalone=\"yes\"?><hello/>") :: [SAXEvent String String])
+    assertEqual "SA0enc" [XMLDeclaration "1.0" (Just "UTF-8") (Just False),StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><hello/>") :: [SAXEvent String String])
+    assertEqual "SA1enc" [XMLDeclaration "1.0" (Just "UTF-8") (Just True),StartElement "hello" [],EndElement "hello"]
+        (SAX.parse defaultParseOptions (LC.pack "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><hello/>") :: [SAXEvent String String])
+
+normalizeSAXText :: Monoid t => [SAXEvent s t] -> [SAXEvent s t]
+normalizeSAXText (CharacterData a:CharacterData b:xs) = normalizeSAXText (CharacterData (a `mappend` b):xs)
+normalizeSAXText (x:xs) = x:normalizeSAXText xs
+normalizeSAXText [] = []
+
+test_various :: IO ()
+test_various =
+    assertEqual "var1" [
+            StartElement "test" [],
+            StartElement "sample" [("id","5")],
+            CharacterData "This \"text with quotations\" should be escaped.",
+            EndElement "sample",
+            StartElement "mytest" [],
+            CharacterData "//",
+            StartCData,
+            CharacterData "This \"text with quotations\" should not be escaped.//",
+            EndCData,
+            EndElement "mytest",
+            ProcessingInstruction "php" "somecode(); ",
+            Comment " this is a comment ",
+            EndElement "test"
+        ]
+        (normalizeSAXText $ SAX.parse defaultParseOptions (LC.pack variousText) :: [SAXEvent String String])
+
+variousText =
+    "<test>"++
+    "<sample id=\"5\">This \"text with quotations\" should be escaped.</sample>"++
+    "<mytest>"++
+    "//<![CDATA["++
+    "This \"text with quotations\" should not be escaped."++
+    "//]]>"++
+    "</mytest>"++
+    "<?php somecode(); ?>"++
+    "<!-- this is a comment -->"++
+    "</test>"
+
+quotationOut =
+    "<test><sample id=\"5\">This &quot;text with quotations&quot; should be escaped.</sample>"++
+    "<mytest>//<![CDATA[This \"text with quotations\" should not be escaped.//]]>"++
+    "</mytest><?php somecode(); ?><!-- this is a comment --></test>"
+
+test_quotation =
+    assertEqual "quotation"
+        (quotationOut, Nothing)
+        $ first (C.unpack . mconcat . LC.toChunks . formatDocument)
+        $ (Extended.parse defaultParseOptions (LC.pack variousText) :: (LDocument String String, Maybe XMLParseError))
+
 tests = hUnitTestToTests $
     TestList [
         t' ("String",
@@ -276,12 +318,14 @@
         TestLabel "error2" $ TestCase $ test_error2,
         TestLabel "error3" $ TestCase $ test_error3,
         TestLabel "error4" $ TestCase $ test_error4,
-        TestLabel "parse" $ TestCase $ test_parse,
         TestLabel "entities1" $ TestCase $ test_entities1,
         TestLabel "entities2" $ TestCase $ test_entities2,
         TestLabel "textContent" $ TestCase $ test_textContent,
         TestLabel "indent" $ TestCase $ test_indent,
-        TestLabel "setAttribute" $ TestCase $ test_setAttribute
+        TestLabel "setAttribute" $ TestCase $ test_setAttribute,
+        TestLabel "xmlDecl1" $ TestCase $ test_xmlDecl1,
+        TestLabel "various" $ TestCase $ test_various,
+        TestLabel "quotation" $ TestCase $ test_quotation
       ]
 
   where
