{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module System.IO.Streams.Zlib
(
gunzip
, decompress
, gzip
, compress
, gzipBuilder
, compressBuilder
, CompressionLevel(..)
, defaultCompressionLevel
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as S
import Data.IORef (newIORef, readIORef, writeIORef)
import Prelude hiding (read)
import Codec.Zlib (Deflate, Inflate, Popper, WindowBits (..), feedDeflate, feedInflate, finishDeflate, finishInflate, flushDeflate, flushInflate, initDeflate, initInflate)
import Data.ByteString.Builder (Builder, byteString)
import Data.ByteString.Builder.Extra (defaultChunkSize, flush)
import Data.ByteString.Builder.Internal (newBuffer)
import System.IO.Streams.Builder (unsafeBuilderStream)
import System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, read, write)
gzipBits :: WindowBits
gzipBits :: WindowBits
gzipBits = Int -> WindowBits
WindowBits Int
31
compressBits :: WindowBits
compressBits :: WindowBits
compressBits = Int -> WindowBits
WindowBits Int
15
gunzip :: InputStream ByteString -> IO (InputStream ByteString)
gunzip :: InputStream ByteString -> IO (InputStream ByteString)
gunzip InputStream ByteString
input = WindowBits -> IO Inflate
initInflate WindowBits
gzipBits IO Inflate
-> (Inflate -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= InputStream ByteString -> Inflate -> IO (InputStream ByteString)
inflate InputStream ByteString
input
decompress :: InputStream ByteString -> IO (InputStream ByteString)
decompress :: InputStream ByteString -> IO (InputStream ByteString)
decompress InputStream ByteString
input = WindowBits -> IO Inflate
initInflate WindowBits
compressBits IO Inflate
-> (Inflate -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= InputStream ByteString -> Inflate -> IO (InputStream ByteString)
inflate InputStream ByteString
input
data IS = Input
| Popper Popper
| Done
inflate :: InputStream ByteString -> Inflate -> IO (InputStream ByteString)
inflate :: InputStream ByteString -> Inflate -> IO (InputStream ByteString)
inflate InputStream ByteString
input Inflate
state = do
IORef IS
ref <- IS -> IO (IORef IS)
forall a. a -> IO (IORef a)
newIORef IS
Input
IO (Maybe ByteString) -> IO (InputStream ByteString)
forall a. IO (Maybe a) -> IO (InputStream a)
makeInputStream (IO (Maybe ByteString) -> IO (InputStream ByteString))
-> IO (Maybe ByteString) -> IO (InputStream ByteString)
forall a b. (a -> b) -> a -> b
$ IORef IS -> IO (Maybe ByteString)
stream IORef IS
ref
where
stream :: IORef IS -> IO (Maybe ByteString)
stream IORef IS
ref = IO (Maybe ByteString)
go
where
go :: IO (Maybe ByteString)
go = IORef IS -> IO IS
forall a. IORef a -> IO a
readIORef IORef IS
ref IO IS -> (IS -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \IS
st ->
case IS
st of
IS
Input -> InputStream ByteString -> IO (Maybe ByteString)
forall a. InputStream a -> IO (Maybe a)
read InputStream ByteString
input IO (Maybe ByteString)
-> (Maybe ByteString -> IO (Maybe ByteString))
-> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO (Maybe ByteString)
-> (ByteString -> IO (Maybe ByteString))
-> Maybe ByteString
-> IO (Maybe ByteString)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO (Maybe ByteString)
eof ByteString -> IO (Maybe ByteString)
chunk
Popper IO (Maybe ByteString)
p -> IO (Maybe ByteString) -> IO (Maybe ByteString)
pop IO (Maybe ByteString)
p
IS
Done -> Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ByteString
forall a. Maybe a
Nothing
eof :: IO (Maybe ByteString)
eof = do
ByteString
x <- Inflate -> IO ByteString
finishInflate Inflate
state
IORef IS -> IS -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef IS
ref IS
Done
if (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ByteString -> Bool
S.null ByteString
x)
then Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ByteString -> IO (Maybe ByteString))
-> Maybe ByteString -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$! ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
x
else Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ByteString
forall a. Maybe a
Nothing
chunk :: ByteString -> IO (Maybe ByteString)
chunk ByteString
s =
if ByteString -> Bool
S.null ByteString
s
then do
ByteString
out <- Inflate -> IO ByteString
flushInflate Inflate
state
Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ByteString -> IO (Maybe ByteString))
-> Maybe ByteString -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$! ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
out
else Inflate -> ByteString -> IO (IO (Maybe ByteString))
feedInflate Inflate
state ByteString
s IO (IO (Maybe ByteString))
-> (IO (Maybe ByteString) -> IO (Maybe ByteString))
-> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \IO (Maybe ByteString)
popper -> do
IORef IS -> IS -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef IS
ref (IS -> IO ()) -> IS -> IO ()
forall a b. (a -> b) -> a -> b
$ IO (Maybe ByteString) -> IS
Popper IO (Maybe ByteString)
popper
IO (Maybe ByteString) -> IO (Maybe ByteString)
pop IO (Maybe ByteString)
popper
pop :: IO (Maybe ByteString) -> IO (Maybe ByteString)
pop IO (Maybe ByteString)
popper = IO (Maybe ByteString)
popper IO (Maybe ByteString)
-> (Maybe ByteString -> IO (Maybe ByteString))
-> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO (Maybe ByteString)
-> (ByteString -> IO (Maybe ByteString))
-> Maybe ByteString
-> IO (Maybe ByteString)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO (Maybe ByteString)
backToInput (Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ByteString -> IO (Maybe ByteString))
-> (ByteString -> Maybe ByteString)
-> ByteString
-> IO (Maybe ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just)
backToInput :: IO (Maybe ByteString)
backToInput = IORef IS -> IS -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef IS
ref IS
Input IO () -> IO (Maybe ByteString) -> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> InputStream ByteString -> IO (Maybe ByteString)
forall a. InputStream a -> IO (Maybe a)
read InputStream ByteString
input IO (Maybe ByteString)
-> (Maybe ByteString -> IO (Maybe ByteString))
-> IO (Maybe ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO (Maybe ByteString)
-> (ByteString -> IO (Maybe ByteString))
-> Maybe ByteString
-> IO (Maybe ByteString)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO (Maybe ByteString)
eof ByteString -> IO (Maybe ByteString)
chunk
deflateBuilder :: OutputStream Builder
-> Deflate
-> IO (OutputStream Builder)
deflateBuilder :: OutputStream Builder -> Deflate -> IO (OutputStream Builder)
deflateBuilder OutputStream Builder
stream Deflate
state = do
OutputStream ByteString
zippedStr <- (Maybe ByteString -> IO ()) -> IO (OutputStream ByteString)
forall a. (Maybe a -> IO ()) -> IO (OutputStream a)
makeOutputStream Maybe ByteString -> IO ()
bytestringStream IO (OutputStream ByteString)
-> (OutputStream ByteString -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
\OutputStream ByteString
x -> OutputStream ByteString -> Deflate -> IO (OutputStream ByteString)
deflate OutputStream ByteString
x Deflate
state
IO Buffer -> OutputStream ByteString -> IO (OutputStream Builder)
unsafeBuilderStream (Int -> IO Buffer
newBuffer Int
defaultChunkSize) OutputStream ByteString
zippedStr
where
bytestringStream :: Maybe ByteString -> IO ()
bytestringStream Maybe ByteString
x = Maybe Builder -> OutputStream Builder -> IO ()
forall a. Maybe a -> OutputStream a -> IO ()
write ((ByteString -> Builder) -> Maybe ByteString -> Maybe Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Builder
cvt Maybe ByteString
x) OutputStream Builder
stream
cvt :: ByteString -> Builder
cvt ByteString
s | ByteString -> Bool
S.null ByteString
s = Builder
flush
| Bool
otherwise = ByteString -> Builder
byteString ByteString
s
gzipBuilder :: CompressionLevel
-> OutputStream Builder
-> IO (OutputStream Builder)
gzipBuilder :: CompressionLevel
-> OutputStream Builder -> IO (OutputStream Builder)
gzipBuilder CompressionLevel
level OutputStream Builder
output =
Int -> WindowBits -> IO Deflate
initDeflate (CompressionLevel -> Int
clamp CompressionLevel
level) WindowBits
gzipBits IO Deflate
-> (Deflate -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= OutputStream Builder -> Deflate -> IO (OutputStream Builder)
deflateBuilder OutputStream Builder
output
compressBuilder :: CompressionLevel
-> OutputStream Builder
-> IO (OutputStream Builder)
compressBuilder :: CompressionLevel
-> OutputStream Builder -> IO (OutputStream Builder)
compressBuilder CompressionLevel
level OutputStream Builder
output =
Int -> WindowBits -> IO Deflate
initDeflate (CompressionLevel -> Int
clamp CompressionLevel
level) WindowBits
compressBits IO Deflate
-> (Deflate -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= OutputStream Builder -> Deflate -> IO (OutputStream Builder)
deflateBuilder OutputStream Builder
output
deflate :: OutputStream ByteString
-> Deflate
-> IO (OutputStream ByteString)
deflate :: OutputStream ByteString -> Deflate -> IO (OutputStream ByteString)
deflate OutputStream ByteString
output Deflate
state = (Maybe ByteString -> IO ()) -> IO (OutputStream ByteString)
forall a. (Maybe a -> IO ()) -> IO (OutputStream a)
makeOutputStream Maybe ByteString -> IO ()
stream
where
stream :: Maybe ByteString -> IO ()
stream Maybe ByteString
Nothing = IO (Maybe ByteString) -> IO ()
popAll (Deflate -> IO (Maybe ByteString)
finishDeflate Deflate
state) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe ByteString -> OutputStream ByteString -> IO ()
forall a. Maybe a -> OutputStream a -> IO ()
write Maybe ByteString
forall a. Maybe a
Nothing OutputStream ByteString
output
stream (Just ByteString
s) = do
if ByteString -> Bool
S.null ByteString
s
then do
IO (Maybe ByteString) -> IO ()
popAll (Deflate -> IO (Maybe ByteString)
flushDeflate Deflate
state)
Maybe ByteString -> OutputStream ByteString -> IO ()
forall a. Maybe a -> OutputStream a -> IO ()
write (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
S.empty) OutputStream ByteString
output
else Deflate -> ByteString -> IO (IO (Maybe ByteString))
feedDeflate Deflate
state ByteString
s IO (IO (Maybe ByteString))
-> (IO (Maybe ByteString) -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO (Maybe ByteString) -> IO ()
popAll
popAll :: IO (Maybe ByteString) -> IO ()
popAll IO (Maybe ByteString)
popper = IO ()
go
where
go :: IO ()
go = IO (Maybe ByteString)
popper IO (Maybe ByteString) -> (Maybe ByteString -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO () -> (ByteString -> IO ()) -> Maybe ByteString -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return (() -> IO ()) -> () -> IO ()
forall a b. (a -> b) -> a -> b
$! ()) (\ByteString
s -> Maybe ByteString -> OutputStream ByteString -> IO ()
forall a. Maybe a -> OutputStream a -> IO ()
write (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
s) OutputStream ByteString
output IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
go)
newtype CompressionLevel = CompressionLevel Int
deriving (ReadPrec [CompressionLevel]
ReadPrec CompressionLevel
Int -> ReadS CompressionLevel
ReadS [CompressionLevel]
(Int -> ReadS CompressionLevel)
-> ReadS [CompressionLevel]
-> ReadPrec CompressionLevel
-> ReadPrec [CompressionLevel]
-> Read CompressionLevel
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [CompressionLevel]
$creadListPrec :: ReadPrec [CompressionLevel]
readPrec :: ReadPrec CompressionLevel
$creadPrec :: ReadPrec CompressionLevel
readList :: ReadS [CompressionLevel]
$creadList :: ReadS [CompressionLevel]
readsPrec :: Int -> ReadS CompressionLevel
$creadsPrec :: Int -> ReadS CompressionLevel
Read, CompressionLevel -> CompressionLevel -> Bool
(CompressionLevel -> CompressionLevel -> Bool)
-> (CompressionLevel -> CompressionLevel -> Bool)
-> Eq CompressionLevel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CompressionLevel -> CompressionLevel -> Bool
$c/= :: CompressionLevel -> CompressionLevel -> Bool
== :: CompressionLevel -> CompressionLevel -> Bool
$c== :: CompressionLevel -> CompressionLevel -> Bool
Eq, Int -> CompressionLevel -> ShowS
[CompressionLevel] -> ShowS
CompressionLevel -> String
(Int -> CompressionLevel -> ShowS)
-> (CompressionLevel -> String)
-> ([CompressionLevel] -> ShowS)
-> Show CompressionLevel
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CompressionLevel] -> ShowS
$cshowList :: [CompressionLevel] -> ShowS
show :: CompressionLevel -> String
$cshow :: CompressionLevel -> String
showsPrec :: Int -> CompressionLevel -> ShowS
$cshowsPrec :: Int -> CompressionLevel -> ShowS
Show, Integer -> CompressionLevel
CompressionLevel -> CompressionLevel
CompressionLevel -> CompressionLevel -> CompressionLevel
(CompressionLevel -> CompressionLevel -> CompressionLevel)
-> (CompressionLevel -> CompressionLevel -> CompressionLevel)
-> (CompressionLevel -> CompressionLevel -> CompressionLevel)
-> (CompressionLevel -> CompressionLevel)
-> (CompressionLevel -> CompressionLevel)
-> (CompressionLevel -> CompressionLevel)
-> (Integer -> CompressionLevel)
-> Num CompressionLevel
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> CompressionLevel
$cfromInteger :: Integer -> CompressionLevel
signum :: CompressionLevel -> CompressionLevel
$csignum :: CompressionLevel -> CompressionLevel
abs :: CompressionLevel -> CompressionLevel
$cabs :: CompressionLevel -> CompressionLevel
negate :: CompressionLevel -> CompressionLevel
$cnegate :: CompressionLevel -> CompressionLevel
* :: CompressionLevel -> CompressionLevel -> CompressionLevel
$c* :: CompressionLevel -> CompressionLevel -> CompressionLevel
- :: CompressionLevel -> CompressionLevel -> CompressionLevel
$c- :: CompressionLevel -> CompressionLevel -> CompressionLevel
+ :: CompressionLevel -> CompressionLevel -> CompressionLevel
$c+ :: CompressionLevel -> CompressionLevel -> CompressionLevel
Num)
defaultCompressionLevel :: CompressionLevel
defaultCompressionLevel :: CompressionLevel
defaultCompressionLevel = Int -> CompressionLevel
CompressionLevel Int
5
clamp :: CompressionLevel -> Int
clamp :: CompressionLevel -> Int
clamp (CompressionLevel Int
x) = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
9 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
x Int
0)
gzip :: CompressionLevel
-> OutputStream ByteString
-> IO (OutputStream ByteString)
gzip :: CompressionLevel
-> OutputStream ByteString -> IO (OutputStream ByteString)
gzip CompressionLevel
level OutputStream ByteString
output = Int -> WindowBits -> IO Deflate
initDeflate (CompressionLevel -> Int
clamp CompressionLevel
level) WindowBits
gzipBits IO Deflate
-> (Deflate -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= OutputStream ByteString -> Deflate -> IO (OutputStream ByteString)
deflate OutputStream ByteString
output
compress :: CompressionLevel
-> OutputStream ByteString
-> IO (OutputStream ByteString)
compress :: CompressionLevel
-> OutputStream ByteString -> IO (OutputStream ByteString)
compress CompressionLevel
level OutputStream ByteString
output = Int -> WindowBits -> IO Deflate
initDeflate (CompressionLevel -> Int
clamp CompressionLevel
level) WindowBits
compressBits IO Deflate
-> (Deflate -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
OutputStream ByteString -> Deflate -> IO (OutputStream ByteString)
deflate OutputStream ByteString
output