zlib 0.4.0.4 → 0.5.0.0
raw patch · 6 files changed
+406/−182 lines, 6 filesdep ~base
Dependency ranges changed: base
Files
- Codec/Compression/GZip.hs +46/−20
- Codec/Compression/Zlib.hs +74/−12
- Codec/Compression/Zlib/Internal.hs +117/−71
- Codec/Compression/Zlib/Raw.hs +27/−13
- Codec/Compression/Zlib/Stream.hsc +140/−65
- zlib.cabal +2/−1
Codec/Compression/GZip.hs view
@@ -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
Codec/Compression/Zlib.hs view
@@ -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
Codec/Compression/Zlib/Internal.hs view
@@ -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
Codec/Compression/Zlib/Raw.hs view
@@ -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
Codec/Compression/Zlib/Stream.hsc view
@@ -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
zlib.cabal view
@@ -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