Skip to content

Commit eb56899

Browse files
committed
Add compressFromHandle / decompressFromHandle
1 parent 7c7a3ed commit eb56899

File tree

1 file changed

+54
-1
lines changed

1 file changed

+54
-1
lines changed

zlib/Codec/Compression/Zlib/Internal.hs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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

7781
import Prelude hiding (length)
7882
import Control.Monad (when)
79-
import Control.Exception (Exception, throw, assert)
83+
import Control.Exception (Exception, throw, assert, throwIO)
8084
import Control.Monad.ST.Lazy hiding (stToIO)
8185
import Control.Monad.ST.Strict (stToIO)
8286
import qualified Control.Monad.ST.Unsafe as Unsafe (unsafeIOToST)
@@ -94,6 +98,8 @@ import GHC.IO (noDuplicate)
9498
import qualified Codec.Compression.Zlib.Stream as Stream
9599
import Codec.Compression.Zlib.ByteStringCompat (mkBS, withBS)
96100
import 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
483489
compressST format params = compressStreamST format params
484490
compressIO 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'.
487513
compressStream :: Stream.Format -> CompressParams -> S.ByteString
488514
-> Stream (CompressStream Stream)
@@ -617,6 +643,33 @@ decompress format params = foldDecompressStreamWithInput
617643
decompressST format params = decompressStreamST format params
618644
decompressIO 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'.
621674
decompressStream :: Stream.Format -> DecompressParams
622675
-> Bool -> S.ByteString

0 commit comments

Comments
 (0)