iteratee-compress 0.1 → 0.1.1
raw patch · 2 files changed
+240/−30 lines, 2 filesdep −zlibPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: zlib
API changes (from Hackage documentation)
+ Data.Iteratee.ZLib: BestCompression :: CompressionLevel
+ Data.Iteratee.ZLib: BestSpeed :: CompressionLevel
+ Data.Iteratee.ZLib: CompressionLevel :: Int -> CompressionLevel
+ Data.Iteratee.ZLib: DefaultCompression :: CompressionLevel
+ Data.Iteratee.ZLib: DefaultMemoryLevel :: MemoryLevel
+ Data.Iteratee.ZLib: DefaultStrategy :: CompressionStrategy
+ Data.Iteratee.ZLib: DefaultWindowBits :: WindowBits
+ Data.Iteratee.ZLib: Deflated :: Method
+ Data.Iteratee.ZLib: Filtered :: CompressionStrategy
+ Data.Iteratee.ZLib: HuffmanOnly :: CompressionStrategy
+ Data.Iteratee.ZLib: MaxMemoryLevel :: MemoryLevel
+ Data.Iteratee.ZLib: MemoryLevel :: Int -> MemoryLevel
+ Data.Iteratee.ZLib: MinMemoryLevel :: MemoryLevel
+ Data.Iteratee.ZLib: NoCompression :: CompressionLevel
+ Data.Iteratee.ZLib: WindowBits :: Int -> WindowBits
+ Data.Iteratee.ZLib: data CompressionLevel
+ Data.Iteratee.ZLib: data CompressionStrategy
+ Data.Iteratee.ZLib: data MemoryLevel
+ Data.Iteratee.ZLib: data Method
+ Data.Iteratee.ZLib: data WindowBits
+ Data.Iteratee.ZLib: defaultCompressParams :: CompressParams
+ Data.Iteratee.ZLib: defaultDecompressParams :: DecompressParams
+ Data.Iteratee.ZLib: instance Eq Format
+ Data.Iteratee.ZLib: instance Eq ZlibFlush
+ Data.Iteratee.ZLib: instance Exception ZlibFlush
+ Data.Iteratee.ZLib: instance Show ZlibFlush
+ Data.Iteratee.ZLib: instance Typeable ZlibFlush
- Data.Iteratee.ZLib: data CompressParams :: *
+ Data.Iteratee.ZLib: data CompressParams
- Data.Iteratee.ZLib: data DecompressParams :: *
+ Data.Iteratee.ZLib: data DecompressParams
- Data.Iteratee.ZLib: data Format :: *
+ Data.Iteratee.ZLib: data Format
- Data.Iteratee.ZLib: enumDeflate :: (MonadIO m) => Format -> CompressParams -> Enumerator ByteString m a
+ Data.Iteratee.ZLib: enumDeflate :: MonadIO m => Format -> CompressParams -> Enumerator ByteString m a
- Data.Iteratee.ZLib: enumInflate :: (MonadIO m) => Format -> DecompressParams -> Enumerator ByteString m a
+ Data.Iteratee.ZLib: enumInflate :: MonadIO m => Format -> DecompressParams -> Enumerator ByteString m a
Files
- Data/Iteratee/ZLib.hsc +238/−27
- iteratee-compress.cabal +2/−3
Data/Iteratee/ZLib.hsc view
@@ -3,19 +3,28 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ScopedTypeVariables #-} module Data.Iteratee.ZLib- ( + (+ -- * Enumerators+ enumInflate,+ enumDeflate,+ -- * Exceptions ZLibParamsException(..), ZLibException(..),+ -- * Parameters CompressParams(..),+ defaultCompressParams, DecompressParams(..),+ defaultDecompressParams, Format(..),- enumInflate,- enumDeflate,+ CompressionLevel(..),+ Method(..),+ WindowBits(..),+ MemoryLevel(..),+ CompressionStrategy(..), ) where #include <zlib.h> -import Codec.Compression.Zlib.Internal hiding (StreamError, DataError) import Control.Applicative import Control.Exception import Control.Monad.Trans@@ -47,14 +56,14 @@ = NeedDictionary -- ^ Decompression requires user-supplied dictionary (not supported) | BufferError- -- ^ Buffer error - denotes the library error+ -- ^ Buffer error - denotes a library error -- | File Error | StreamError -- ^ State of steam inconsistent | DataError -- ^ Input data corrupted | MemoryError- -- ^ Not enought memory+ -- ^ Not enough memory | VersionError -- ^ Version error | Unexpected !CInt@@ -63,17 +72,45 @@ -- ^ Incorrect state - denotes error in library deriving (Eq,Typeable) +-- | Denotes the flush that can be sent to stream+data ZlibFlush+ = SyncFlush+ -- ^ All pending output is flushed and all input that is available is sent+ -- to inner Iteratee.+ | FullFlush+ -- ^ Flush all pending output and reset the compression state. It allows to+ -- restart from this point if compression was damaged but it can seriously + -- affect the compression rate.+ --+ -- It may be only used during compression.+ | Block+ -- ^ If the iteratee is compressing it requests to stop when next block is+ -- emmited. On the beginning it skips only header if and only if it exists.+ deriving (Eq,Typeable)++instance Show ZlibFlush where+ show SyncFlush = "zlib: flush requested"+ show FullFlush = "zlib: full flush requested"+ show Block = "zlib: block flush requested"++instance Exception ZlibFlush++fromFlush :: ZlibFlush -> CInt+fromFlush SyncFlush = #{const Z_SYNC_FLUSH}+fromFlush FullFlush = #{const Z_FULL_FLUSH}+fromFlush Block = #{const Z_BLOCK}+ instance Show ZLibParamsException where show (IncorrectCompressionLevel lvl) = "zlib: incorrect compression level " ++ show lvl show (IncorrectWindowBits lvl) = "zlib: incorrect window bits " ++ show lvl show (IncorrectMemoryLevel lvl)- = "zlib: incorrect memory lvele " ++ show lvl+ = "zlib: incorrect memory level " ++ show lvl instance Show ZLibException where show NeedDictionary = "zlib: needs dictionary"- show BufferError = "zlib: no progress is possible (internall error)"+ show BufferError = "zlib: no progress is possible (internal error)" -- show FileError = "zlib: file I/O error" show StreamError = "zlib: stream error" show DataError = "zlib: data error"@@ -95,6 +132,137 @@ -- Following code is copied from Duncan Coutts zlib haskell library version -- 0.5.2.0 ((c) 2006-2008 Duncan Coutts, published on BSD licence) and adapted +-- | Set of parameters for compression. For sane defaults use+-- 'defaultCompressParams'+data CompressParams = CompressParams {+ compressLevel :: !CompressionLevel,+ compressMethod :: !Method,+ compressWindowBits :: !WindowBits,+ compressMemoryLevel :: !MemoryLevel,+ compressStrategy :: !CompressionStrategy,+ -- | The size of output buffer. That is the size of 'Chunk's that will be+ -- emitted to inner iterator (except the last 'Chunk').+ compressBufferSize :: !Int+ }++defaultCompressParams+ = CompressParams DefaultCompression Deflated DefaultWindowBits + DefaultMemoryLevel DefaultStrategy (8*1024)++-- | Set of parameters for decompression. For sane defaults see +-- 'defaultDecompressParams'.+data DecompressParams = DecompressParams {+ -- | Window size - it have to be at least the size of+ -- 'compressWindowBits' the stream was compressed with.+ --+ -- Default in 'defaultDecompressParams' is the maximum window size - + -- please do not touch it unless you know what you are doing.+ decompressWindowBits :: !WindowBits,+ -- | The size of output buffer. That is the size of 'Chunk's that will be+ -- emitted to inner iterator (except the last 'Chunk').+ decompressBufferSize :: !Int+ }++defaultDecompressParams = DecompressParams DefaultWindowBits (8*1024)++-- | Specify the format for compression and decompression+data Format+ = GZip+ -- ^ The gzip format is widely used and uses a header with checksum and+ -- some optional metadata about the compress file.+ --+ -- It is intended primarily for compressing individual files but is also+ -- used for network protocols such as HTTP.+ --+ -- The format is described in RFC 1952 + -- <http://www.ietf.org/rfc/rfc1952.txt>.+ | Zlib+ -- ^ The zlib format uses a minimal header with a checksum but no other+ -- metadata. It is designed for use in network protocols.+ --+ -- The format is described in RFC 1950+ -- <http://www.ietf.org/rfc/rfc1950.txt>+ | Raw+ -- ^ The \'raw\' format is just the DEFLATE compressed data stream without+ -- and additionl headers. + --+ -- Thr format is described in RFC 1951+ -- <http://www.ietf.org/rfc/rfc1951.txt>+ | GZipOrZlib+ -- ^ "Format" for decompressing a 'Zlib' or 'GZip' stream.+ deriving (Eq)++-- | The compression level specify the tradeoff between speed and compression.+data CompressionLevel+ = DefaultCompression+ -- ^ Default compression level set at 6.+ | NoCompression+ -- ^ No compression, just a block copy.+ | BestSpeed+ -- ^ The fastest compression method (however less compression)+ | BestCompression+ -- ^ The best compression method (however slowest)+ | CompressionLevel Int+ -- ^ Compression level set by number from 1 to 9++-- | Specify the compression method.+data Method+ = Deflated+ -- ^ \'Deflate\' is so far the only method supported. ++-- | This specify the size of compression level. Larger values result in better+-- compression at the expense of highier memory usage.+--+-- The compression window size is 2 to the power of the value of the window+-- bits. +--+-- The total memory used depends on windows bits and 'MemoryLevel'.+data WindowBits+ = WindowBits Int+ -- ^ The size of window bits. It have to be between @8@ (which corresponds+ -- to 256b i.e. 32B) and @15@ (which corresponds to 32 kib i.e. 4kiB).+ | DefaultWindowBits+ -- ^ The default window size which is 4kiB++-- | The 'MemoryLevel' specifies how much memory should be allocated for the+-- internal state. It is a tradeoff between memory usage, speed and+-- compression.+-- Using more memory allows faster and better compression.+--+-- The memory used for interal state, excluding 'WindowBits', is 512 bits times+-- 2 to power of memory level.+--+-- The total amount of memory use depends on the 'WindowBits' and+-- 'MemoryLevel'.+data MemoryLevel+ = DefaultMemoryLevel+ -- ^ Default memory level set to 8.+ | MinMemoryLevel+ -- ^ Use the small amount of memory (equivalent to memory level 1) - i.e.+ -- 1024b or 256 B.+ -- It slow and reduces the compresion ratio.+ | MaxMemoryLevel+ -- ^ Maximum memory level for optimal compression speed (equivalent to+ -- memory level 9).+ -- The internal state is 256kib or 32kiB.+ | MemoryLevel Int+ -- ^ A specific level. It have to be between 1 and 9. ++-- | Tunes the compress algorithm but does not affact the correctness.+data CompressionStrategy+ = DefaultStrategy+ -- ^ Default strategy+ | Filtered+ -- ^ Use the filtered compression strategy for data produced by a filter+ -- (or predictor). Filtered data consists mostly of small values with a+ -- somewhat random distribution. In this case, the compression algorithm+ -- is tuned to compress them better. The effect of this strategy is to+ -- force more Huffman coding and less string matching; it is somewhat+ -- intermediate between 'DefaultStrategy' and 'HuffmanOnly'.+ | HuffmanOnly+ -- ^ Use the Huffman-only compression strategy to force Huffman encoding+ -- only (no string match). + fromMethod :: Method -> CInt fromMethod Deflated = #{const Z_DEFLATED} @@ -158,22 +326,28 @@ r = Right in eit (\c_ -> eit (\b_ -> eit (\l_ -> r (c_, m', b_, l_, s')) l') b') c' ----- In following code we go through 6 states. Some of the operations are+-- In following code we go through 7 states. Some of the operations are -- 'deterministic' like 'insertOut' and some of them depends on input ('fill') -- or library call. ----- insertOut fill[1]--- (Initial) -------------> (EmptyIn) -----------> (Finishing)--- ^ ^ | |--- | run[2] | | |--- | run[1] | | |--- \------------------\ | | fill[0] | finish--- | | | |--- | | | |--- swapOut | | v v--- (FullOut) -------------> (Invalid) (Finished)--- <--------------- run[0]+-- (Finished)+-- ^+-- |+-- |+-- | finish+-- |+-- insertOut fill[1] |+--- (Initial) -------------> (EmptyIn) -----------> (Finishing)+-- ^ ^ | ^ |+-- | run[2] | | | \------------------\+-- | | | | |+-- | | | \------------------\ |+-- | run[1] | | flush[0] | |+-- \------------------\ | | fill[0] | | fill[3]+-- | | | | |+-- | | | | |+-- swapOut | | v flush[1] | v+-- (FullOut) -------------> (Invalid) <----------- (Flushing) -- -- Initial: Initial state, both buffers are empty -- EmptyIn: Empty in buffer, out waits untill filled@@ -182,7 +356,10 @@ -- Finishing: There is no more in data and in buffer is empty. Waits till -- all outs was sent. -- Finished: Operation finished+-- Flushing: Flush requested -- +-- Please note that the decompressing can finish also on flush and finish.+-- -- [1] Named for 'historical' reasons newtype Initial = Initial ZStream@@ -190,6 +367,7 @@ data FullOut = FullOut !ZStream !ByteString data Invalid = Invalid !ZStream !ByteString !ByteString data Finishing = Finishing !ZStream !ByteString+data Flushing = Flushing !ZStream !ZlibFlush !ByteString withByteString :: ByteString -> (Ptr Word8 -> Int -> IO a) -> IO a withByteString (PS ptr off len) f@@ -280,7 +458,11 @@ | otherwise = fillI fill' (EOF Nothing) = joinIM $ finish size run (Finishing zstr BS.empty) iter- fill' (EOF (Just err)) = throwRecoverableErr err fill'+ fill' (EOF (Just err))+ = case fromException err of+ Just err' ->+ joinIM $ flush size run (Flushing zstr err' _out) iter+ Nothing -> throwRecoverableErr err fill' #ifdef DEBUG fillI = do liftIO $ IO.hPutStrLn stderr $ "About to insert in buffer"@@ -342,6 +524,35 @@ 0 -> fill size run (EmptyIn zstr _out) iter _ -> enumErr IncorrectState iter +flush :: MonadIO m+ => Int+ -> (ZStream -> CInt -> IO CInt)+ -> Flushing+ -> Enumerator ByteString m a+flush size run fin@(Flushing zstr _flush _out) iter = return $! do+ status <- liftIO $ run zstr (fromFlush _flush)+ case fromErrno status of+ Left err -> joinIM $ enumErr err iter+ Right False -> do -- Finished+ out <- liftIO $ pullOutBuffer zstr _out+ iter' <- lift $ enumPure1Chunk out iter+ res <- lift $ tryRun iter'+ case res of+ Left err@(SomeException _) -> throwErr err+ Right x -> idone x (Chunk BS.empty)+ Right True -> do+ (avail_in, avail_out) <- liftIO $ withZStream zstr $ \zptr -> do+ avail_in <- liftIO $ #{peek z_stream, avail_in} zptr+ avail_out <- liftIO $ #{peek z_stream, avail_out} zptr+ return (avail_in, avail_out) :: IO (CInt, CInt)+ case avail_out of+ 0 -> do+ out <- liftIO $ pullOutBuffer zstr _out+ iter' <- lift $ enumPure1Chunk out iter+ out' <- liftIO $ putOutBuffer size zstr+ joinIM $ flush size run (Flushing zstr _flush out') iter'+ _ -> joinIM $ insertOut size run (Initial zstr) iter+ finish :: MonadIO m => Int -> (ZStream -> CInt -> IO CInt)@@ -426,8 +637,8 @@ zstr <- mallocForeignPtrBytes #{size z_stream} withForeignPtr zstr $ \zptr -> do memset (castPtr zptr) 0 #{size z_stream}- deflateInit2 zptr c m b l s- addForeignPtrFinalizer deflateEnd zstr+ deflateInit2 zptr c m b l s `finally`+ addForeignPtrFinalizer deflateEnd zstr return $! Right $! Initial $ ZStream zstr mkDecompress :: Format -> DecompressParams@@ -439,11 +650,11 @@ zstr <- mallocForeignPtrBytes #{size z_stream} withForeignPtr zstr $ \zptr -> do memset (castPtr zptr) 0 #{size z_stream}- inflateInit2 zptr wB'- addForeignPtrFinalizer inflateEnd zstr+ inflateInit2 zptr wB' `finally`+ addForeignPtrFinalizer inflateEnd zstr return $! Right $! Initial $ ZStream zstr --- User-releted code+-- User-related code -- | Compress the input and send to inner iteratee. enumDeflate :: MonadIO m
iteratee-compress.cabal view
@@ -1,5 +1,5 @@ Name: iteratee-compress-Version: 0.1+Version: 0.1.1 Synopsis: An enumerators for compressing and decompressing streams Description: An enumerators for compressing and decompressing streams License: BSD3@@ -21,8 +21,7 @@ Build-depends: base >= 4 && < 5, bytestring >= 0.9 && < 0.10, iteratee >= 0.4 && < 5,- monads-fd >= 0.1 && < 0.2,- zlib >= 0.5 && < 6+ monads-fd >= 0.1 && < 0.2 Build-tools: c2hs Extensions: CPP, DeriveDataTypeable,