diff --git a/Codec/Compression/GZip.hs b/Codec/Compression/GZip.hs
--- a/Codec/Compression/GZip.hs
+++ b/Codec/Compression/GZip.hs
@@ -1,9 +1,9 @@
 -----------------------------------------------------------------------------
 -- |
--- Copyright   :  (c) 2006 Duncan Coutts
+-- Copyright   :  (c) 2006-2008 Duncan Coutts
 -- License     :  BSD-style
 --
--- Maintainer  :  duncan.coutts@worc.ox.ac.uk
+-- Maintainer  :  duncan@haskell.org
 -- Stability   :  provisional
 -- Portability :  portable (H98 + FFI)
 --
@@ -18,8 +18,8 @@
 module Codec.Compression.GZip (
 
   -- | This module provides pure functions for compressing and decompressing
-  -- streams of data represented by lazy 'ByteString's. This makes it easy to
-  -- use either in memory or with disk or network IO.
+  -- streams of data in the gzip format and represented by lazy 'ByteString's.
+  -- This makes it easy to use either in memory or with disk or network IO.
   --
   -- For example a simple gzip compression program is just:
   --
@@ -33,19 +33,30 @@
   -- > content <- fmap GZip.decompress (readFile file)
   --
 
-  -- * Compression
+  -- * Simple compression and decompression
   compress,
+  decompress,
+
+  -- * Extended api with control over compression parameters
   compressWith,
-  CompressionLevel(..),
+  decompressWith,
 
-  -- * Decompression
-  decompress
+  CompressParams(..), defaultCompressParams,
+  DecompressParams(..), defaultDecompressParams,
 
+  -- ** The compression parameter types
+  CompressionLevel(..),
+  Method(..),
+  WindowBits(..),
+  MemoryLevel(..),
+  CompressionStrategy(..),
+
   ) where
 
 import Data.ByteString.Lazy (ByteString)
 
-import Codec.Compression.Zlib.Internal as Internal
+import qualified Codec.Compression.Zlib.Internal as Internal
+import Codec.Compression.Zlib.Internal hiding (compress, decompress)
 
 
 -- | Decompress a stream of data in the gzip format.
@@ -66,24 +77,39 @@
 -- stream before doing any IO action that depends on it.
 --
 decompress :: ByteString -> ByteString
-decompress = Internal.decompressDefault GZip
+decompress = Internal.decompress GZip defaultDecompressParams
 
 
+-- | Like 'decompress' but with the ability to specify various decompression
+-- parameters. Typical usage:
+--
+-- > decompressWith defaultCompressParams { ... }
+--
+decompressWith :: DecompressParams -> ByteString -> ByteString
+decompressWith = Internal.decompress GZip
+
+
 -- | Compress a stream of data into the gzip format.
 --
--- This uses the default compression level which favours a higher compression
--- ratio over compression speed. Use 'compressWith' to adjust the compression
--- level.
+-- This uses the default compression parameters. In partiular it uses the
+-- default compression level which favours a higher compression ratio over
+-- compression speed, though it does not use the maximum compression level.
 --
+-- Use 'compressWith' to adjust the compression level or other compression
+-- parameters.
+--
 compress :: ByteString -> ByteString
-compress = Internal.compressDefault GZip DefaultCompression
+compress = Internal.compress GZip defaultCompressParams
 
 
--- | Like 'compress' but with an extra parameter to specify the compression
--- level.
+-- | Like 'compress' but with the ability to specify various compression
+-- parameters. Typical usage:
 --
--- There are a number of additional compression parameters which are rarely
--- necessary to change but if you need to you can do so using 'compressFull'.
+-- > compressWith defaultCompressParams { ... }
 --
-compressWith ::CompressionLevel -> ByteString -> ByteString
-compressWith = Internal.compressDefault GZip
+-- In particular you can set the compression level:
+--
+-- > compressWith defaultCompressParams { compressLevel = BestCompression }
+--
+compressWith :: CompressParams -> ByteString -> ByteString
+compressWith = Internal.compress GZip
diff --git a/Codec/Compression/Zlib.hs b/Codec/Compression/Zlib.hs
--- a/Codec/Compression/Zlib.hs
+++ b/Codec/Compression/Zlib.hs
@@ -1,9 +1,9 @@
 -----------------------------------------------------------------------------
 -- |
--- Copyright   :  (c) 2006 Duncan Coutts
+-- Copyright   :  (c) 2006-2008 Duncan Coutts
 -- License     :  BSD-style
 --
--- Maintainer  :  duncan.coutts@worc.ox.ac.uk
+-- Maintainer  :  duncan@haskell.org
 -- Stability   :  provisional
 -- Portability :  portable (H98 + FFI)
 --
@@ -16,26 +16,88 @@
 --
 -----------------------------------------------------------------------------
 module Codec.Compression.Zlib (
-  
-  -- * Compression
+
+  -- | This module provides pure functions for compressing and decompressing
+  -- streams of data in the zlib format and represented by lazy 'ByteString's.
+  -- This makes it easy to use either in memory or with disk or network IO.
+
+  -- * Simple compression and decompression
   compress,
+  decompress,
+
+  -- * Extended api with control over compression parameters
   compressWith,
+  decompressWith,
+
+  CompressParams(..), defaultCompressParams,
+  DecompressParams(..), defaultDecompressParams,
+
+  -- ** The compression parameter types
   CompressionLevel(..),
-  
-  -- * Decompression
-  decompress
+  Method(..),
+  WindowBits(..),
+  MemoryLevel(..),
+  CompressionStrategy(..),
 
   ) where
 
 import Data.ByteString.Lazy (ByteString)
 
-import Codec.Compression.Zlib.Internal as Internal
+import qualified Codec.Compression.Zlib.Internal as Internal
+import Codec.Compression.Zlib.Internal hiding (compress, decompress)
 
+
+-- | Decompress a stream of data in the zlib format.
+--
+-- There are a number of errors that can occur. In each case an exception will
+-- be thrown. The possible error conditions are:
+--
+-- * if the stream does not start with a valid gzip header
+--
+-- * if the compressed stream is corrupted
+--
+-- * if the compressed stream ends permaturely
+--
+-- Note that the decompression is performed /lazily/. Errors in the data stream
+-- may not be detected until the end of the stream is demanded (since it is
+-- only at the end that the final checksum can be checked). If this is
+-- important to you, you must make sure to consume the whole decompressed
+-- stream before doing any IO action that depends on it.
+--
 decompress :: ByteString -> ByteString
-decompress = Internal.decompressDefault Zlib
+decompress = Internal.decompress Zlib defaultDecompressParams
 
+
+-- | Like 'decompress' but with the ability to specify various decompression
+-- parameters. Typical usage:
+--
+-- > decompressWith defaultCompressParams { ... }
+--
+decompressWith :: DecompressParams -> ByteString -> ByteString
+decompressWith = Internal.decompress Zlib
+
+
+-- | Compress a stream of data into the zlib format.
+--
+-- This uses the default compression parameters. In partiular it uses the
+-- default compression level which favours a higher compression ratio over
+-- compression speed, though it does not use the maximum compression level.
+--
+-- Use 'compressWith' to adjust the compression level or other compression
+-- parameters.
+--
 compress :: ByteString -> ByteString
-compress = Internal.compressDefault Zlib DefaultCompression
+compress = Internal.compress Zlib defaultCompressParams
 
-compressWith ::CompressionLevel -> ByteString -> ByteString
-compressWith = Internal.compressDefault Zlib
+
+-- | Like 'compress' but with the ability to specify various compression
+-- parameters. Typical usage:
+--
+-- > compressWith defaultCompressParams { ... }
+--
+-- In particular you can set the compression level:
+--
+-- > compressWith defaultCompressParams { compressLevel = BestCompression }
+--
+compressWith :: CompressParams -> ByteString -> ByteString
+compressWith = Internal.compress Zlib
diff --git a/Codec/Compression/Zlib/Internal.hs b/Codec/Compression/Zlib/Internal.hs
--- a/Codec/Compression/Zlib/Internal.hs
+++ b/Codec/Compression/Zlib/Internal.hs
@@ -1,9 +1,10 @@
+{-# LANGUAGE CPP #-}
 -----------------------------------------------------------------------------
 -- |
--- Copyright   :  (c) 2006-2007 Duncan Coutts
+-- Copyright   :  (c) 2006-2008 Duncan Coutts
 -- License     :  BSD-style
 --
--- Maintainer  :  duncan.coutts@worc.ox.ac.uk
+-- Maintainer  :  duncan@haskell.org
 -- Stability   :  provisional
 -- Portability :  portable (H98 + FFI)
 --
@@ -12,20 +13,23 @@
 -----------------------------------------------------------------------------
 module Codec.Compression.Zlib.Internal (
 
-  -- * Compression and decompression
-  compressDefault,
-  decompressDefault,
+  -- * Compression
+  compress,
+  CompressParams(..),
+  defaultCompressParams,
+
+  -- * Decompression
+  decompress,
+  DecompressParams(..),
+  defaultDecompressParams,
+
+  -- * The compression parameter types
   Stream.Format(..),
   Stream.CompressionLevel(..),
-
-  -- * The same but with the full set of parameters
-  compressFull,
-  decompressFull,
   Stream.Method(..),
   Stream.WindowBits(..),
   Stream.MemoryLevel(..),
   Stream.CompressionStrategy(..),
-
   ) where
 
 import Prelude hiding (length)
@@ -42,64 +46,111 @@
 import qualified Codec.Compression.Zlib.Stream as Stream
 import Codec.Compression.Zlib.Stream (Stream)
 
-compressDefault
-  :: Stream.Format
-  -> Stream.CompressionLevel
-  -> L.ByteString
-  -> L.ByteString
-compressDefault format compressionLevel =
-  compressFull format
-               compressionLevel
-               Stream.Deflated
-               Stream.DefaultWindowBits
-               Stream.DefaultMemoryLevel
-               Stream.DefaultStrategy
+-- | The full set of parameters for compression. The defaults are
+-- 'defaultCompressParams'.
+--
+-- The 'compressBufferSize' is the size of the first output buffer containing
+-- the compressed data. If you know an approximate upper bound on the size of
+-- the compressed data then setting this parameter can save memory. The default
+-- compression output buffer size is @16k@. If your extimate is wrong it does
+-- not matter too much, the default buffer size will be used for the remaining
+-- chunks.
+--
+data CompressParams = CompressParams {
+  compressLevel       :: Stream.CompressionLevel,
+  compressMethod      :: Stream.Method,
+  compressWindowBits  :: Stream.WindowBits,
+  compressMemoryLevel :: Stream.MemoryLevel,
+  compressStrategy    :: Stream.CompressionStrategy,
+  compressBufferSize  :: Int
+}
 
-decompressDefault
-  :: Stream.Format
-  -> L.ByteString
-  -> L.ByteString
-decompressDefault format =
-  decompressFull format
-                 Stream.DefaultWindowBits
+-- | The full set of parameters for decompression. The defaults are
+-- 'defaultDecompressParams'.
+--
+-- The 'decompressBufferSize' is the size of the first output buffer,
+-- containing the uncompressed data. If you know an exact or approximate upper
+-- bound on the size of the decompressed data then setting this parameter can
+-- save memory. The default decompression output buffer size is @32k@. If your
+-- extimate is wrong it does not matter too much, the default buffer size will
+-- be used for the remaining chunks.
+--
+-- One particular use case for setting the 'decompressBufferSize' is if you
+-- know the exact size of the decompressed data and want to produce a strict
+-- 'Data.ByteString.ByteString'. The compression and deccompression functions
+-- use lazy 'Data.ByteString.Lazy.ByteString's but if you set the
+-- 'decompressBufferSize' correctly then you can generate a lazy
+-- 'Data.ByteString.Lazy.ByteString' with exactly one chunk, which can be
+-- converted to a strict 'Data.ByteString.ByteString' in @O(1)@ time using
+-- @'Data.ByteString.concat' . 'Data.ByteString.Lazy.toChunks'@.
+--
+data DecompressParams = DecompressParams {
+  decompressWindowBits :: Stream.WindowBits,
+  decompressBufferSize :: Int
+}
 
-{-# NOINLINE compressFull #-}
-compressFull
+-- | The default set of parameters for compression. This is typically used with
+-- the @compressWith@ function with specific paramaters overridden.
+--
+defaultCompressParams :: CompressParams
+defaultCompressParams = CompressParams {
+  compressLevel       = Stream.DefaultCompression,
+  compressMethod      = Stream.Deflated,
+  compressWindowBits  = Stream.DefaultWindowBits,
+  compressMemoryLevel = Stream.DefaultMemoryLevel,
+  compressStrategy    = Stream.DefaultStrategy,
+  compressBufferSize  = defaultCompressBufferSize
+}
+
+-- | The default set of parameters for decompression. This is typically used with
+-- the @compressWith@ function with specific paramaters overridden.
+--
+defaultDecompressParams :: DecompressParams
+defaultDecompressParams = DecompressParams {
+  decompressWindowBits = Stream.DefaultWindowBits,
+  decompressBufferSize = defaultDecompressBufferSize
+}
+
+-- | The default chunk sizes for the output of compression and decompression
+-- are 16k and 32k respectively (less a small accounting overhead).
+--
+defaultCompressBufferSize, defaultDecompressBufferSize :: Int
+#ifdef BYTESTRING_IN_BASE
+defaultCompressBufferSize   = 16 * 1024 - 16
+defaultDecompressBufferSize = 32 * 1024 - 16
+#else
+defaultCompressBufferSize   = 16 * 1024 - L.chunkOverhead
+defaultDecompressBufferSize = 32 * 1024 - L.chunkOverhead
+#endif
+
+{-# NOINLINE compress #-}
+compress
   :: Stream.Format
-  -> Stream.CompressionLevel
-  -> Stream.Method
-  -> Stream.WindowBits
-  -> Stream.MemoryLevel
-  -> Stream.CompressionStrategy
+  -> CompressParams
   -> L.ByteString
   -> L.ByteString
-compressFull format compLevel method bits memLevel strategy input =
+compress format
+  (CompressParams compLevel method bits memLevel strategy initChunkSize)
+  input =
   L.fromChunks $ Stream.run $ do
     Stream.deflateInit format compLevel method bits memLevel strategy
     case L.toChunks input of
-      [] -> fillBuffers []
+      [] -> fillBuffers 20 [] --gzip header is 20 bytes, others even smaller
       S.PS inFPtr offset length : chunks -> do
         Stream.pushInputBuffer inFPtr offset length
-        fillBuffers chunks
+        fillBuffers initChunkSize chunks
 
   where
-  outChunkSize :: Int
-#ifdef BYTESTRING_IN_BASE
-  outChunkSize = 16 * 1024 - 16
-#else
-  outChunkSize = 16 * 1024 - L.chunkOverhead
-#endif
-
     -- we flick between two states:
     --   * where one or other buffer is empty
     --       - in which case we refill one or both
     --   * where both buffers are non-empty
     --       - in which case we compress until a buffer is empty
 
-  fillBuffers ::
-      [S.ByteString]
-   -> Stream [S.ByteString]
-  fillBuffers inChunks = do
+  fillBuffers :: Int
+              -> [S.ByteString]
+              -> Stream [S.ByteString]
+  fillBuffers outChunkSize inChunks = do
     Stream.consistencyCheck
 
     -- in this state there are two possabilities:
@@ -145,9 +196,10 @@
         outputBufferFull <- Stream.outputBufferFull
         if outputBufferFull
           then do (outFPtr, offset, length) <- Stream.popOutputBuffer
-                  outChunks <- Stream.unsafeInterleave (fillBuffers inChunks)
+                  outChunks <- Stream.unsafeInterleave
+                    (fillBuffers defaultCompressBufferSize inChunks)
                   return (S.PS outFPtr offset length : outChunks)
-          else do fillBuffers inChunks
+          else do fillBuffers defaultCompressBufferSize inChunks
 
       Stream.StreamEnd -> do
         inputBufferEmpty <- Stream.inputBufferEmpty
@@ -163,39 +215,32 @@
       Stream.NeedDict    -> fail "NeedDict is impossible!"
 
 
-{-# NOINLINE decompressFull #-}
-decompressFull
+{-# NOINLINE decompress #-}
+decompress
   :: Stream.Format
-  -> Stream.WindowBits
+  -> DecompressParams
   -> L.ByteString
   -> L.ByteString
-decompressFull format bits input =
+decompress format (DecompressParams bits initChunkSize) input =
   L.fromChunks $ Stream.run $ do
     Stream.inflateInit format bits
     case L.toChunks input of
-      [] -> fillBuffers []
+      [] -> fillBuffers 4 [] --always an error anyway
       S.PS inFPtr offset length : chunks -> do
         Stream.pushInputBuffer inFPtr offset length
-        fillBuffers chunks
+        fillBuffers initChunkSize chunks
 
   where
-  outChunkSize :: Int
-#ifdef BYTESTRING_IN_BASE
-  outChunkSize = 32 * 1024 - 16
-#else
-  outChunkSize = 32 * 1024 - L.chunkOverhead
-#endif
-
     -- we flick between two states:
     --   * where one or other buffer is empty
     --       - in which case we refill one or both
     --   * where both buffers are non-empty
     --       - in which case we compress until a buffer is empty
 
-  fillBuffers ::
-      [S.ByteString]
-   -> Stream [S.ByteString]
-  fillBuffers inChunks = do
+  fillBuffers :: Int
+              -> [S.ByteString]
+              -> Stream [S.ByteString]
+  fillBuffers outChunkSize inChunks = do
 
     -- in this state there are two possabilities:
     --   * no outbut buffer space is available
@@ -239,9 +284,10 @@
         outputBufferFull <- Stream.outputBufferFull
         if outputBufferFull
           then do (outFPtr, offset, length) <- Stream.popOutputBuffer
-                  outChunks <- Stream.unsafeInterleave (fillBuffers inChunks)
+                  outChunks <- Stream.unsafeInterleave
+                    (fillBuffers defaultDecompressBufferSize inChunks)
                   return (S.PS outFPtr offset length : outChunks)
-          else do fillBuffers inChunks
+          else do fillBuffers defaultDecompressBufferSize inChunks
 
       Stream.StreamEnd -> do
         -- Note that there may be input bytes still available if the stream
diff --git a/Codec/Compression/Zlib/Raw.hs b/Codec/Compression/Zlib/Raw.hs
--- a/Codec/Compression/Zlib/Raw.hs
+++ b/Codec/Compression/Zlib/Raw.hs
@@ -1,10 +1,10 @@
 -----------------------------------------------------------------------------
 -- |
--- Copyright   :  (c) 2006 Duncan Coutts
+-- Copyright   :  (c) 2006-2008 Duncan Coutts
 -- License     :  BSD-style
 --
--- Maintainer  :  duncan.coutts@worc.ox.ac.uk
--- Stability   :  experimental
+-- Maintainer  :  duncan@haskell.org
+-- Stability   :  provisional
 -- Portability :  portable (H98 + FFI)
 --
 -- Compression and decompression of data streams in the raw deflate format.
@@ -17,25 +17,39 @@
 -----------------------------------------------------------------------------
 module Codec.Compression.Zlib.Raw (
   
-  -- * Compression
+  -- * Simple compression and decompression
   compress,
+  decompress,
+
+  -- * Extended api with control over compression parameters
   compressWith,
+  decompressWith,
+
+  CompressParams(..), defaultCompressParams,
+  DecompressParams(..), defaultDecompressParams,
+
+  -- ** The compression parameter types
   CompressionLevel(..),
-  
-  -- * Decompression
-  decompress
-  
+  Method(..),
+  WindowBits(..),
+  MemoryLevel(..),
+  CompressionStrategy(..),
+
   ) where
 
 import Data.ByteString.Lazy (ByteString)
 
-import Codec.Compression.Zlib.Internal as Internal
+import qualified Codec.Compression.Zlib.Internal as Internal
+import Codec.Compression.Zlib.Internal hiding (compress, decompress)
 
 decompress :: ByteString -> ByteString
-decompress = Internal.decompressDefault Raw
+decompress = Internal.decompress Raw defaultDecompressParams
 
+decompressWith :: DecompressParams -> ByteString -> ByteString
+decompressWith = Internal.decompress Raw
+
 compress :: ByteString -> ByteString
-compress = Internal.compressDefault Raw DefaultCompression
+compress = Internal.compress Raw defaultCompressParams
 
-compressWith ::CompressionLevel -> ByteString -> ByteString
-compressWith = Internal.compressDefault Raw
+compressWith :: CompressParams -> ByteString -> ByteString
+compressWith = Internal.compress Raw
diff --git a/Codec/Compression/Zlib/Stream.hsc b/Codec/Compression/Zlib/Stream.hsc
--- a/Codec/Compression/Zlib/Stream.hsc
+++ b/Codec/Compression/Zlib/Stream.hsc
@@ -1,11 +1,11 @@
-{-# OPTIONS_GHC -fno-warn-missing-methods #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 -----------------------------------------------------------------------------
 -- |
 -- Copyright   :  (c) 2006-2008 Duncan Coutts
 -- License     :  BSD-style
 --
--- Maintainer  :  duncan.coutts@worc.ox.ac.uk
--- Stability   :  experimental
+-- Maintainer  :  duncan@haskell.org
+-- Stability   :  provisional
 -- Portability :  portable (H98 + FFI)
 --
 -- Zlib wrapper layer
@@ -58,11 +58,16 @@
   ) where
 
 import Foreign
+         ( Word8, Ptr, nullPtr, plusPtr, peekByteOff, pokeByteOff, mallocBytes
+         , ForeignPtr, FinalizerPtr, newForeignPtr_, addForeignPtrFinalizer
+	 , finalizeForeignPtr, withForeignPtr, touchForeignPtr
+	 , unsafeForeignPtrToPtr, unsafePerformIO )
 import Foreign.C
+         ( CInt, CUInt, CChar, CString, withCAString, peekCAString )
 #ifdef BYTESTRING_IN_BASE
-import Data.ByteString.Base
+import Data.ByteString.Base (nullForeignPtr)
 #else
-import Data.ByteString.Internal
+import Data.ByteString.Internal (nullForeignPtr)
 #endif
 import System.IO.Unsafe (unsafeInterleaveIO)
 import System.IO (hPutStrLn, stderr)
@@ -370,12 +375,12 @@
                 --   'BuferError' is not fatal, and 'inflate' can be called
                 --   again with more input and more output space to continue.
 
-instance Enum Status where
-  toEnum (#{const Z_OK})         = Ok
-  toEnum (#{const Z_STREAM_END}) = StreamEnd
-  toEnum (#{const Z_NEED_DICT})  = NeedDict
-  toEnum (#{const Z_BUF_ERROR})  = BufferError
-  toEnum other = error ("unexpected zlib status: " ++ show other)
+toStatus :: CInt -> Status
+toStatus (#{const Z_OK})         = Ok
+toStatus (#{const Z_STREAM_END}) = StreamEnd
+toStatus (#{const Z_NEED_DICT})  = NeedDict
+toStatus (#{const Z_BUF_ERROR})  = BufferError
+toStatus other = error ("unexpected zlib status: " ++ show other)
 
 failIfError :: CInt -> Stream ()
 failIfError errno
@@ -387,7 +392,7 @@
 getErrorMessage errno = do
   msgPtr <- withStreamPtr (#{peek z_stream, msg})
   if msgPtr /= nullPtr
-    then unsafeLiftIO (peekCString msgPtr)
+    then unsafeLiftIO (peekCAString msgPtr)
     else return $ case errno of
       #{const Z_ERRNO}         -> "file error"
       #{const Z_STREAM_ERROR}  -> "stream error"
@@ -403,54 +408,89 @@
   | Finish
 --  | Block -- only available in zlib 1.2 and later, uncomment if you need it.
 
-instance Enum Flush where
-  fromEnum NoFlush   = #{const Z_NO_FLUSH}
-  fromEnum SyncFlush = #{const Z_SYNC_FLUSH}
-  fromEnum FullFlush = #{const Z_FULL_FLUSH}
-  fromEnum Finish    = #{const Z_FINISH}
---  fromEnum Block     = #{const Z_BLOCK}
+fromFlush :: Flush -> CInt
+fromFlush NoFlush   = #{const Z_NO_FLUSH}
+fromFlush SyncFlush = #{const Z_SYNC_FLUSH}
+fromFlush FullFlush = #{const Z_FULL_FLUSH}
+fromFlush Finish    = #{const Z_FINISH}
+--  fromFlush Block     = #{const Z_BLOCK}
 
+-- | The format used for compression or decompression. There are three
+-- variations.
+--
 data Format =
-    GZip       -- ^ Encode or decode with the gzip header format.
-  | Zlib       -- ^ Encode or decode with the zlib header format.
-  | Raw        -- ^ Encode or decode a raw data stream without any header.
-  | GZipOrZlib -- ^ Enable zlib or gzip decoding with automatic header
-               --   detection. This only makes sense for decompression.
+    GZip -- ^ The gzip format uses a header with a checksum and some optional
+         -- meta-data about the compressed file. It is intended primarily for
+         -- compressing individual files but is also sometimes used for network
+         -- protocols such as HTTP. The format is described in detail in RFC
+         -- #1952 <http://www.ietf.org/rfc/rfc1952.txt>
 
+  | Zlib -- | The zlib format uses a minimal header with a checksum but no
+         -- other meta-data. It is especially designed for use in network
+         -- protocols. The format is described in detail in RFC #1950
+         -- <http://www.ietf.org/rfc/rfc1950.txt>
+
+  | Raw  -- | The \'raw\' format is just the compressed data stream without any
+         -- additional header, meta-data or data-integrity checksum. The format
+         -- is described in detail in RFC #1951
+         -- <http://www.ietf.org/rfc/rfc1951.txt>
+
+  | GZipOrZlib -- ^ This is not a format as such. It enabled zlib or gzip
+               -- decoding with automatic header detection. This only makes
+               -- sense for decompression.
+  deriving Eq
+
 -- | The compression method
-data Method = Deflated -- ^ \'Deflate\' is the only one supported in this
-                       -- version of zlib.
+--
+data Method = Deflated -- ^ \'Deflate\' is the only method supported in this
+                       -- version of zlib. Indeed it is likely to be the only
+                       -- method that ever will be supported.
 
-instance Enum Method where
-  fromEnum Deflated = #{const Z_DEFLATED}
+fromMethod :: Method -> CInt
+fromMethod Deflated = #{const Z_DEFLATED}
 
--- | Control amount of compression. This is a trade-off between the amount
--- of compression and the time and memory required to do the compression.
+-- | The compression level parameter controls the amount of compression. This
+-- is a trade-off between the amount of compression and the time required to do
+-- the compression.
+--
 data CompressionLevel = 
     DefaultCompression   -- ^ The default compression level is 6 (that is, 
-                         --   biased towards high compression at expense of speed).
+                         --   biased towards higher compression at expense of
+			 -- speed).
   | NoCompression        -- ^ No compression, just a block copy.
   | BestSpeed            -- ^ The fastest compression method (less compression) 
   | BestCompression      -- ^ The slowest compression method (best compression).
   | CompressionLevel Int -- ^ A specific compression level between 1 and 9.
 
-instance Enum CompressionLevel where
-  fromEnum DefaultCompression = -1
-  fromEnum NoCompression      = 0
-  fromEnum BestSpeed          = 1
-  fromEnum BestCompression    = 9
-  fromEnum (CompressionLevel n)
-           | n >= 1 && n <= 9 = n
+fromCompressionLevel :: CompressionLevel -> CInt
+fromCompressionLevel DefaultCompression   = -1
+fromCompressionLevel NoCompression        = 0
+fromCompressionLevel BestSpeed            = 1
+fromCompressionLevel BestCompression      = 9
+fromCompressionLevel (CompressionLevel n)
+           | n >= 1 && n <= 9 = fromIntegral n
            | otherwise        = error "CompressLevel must be in the range 1..9"
 
+-- | This specifies the size of the compression window. Larger values of this
+-- parameter result in better compression at the expense of higher memory
+-- usage.
+--
+-- The compression window size is the value of the the window bits raised to
+-- the power 2. The window bits must be in the range @8..15@ which corresponds
+-- to compression window sizes of 256b to 32Kb. The default is 15 which is also
+-- the maximum size.
+--
+-- The total amount of memory used depends on the window bits and the
+-- 'MemoryLevel'. See the 'MemoryLevel' for the details.
+--
 data WindowBits = DefaultWindowBits
                 | WindowBits Int
 
-windowBits :: Format -> WindowBits-> Int
+windowBits :: Format -> WindowBits-> CInt
 windowBits format bits = (formatModifier format) (checkWindowBits bits)
   where checkWindowBits DefaultWindowBits = 15
         checkWindowBits (WindowBits n)
-          | n >= 8 && n <= 15 = n
+          | n >= 8 && n <= 15 = fromIntegral n
           | otherwise         = error "WindowBits must be in the range 8..15"
         formatModifier Zlib       = id
         formatModifier GZip       = (+16)
@@ -458,23 +498,41 @@
         formatModifier Raw        = negate
 
 -- | The 'MemoryLevel' parameter specifies how much memory should be allocated
--- for the internal compression state.
+-- for the internal compression state. It is a tradoff between memory usage,
+-- compression ratio and compression speed. Using more memory allows faster
+-- compression and a better compression ratio.
 --
+-- The total amount of memory used for compression depends on the 'WindowBits'
+-- and the 'MemoryLevel'. For decompression it depends only on the
+-- 'WindowBits'. The totals are given by the functions:
+--
+-- > compressTotal windowBits memLevel = 4 * 2^windowBits + 512 * 2^memLevel
+-- > decompressTotal windowBits = 2^windowBits
+--
+-- For example, for compression with the default @windowBits = 15@ and
+-- @memLevel = 8@ uses @256Kb@. So for example a network server with 100
+-- concurrent compressed streams would use @25Mb@. The memory per stream can be
+-- halved (at the cost of somewhat degraded and slower compressionby) by
+-- reducing the @windowBits@ and @memLevel@ by one.
+--
+-- Decompression takes less memory, the default @windowBits = 15@ corresponds
+-- to just @32Kb@.
+--
 data MemoryLevel =
     DefaultMemoryLevel -- ^ The default. (Equivalent to @'MemoryLevel' 8@)
   | MinMemoryLevel     -- ^ Use minimum memory. This is slow and reduces the
                        --   compression ratio. (Equivalent to @'MemoryLevel' 1@)
   | MaxMemoryLevel     -- ^ Use maximum memory for optimal compression speed.
                        --   (Equivalent to @'MemoryLevel' 9@)
-  | MemoryLevel Int    -- ^ Use a specific level in the range 1..9
+  | MemoryLevel Int    -- ^ Use a specific level in the range @1..9@
 
-instance Enum MemoryLevel where
-  fromEnum DefaultMemoryLevel = 8
-  fromEnum MinMemoryLevel     = 1
-  fromEnum MaxMemoryLevel     = 9
-  fromEnum (MemoryLevel n)
-           | n >= 1 && n <= 9 = n
-           | otherwise        = error "MemoryLevel must be in the range 1..9"
+fromMemoryLevel :: MemoryLevel -> CInt
+fromMemoryLevel DefaultMemoryLevel = 8
+fromMemoryLevel MinMemoryLevel     = 1
+fromMemoryLevel MaxMemoryLevel     = 9
+fromMemoryLevel (MemoryLevel n)
+         | n >= 1 && n <= 9 = fromIntegral n
+         | otherwise        = error "MemoryLevel must be in the range 1..9"
 
 
 -- | The strategy parameter is used to tune the compression algorithm.
@@ -505,12 +563,12 @@
                     --   allowing for a simpler decoder for special applications.
 -}
 
-instance Enum CompressionStrategy where
-  fromEnum DefaultStrategy = #{const Z_DEFAULT_STRATEGY}
-  fromEnum Filtered        = #{const Z_FILTERED}
-  fromEnum HuffmanOnly     = #{const Z_HUFFMAN_ONLY}
---  fromEnum RLE             = #{const Z_RLE}
---  fromEnum Fixed           = #{const Z_FIXED}
+fromCompressionStrategy :: CompressionStrategy -> CInt
+fromCompressionStrategy DefaultStrategy = #{const Z_DEFAULT_STRATEGY}
+fromCompressionStrategy Filtered        = #{const Z_FILTERED}
+fromCompressionStrategy HuffmanOnly     = #{const Z_HUFFMAN_ONLY}
+--fromCompressionStrategy RLE             = #{const Z_RLE}
+--fromCompressionStrategy Fixed           = #{const Z_FIXED}
 
 withStreamPtr :: (Ptr StreamState -> IO a) -> Stream a
 withStreamPtr f = do
@@ -552,6 +610,7 @@
 
 inflateInit :: Format -> WindowBits -> Stream ()
 inflateInit format bits = do
+  checkFormatSupported format
   err <- withStreamState $ \zstream ->
     c_inflateInit2 zstream (fromIntegral (windowBits format bits))
   failIfError err
@@ -565,29 +624,30 @@
             -> CompressionStrategy
             -> Stream ()
 deflateInit format compLevel method bits memLevel strategy = do
+  checkFormatSupported format
   err <- withStreamState $ \zstream ->
     c_deflateInit2 zstream
-                  (fromIntegral (fromEnum compLevel))
-                  (fromIntegral (fromEnum method))
-                  (fromIntegral (windowBits format bits))
-                  (fromIntegral (fromEnum memLevel))
-                  (fromIntegral (fromEnum strategy))
+                  (fromCompressionLevel compLevel)
+                  (fromMethod method)
+                  (windowBits format bits)
+                  (fromMemoryLevel memLevel)
+                  (fromCompressionStrategy strategy)
   failIfError err
   getStreamState >>= unsafeLiftIO . addForeignPtrFinalizer c_deflateEnd
 
 inflate_ :: Flush -> Stream Status
 inflate_ flush = do
   err <- withStreamState $ \zstream ->
-    c_inflate zstream (fromIntegral (fromEnum flush))
+    c_inflate zstream (fromFlush flush)
   failIfError err
-  return (toEnum (fromIntegral err))
+  return (toStatus err)
 
 deflate_ :: Flush -> Stream Status
 deflate_ flush = do
   err <- withStreamState $ \zstream ->
-    c_deflate zstream (fromIntegral (fromEnum flush))
+    c_deflate zstream (fromFlush flush)
   failIfError err
-  return (toEnum (fromIntegral err))
+  return (toStatus err)
 
 -- | This never needs to be used as the stream's resources will be released
 -- automatically when no longer needed, however this can be used to release
@@ -597,6 +657,18 @@
 finalise :: Stream ()
 finalise = getStreamState >>= unsafeLiftIO . finalizeForeignPtr
 
+checkFormatSupported :: Format -> Stream ()
+checkFormatSupported format = do
+  version <- unsafeLiftIO (peekCAString =<< c_zlibVersion)
+  case version of
+    ('1':'.':'1':'.':_)
+       | format == GZip
+      || format == GZipOrZlib
+      -> fail $ "version 1.1.x of the zlib C library does not support the"
+             ++ " 'gzip' format via the in-memory api, only the 'raw' and "
+	     ++ " 'zlib' formats."
+    _ -> return ()
+
 ----------------------
 -- The foreign imports
 
@@ -621,7 +693,7 @@
 
 c_inflateInit2 :: StreamState -> CInt -> IO CInt
 c_inflateInit2 z n =
-  withCString #{const_str ZLIB_VERSION} $ \versionStr ->
+  withCAString #{const_str ZLIB_VERSION} $ \versionStr ->
     c_inflateInit2_ z n versionStr (#{const sizeof(z_stream)} :: CInt)
 
 foreign import ccall unsafe "zlib.h inflate"
@@ -640,7 +712,7 @@
 c_deflateInit2 :: StreamState
                -> CInt -> CInt -> CInt -> CInt -> CInt -> IO CInt
 c_deflateInit2 z a b c d e =
-  withCString #{const_str ZLIB_VERSION} $ \versionStr ->
+  withCAString #{const_str ZLIB_VERSION} $ \versionStr ->
     c_deflateInit2_ z a b c d e versionStr (#{const sizeof(z_stream)} :: CInt)
 
 foreign import ccall unsafe "zlib.h deflate"
@@ -648,3 +720,6 @@
 
 foreign import ccall unsafe "zlib.h &deflateEnd"
   c_deflateEnd :: FinalizerPtr StreamState
+
+foreign import ccall unsafe "zlib.h zlibVersion"
+  c_zlibVersion :: IO CString
diff --git a/zlib.cabal b/zlib.cabal
--- a/zlib.cabal
+++ b/zlib.cabal
@@ -1,5 +1,5 @@
 name:            zlib
-version:         0.4.0.4
+version:         0.5.0.0
 copyright:       (c) 2006-2008 Duncan Coutts
 license:         BSD3
 license-file:    LICENSE
@@ -36,6 +36,7 @@
                    Codec.Compression.Zlib.Internal
   other-modules:   Codec.Compression.Zlib.Stream
   extensions:      CPP, ForeignFunctionInterface
+  build-depends: base < 5
   if flag(bytestring-in-base)
     -- bytestring was in base-2.0 and 2.1.1
     build-depends: base >= 2.0 && < 2.2
