11{-# LANGUAGE CPP, RankNTypes, BangPatterns #-}
22{-# LANGUAGE DeriveGeneric #-}
33{-# LANGUAGE Trustworthy #-}
4+ {-# LANGUAGE LambdaCase #-}
5+ {-# LANGUAGE ScopedTypeVariables #-}
46-----------------------------------------------------------------------------
57-- |
68-- Copyright : (c) 2006-2015 Duncan Coutts
@@ -15,7 +17,9 @@ module Codec.Compression.Zlib.Internal (
1517
1618 -- * Pure interface
1719 compress ,
20+ compressFromHandle ,
1821 decompress ,
22+ decompressFromHandle ,
1923
2024 -- * Monadic incremental interface
2125 -- $incremental-compression
@@ -76,7 +80,7 @@ module Codec.Compression.Zlib.Internal (
7680
7781import Prelude hiding (length )
7882import Control.Monad (when )
79- import Control.Exception (Exception , throw , assert )
83+ import Control.Exception (Exception , throw , assert , throwIO )
8084import Control.Monad.ST.Lazy hiding (stToIO )
8185import Control.Monad.ST.Strict (stToIO )
8286import qualified Control.Monad.ST.Unsafe as Unsafe (unsafeIOToST )
@@ -94,6 +98,8 @@ import GHC.IO (noDuplicate)
9498import qualified Codec.Compression.Zlib.Stream as Stream
9599import Codec.Compression.Zlib.ByteStringCompat (mkBS , withBS )
96100import Codec.Compression.Zlib.Stream (Stream )
101+ import System.IO (Handle , hIsSeekable , hSeek , SeekMode (.. ))
102+ import Data.ByteString.Builder.Extra (defaultChunkSize )
97103
98104-- | The full set of parameters for compression. The defaults are
99105-- 'defaultCompressParams'.
@@ -483,6 +489,26 @@ compress format params = foldCompressStreamWithInput
483489compressST format params = compressStreamST format params
484490compressIO format params = compressStreamIO format params
485491
492+ compressFromHandle
493+ :: forall acc .
494+ Stream. Format
495+ -> CompressParams
496+ -> Handle
497+ -> (acc -> S. ByteString -> IO acc ) -- TODO add early exit?
498+ -> acc
499+ -> IO acc
500+ compressFromHandle format params hndl cons nil = go nil (compressStreamIO format params)
501+ where
502+ go :: acc -> CompressStream IO -> IO acc
503+ go ! acc = \ case
504+ CompressInputRequired next ->
505+ S. hGetSome hndl defaultChunkSize >>= next >>= go acc
506+ CompressOutputAvailable outchunk next -> do
507+ acc' <- acc `cons` outchunk
508+ next >>= go acc'
509+ CompressStreamEnd ->
510+ pure acc
511+
486512-- | Chunk size must fit into t'CUInt'.
487513compressStream :: Stream. Format -> CompressParams -> S. ByteString
488514 -> Stream (CompressStream Stream )
@@ -617,6 +643,33 @@ decompress format params = foldDecompressStreamWithInput
617643decompressST format params = decompressStreamST format params
618644decompressIO format params = decompressStreamIO format params
619645
646+ decompressFromHandle
647+ :: forall acc .
648+ Stream. Format
649+ -> DecompressParams
650+ -> Handle
651+ -> (acc -> S. ByteString -> IO acc ) -- TODO add early exit?
652+ -> acc
653+ -> IO (acc , S. ByteString )
654+ decompressFromHandle format params hndl cons nil = go nil (decompressStreamIO format params)
655+ where
656+ go :: acc -> DecompressStream IO -> IO (acc , S. ByteString )
657+ go ! acc = \ case
658+ DecompressInputRequired next ->
659+ S. hGetSome hndl defaultChunkSize >>= next >>= go acc
660+ DecompressOutputAvailable outchunk next -> do
661+ acc' <- acc `cons` outchunk
662+ next >>= go acc'
663+ DecompressStreamEnd unconsumed -> do
664+ isHndlSeekable <- hIsSeekable hndl
665+ if isHndlSeekable then do
666+ hSeek hndl RelativeSeek (negate $ toInteger $ S. length unconsumed)
667+ pure (acc, mempty )
668+ else
669+ pure (acc, unconsumed)
670+ DecompressStreamError err ->
671+ throwIO err
672+
620673-- | Chunk size must fit into t'CUInt'.
621674decompressStream :: Stream. Format -> DecompressParams
622675 -> Bool -> S. ByteString
0 commit comments