 -- |@parseChunk data False@ feeds /strict/ ByteString data into a
 -- 'Parser'.  The end of the data is indicated by passing @True@ for the
 -- final parameter.  @parse@ returns @False@ on a parse error.
-{#fun XML_Parse as parseChunk
+parseChunk :: Parser
+              -> BS.ByteString
+              -> Bool
+              -> IO Bool
+parseChunk parser@(Parser fp startRef endRef charRef) xml final = do
+    bracket
+        (do
+            cStartH <- mkCStartElementHandler =<< readIORef startRef
+            cEndH   <- mkCEndElementHandler =<< readIORef endRef
+            cCharH  <- mkCCharacterDataHandler =<< readIORef charRef
+            withParser parser $ \p -> do
+                {#call unsafe XML_SetStartElementHandler as ^#}  p cStartH
+                {#call unsafe XML_SetEndElementHandler as ^#}    p cEndH
+                {#call unsafe XML_SetCharacterDataHandler as ^#} p cCharH
+            return (cStartH, cEndH, cCharH))
+        (\(cStartH, cEndH, cCharH) -> do
+            freeHaskellFunPtr cStartH
+            freeHaskellFunPtr cEndH
+            freeHaskellFunPtr cCharH)
+        (\_ -> doParseChunk parser xml final)
+
+{#fun XML_Parse as doParseChunk
     {withParser* `Parser', withBStringLen* `BS.ByteString' &, `Bool'}
     -> `Bool' unStatus#}
 

type CharacterDataHandler = String -> IO ()

type CStartElementHandler = Ptr () -> CString -> Ptr CString -> IO ()
foreign import ccall "wrapper"
  mkCStartElementHandler :: CStartElementHandler
                         -> IO (FunPtr CStartElementHandler)
wrapStartElementHandler :: StartElementHandler
                        -> IO (FunPtr CStartElementHandler)
wrapStartElementHandler handler = mkCStartElementHandler h where
  h ptr cname cattrs = do
    name <- peekCString cname
    cattrlist <- peekArray0 nullPtr cattrs

    handler name (pairwise attrlist)
-- |Attach a StartElementHandler to a Parser.
setStartElementHandler :: Parser -> StartElementHandler -> IO ()
setStartElementHandler parser@(Parser _ startRef _ _) handler = do
  withParser parser $ \p -> do
  writeIORef startRef $ wrapStartElementHandler handler


type CEndElementHandler = Ptr () -> CString -> IO ()
nullCEndElementHandler _ _ = return ()

foreign import ccall "wrapper"
  mkCEndElementHandler :: CEndElementHandler
                       -> IO (FunPtr CEndElementHandler)
wrapEndElementHandler :: EndElementHandler -> CEndElementHandler
wrapEndElementHandler handler = h where
  h ptr cname = do
    name <- peekCString cname
    handler name

-- |Attach an EndElementHandler to a Parser.
setEndElementHandler :: Parser -> EndElementHandler -> IO ()
setEndElementHandler parser@(Parser _ _ endRef _) handler = do
  withParser parser $ \p -> do
  writeIORef endRef $ wrapEndElementHandler handler

type CCharacterDataHandler = Ptr () -> CString -> CInt -> IO ()
nullCCharacterDataHandler _ _ _ = return ()

foreign import ccall "wrapper"
  mkCCharacterDataHandler :: CCharacterDataHandler
                          -> IO (FunPtr CCharacterDataHandler)
wrapCharacterDataHandler :: CharacterDataHandler -> CCharacterDataHandler
wrapCharacterDataHandler handler = h where
  h ptr cdata len = do
    data_ <- peekCStringLen (cdata, fromIntegral len)
    handler data_
-- |Attach an CharacterDataHandler to a Parser.
setCharacterDataHandler :: Parser -> CharacterDataHandler -> IO ()
setCharacterDataHandler parser@(Parser _ _ _ charRef) handler = do
  withParser parser $ \p -> do
  writeIORef charRef $ wrapCharacterDataHandler handler

pairwise (x1:x2:xs) = (x1,x2) : pairwise xs
pairwise []         = []
