{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE Trustworthy #-}
module Streaming.Brotli
(
compress
, decompress
, decompress_
, compressWith
, Brotli.defaultCompressParams
, Brotli.CompressParams
, Brotli.compressLevel
, Brotli.compressWindowSize
, Brotli.compressMode
, Brotli.compressSizeHint
, Brotli.CompressionLevel(..)
, Brotli.CompressionWindowSize(..)
, Brotli.CompressionMode(..)
, decompressWith
, Brotli.defaultDecompressParams
, Brotli.DecompressParams
, Brotli.decompressDisableRingBufferReallocation
) where
import qualified Codec.Compression.Brotli as Brotli
import Control.Exception (throwIO)
import qualified Data.ByteString as B
import Data.ByteString.Streaming (ByteString, chunk, effects,
nextChunk, null_)
import Streaming (MonadIO (liftIO), lift)
decompress :: MonadIO m
=> ByteString m r
-> ByteString m (ByteString m r)
decompress = decompressWith Brotli.defaultDecompressParams
decompress_ :: MonadIO m
=> ByteString m r
-> ByteString m r
decompress_ is = do
mr <- decompress is
lift $ do
noLeftovers <- null_ mr
if noLeftovers
then effects mr
else liftIO (throwIO (Brotli.BrotliException "extra trailing data"))
decompressWith :: MonadIO m
=> Brotli.DecompressParams
-> ByteString m r
-> ByteString m (ByteString m r)
decompressWith params stream0 =
go stream0 =<< liftIO (Brotli.decompressIO params)
where
go stream enc@(Brotli.DecompressInputRequired cont) = do
lift (nextChunk stream) >>= \case
Right (ibs,stream')
| B.null ibs -> go stream' enc
| otherwise -> go stream' =<< liftIO (cont ibs)
Left r -> go (pure r) =<< liftIO (cont B.empty)
go stream (Brotli.DecompressOutputAvailable obs cont) = do
chunk obs
go stream =<< liftIO cont
go stream (Brotli.DecompressStreamEnd leftover) =
pure (chunk leftover >> stream)
go _stream (Brotli.DecompressStreamError ecode) =
liftIO (throwIO ecode)
compress :: MonadIO m
=> ByteString m r
-> ByteString m r
compress = compressWith Brotli.defaultCompressParams
compressWith :: MonadIO m
=> Brotli.CompressParams
-> ByteString m r
-> ByteString m r
compressWith params stream0 =
go stream0 =<< liftIO (Brotli.compressIO params)
where
go stream enc@(Brotli.CompressInputRequired _flush cont) = do
lift (nextChunk stream) >>= \case
Right (x, stream')
| B.null x -> go stream' enc
| otherwise -> go stream' =<< liftIO (cont x)
Left r -> go (pure r) =<< liftIO (cont B.empty)
go stream (Brotli.CompressOutputAvailable obs cont) = do
chunk obs
go stream =<< liftIO cont
go stream Brotli.CompressStreamEnd = stream