{-# LANGUAGE RankNTypes #-} -- | This module exports utilities to compress and decompress @pipes@ streams -- using the zlib compression codec. module Pipes.Zlib ( -- * Streams decompress , compress -- * Compression level -- $ccz-re-export , ZC.defaultCompression , ZC.noCompression , ZC.bestSpeed , ZC.bestCompression , ZC.compressionLevel -- * Window size -- $ccz-re-export , ZC.defaultWindowBits , ZC.windowBits ) where import qualified Codec.Compression.Zlib as ZC import qualified Codec.Zlib as Z import Control.Monad (unless) import qualified Data.ByteString as B import Pipes -------------------------------------------------------------------------------- -- | Decompress bytes flowing from a 'Producer'. -- -- See the "Codec.Compression.Zlib" module for details about 'Z.WindowBits'. decompress :: MonadIO m => ZC.WindowBits -> Producer' B.ByteString m r -- ^ Compressed stream -> Producer' B.ByteString m r -- ^ Decompressed stream decompress wbits p0 = do inf <- liftIO $ Z.initInflate wbits r <- for p0 $ \bs -> do popper <- liftIO (Z.feedInflate inf bs) fromPopper popper bs <- liftIO $ Z.finishInflate inf unless (B.null bs) (yield bs) return r {-# INLINABLE decompress #-} -- | Compress bytes flowing from a 'Producer'. -- -- See the "Codec.Compression.Zlib" module for details about -- 'ZC.CompressionLevel' and 'ZC.WindowBits'. compress :: MonadIO m => ZC.CompressionLevel -> ZC.WindowBits -> Producer' B.ByteString m r -- ^ Decompressed stream -> Producer' B.ByteString m r -- ^ Compressed stream compress clevel wbits p0 = do def <- liftIO $ Z.initDeflate (fromCompressionLevel clevel) wbits r <- for p0 $ \bs -> do popper <- liftIO (Z.feedDeflate def bs) fromPopper popper mbs <- liftIO $ Z.finishDeflate def case mbs of Just bs -> yield bs Nothing -> return () return r {-# INLINABLE compress #-} -------------------------------------------------------------------------------- -- $ccz-re-export -- -- The following are re-exported from "Codec.Compression.Zlib" for your -- convenience. -------------------------------------------------------------------------------- -- Internal stuff -- | Produce values from the given 'Z.Popper' until exhausted. fromPopper :: MonadIO m => Z.Popper -> Producer' B.ByteString m () fromPopper pop = loop where loop = do mbs <- liftIO pop case mbs of Nothing -> return () Just bs -> yield bs >> loop {-# INLINABLE fromPopper #-} -- We need this function until the @zlib@ library hides the -- 'ZC.CompressionLevel' constructors in future version 0.7. fromCompressionLevel :: ZC.CompressionLevel -> Int fromCompressionLevel level = case level of ZC.DefaultCompression -> -1 ZC.NoCompression -> 0 ZC.BestSpeed -> 1 ZC.BestCompression -> 9 ZC.CompressionLevel n | n >= 0 && n <= 9 -> fromIntegral n _ -> error "CompressLevel must be in the range 1..9"