{-# LINE 1 "src/LibBrotli.hsc" #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RecordWildCards #-}
module LibBrotli
( CompressParams(..), defaultCompressParams
, CompressionLevel(..), CompressionWindowSize(..), CompressionMode(..)
, DecompressParams(..), defaultDecompressParams
, BrotliState(..), BrotliEncOp(..)
, newBrotliEncoder, newBrotliDecoder
, finalizeBrotliEncoder, finalizeBrotliDecoder
, runBrotliEncoder, runBrotliDecoder
, readBrotliEncoder, readBrotliDecoder
, brotliEncoderVersion, brotliDecoderVersion
, BrotliDecoderErrorCode(..), showBrotliDecoderErrorCode
) where
import Control.Applicative
import Control.Monad
import Control.Exception
import Control.Monad.ST.Strict (ST)
import Control.Monad.ST.Unsafe (unsafeIOToST)
import Data.ByteString (ByteString)
import Data.Typeable (Typeable)
import Foreign
import Foreign.C
import System.IO.Unsafe as Unsafe (unsafePerformIO)
import Prelude
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BS
import Control.Monad.Trans.Maybe (MaybeT(..))
allocaPoke :: Storable x => x -> (Ptr x -> IO b) -> IO b
allocaPoke v0 act = alloca $ \pv -> do { poke pv v0; act pv }
packBS :: Ptr Word8 -> CSize -> IO ByteString
packBS p sz
| sz > 0 = BS.packCStringLen (castPtr p, fromIntegral sz)
| otherwise = pure BS.empty
type BrotliBool = Int32
{-# LINE 63 "src/LibBrotli.hsc" #-}
fromBrotliBool :: BrotliBool -> Maybe Bool
fromBrotliBool 1 = Just True
{-# LINE 66 "src/LibBrotli.hsc" #-}
fromBrotliBool 0 = Just False
{-# LINE 67 "src/LibBrotli.hsc" #-}
fromBrotliBool _ = Nothing
toBrotliBool :: Bool -> BrotliBool
toBrotliBool False = 0
{-# LINE 71 "src/LibBrotli.hsc" #-}
toBrotliBool True = 1
{-# LINE 72 "src/LibBrotli.hsc" #-}
newtype BrotliDecoderErrorCode = BrotliDecoderErrorCode Int deriving (Eq,Show,Typeable)
instance Exception BrotliDecoderErrorCode
{-# NOINLINE showBrotliDecoderErrorCode #-}
showBrotliDecoderErrorCode :: BrotliDecoderErrorCode -> String
showBrotliDecoderErrorCode (BrotliDecoderErrorCode ec) = Unsafe.unsafePerformIO $ do
bufptr <- c_BrotliDecoderErrorString (fromIntegral ec)
if bufptr == nullPtr then pure "" else peekCAString bufptr
data BrotliState
= BSNeedsInput
| BSHasOutput
| BSFinished
| BSFail
| BSInternalError
deriving (Eq,Show)
type HsBrotliState = Word32
{-# LINE 99 "src/LibBrotli.hsc" #-}
fromHsBrotliState :: HsBrotliState -> BrotliState
fromHsBrotliState x = case x of
0 -> BSNeedsInput
{-# LINE 103 "src/LibBrotli.hsc" #-}
1 -> BSHasOutput
{-# LINE 104 "src/LibBrotli.hsc" #-}
2 -> BSFinished
{-# LINE 105 "src/LibBrotli.hsc" #-}
3 -> BSFail
{-# LINE 106 "src/LibBrotli.hsc" #-}
_ -> BSInternalError
data CompressParams = CompressParams
{ compressLevel :: !CompressionLevel
, compressWindowSize :: !CompressionWindowSize
, compressMode :: !CompressionMode
, compressSizeHint :: !Word32
}
data DecompressParams = DecompressParams
{ decompressDisableRingBufferReallocation :: !Bool
}
defaultCompressParams :: CompressParams
defaultCompressParams = CompressParams {..}
where
compressLevel = maxBound
compressWindowSize = CompressionWindowBits22
compressMode = CompressionModeGeneric
compressSizeHint = 0
defaultDecompressParams :: DecompressParams
defaultDecompressParams = DecompressParams False
newtype BrotliEncoder = BrotliEncoder (ForeignPtr BrotliEncoder)
newtype BrotliDecoder = BrotliDecoder (ForeignPtr BrotliDecoder)
newBrotliEncoder :: CompressParams -> ST s (Maybe BrotliEncoder)
newBrotliEncoder CompressParams{..} = unsafeIOToST $ runMaybeT $ do
fp <- MaybeT createBrotliEncoder
unless (11 == qualityParm) $ do
{-# LINE 152 "src/LibBrotli.hsc" #-}
rc <- setParm fp 1 qualityParm
{-# LINE 153 "src/LibBrotli.hsc" #-}
unless rc $ fail "invalid BROTLI_PARAM_QUALITY"
unless (0 == modeParm) $ do
{-# LINE 156 "src/LibBrotli.hsc" #-}
rc <- setParm fp 0 modeParm
{-# LINE 157 "src/LibBrotli.hsc" #-}
unless rc $ fail "invalid BROTLI_PARAM_MODE"
unless (22 == winParm) $ do
{-# LINE 160 "src/LibBrotli.hsc" #-}
unless ((10 <= winParm) && (winParm <= 24)) $
{-# LINE 161 "src/LibBrotli.hsc" #-}
fail "invalid BROTLI_PARAM_LGWIN (internal inconsistency)"
rc <- setParm fp 2 winParm
{-# LINE 164 "src/LibBrotli.hsc" #-}
unless rc $ fail "invalid BROTLI_PARAM_LGWIN"
unless (0 == compressSizeHint) $ do
rc <- setParm fp 5 compressSizeHint
{-# LINE 168 "src/LibBrotli.hsc" #-}
unless rc $ fail "invalid BROTLI_PARAM_SIZE_HINT"
pure fp
where
setParm (BrotliEncoder fp) k v = MaybeT (withForeignPtr fp $ \p -> fromBrotliBool <$> c_BrotliEncoderSetParameter p k v)
qualityParm = fromIntegral (fromEnum compressLevel)
winParm = fromIntegral (fromEnum compressWindowSize)
modeParm = case compressMode of
CompressionModeGeneric -> 0
{-# LINE 178 "src/LibBrotli.hsc" #-}
CompressionModeText -> 1
{-# LINE 179 "src/LibBrotli.hsc" #-}
CompressionModeFont -> 2
{-# LINE 180 "src/LibBrotli.hsc" #-}
newBrotliDecoder :: DecompressParams -> ST s (Maybe BrotliDecoder)
newBrotliDecoder DecompressParams{..} = unsafeIOToST $ runMaybeT $ do
fp <- MaybeT createBrotliDecoder
when decompressDisableRingBufferReallocation $ do
rc <- setParm fp 0
{-# LINE 187 "src/LibBrotli.hsc" #-}
(fromIntegral $ toBrotliBool decompressDisableRingBufferReallocation)
unless rc $ fail "invalid BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION"
pure fp
where
setParm (BrotliDecoder fp) k v = MaybeT (withForeignPtr fp $ \p -> fromBrotliBool <$> c_BrotliDecoderSetParameter p k v)
createBrotliEncoder :: IO (Maybe BrotliEncoder)
createBrotliEncoder = mask_ $ do
p <- c_BrotliEncoderCreateInstance nullPtr nullPtr nullPtr
case () of
_ | p == nullPtr -> pure Nothing
| otherwise -> do
!fp <- newForeignPtr cp_BrotliEncoderDestroyInstance p
pure (Just (BrotliEncoder fp))
createBrotliDecoder :: IO (Maybe BrotliDecoder)
createBrotliDecoder = mask_ $ do
p <- c_BrotliDecoderCreateInstance nullPtr nullPtr nullPtr
case () of
_ | p == nullPtr -> pure Nothing
| otherwise -> do
!fp <- newForeignPtr cp_BrotliDecoderDestroyInstance p
pure (Just (BrotliDecoder fp))
finalizeBrotliEncoder :: BrotliEncoder -> ST s ()
finalizeBrotliEncoder (BrotliEncoder s) = unsafeIOToST (finalizeForeignPtr s)
finalizeBrotliDecoder :: BrotliDecoder -> ST s ()
finalizeBrotliDecoder (BrotliDecoder s) = unsafeIOToST (finalizeForeignPtr s)
data BrotliEncOp
= BrotliEncOpProcess
| BrotliEncOpFlush
| BrotliEncOpFinish
runBrotliEncoder :: BrotliEncoder
-> ByteString
-> BrotliEncOp
-> ST s (BrotliState,Int)
runBrotliEncoder (BrotliEncoder fp) ibs action0
= unsafeIOToST $ withForeignPtr fp $ \encPtr -> do
BS.unsafeUseAsCStringLen ibs $ \(ibsptr, ibslen) ->
allocaPoke (fromIntegral ibslen) $ \availIn ->
allocaPoke ibsptr $ \nextIn -> do
allocaPoke 0 $ \availOut -> do
rc <- fromHsBrotliState <$>
c_BrotliEncoderCompressStream encPtr action availIn (castPtr nextIn) availOut nullPtr nullPtr
availIn' <- fromIntegral <$> peek availIn
pure (rc, availIn')
where
action = case action0 of
BrotliEncOpProcess -> 0
{-# LINE 241 "src/LibBrotli.hsc" #-}
BrotliEncOpFinish -> 2
{-# LINE 242 "src/LibBrotli.hsc" #-}
BrotliEncOpFlush -> 1
{-# LINE 243 "src/LibBrotli.hsc" #-}
runBrotliDecoder :: BrotliDecoder
-> ByteString
-> ST s (BrotliState,BrotliDecoderErrorCode,Int )
runBrotliDecoder (BrotliDecoder fp) ibs
= unsafeIOToST $ withForeignPtr fp $ \encPtr -> do
BS.unsafeUseAsCStringLen ibs $ \(ibsptr, ibslen) ->
allocaPoke (fromIntegral ibslen) $ \availIn ->
allocaPoke ibsptr $ \nextIn -> do
allocaPoke 0 $ \availOut -> do
rc <- fromHsBrotliState <$>
c_BrotliDecoderDecompressStream encPtr availIn (castPtr nextIn) availOut nullPtr nullPtr
availIn' <- fromIntegral <$> peek availIn
ecode <- BrotliDecoderErrorCode <$> if rc == BSFail
then fromIntegral <$> c_BrotliDecoderGetErrorCode encPtr
else pure 0
pure (rc, ecode, availIn')
readBrotliEncoder :: BrotliEncoder -> Int -> ST s (BrotliState, ByteString)
readBrotliEncoder (BrotliEncoder fp) maxobs
= unsafeIOToST $ withForeignPtr fp $ \encPtr -> do
allocaPoke (fromIntegral maxobs) $ \availOutPtr -> do
alloca $ \obsptrptr -> do
rc <- fromHsBrotliState <$>
c_BrotliEncoderTakeOutput encPtr availOutPtr obsptrptr
availOut' <- peek availOutPtr
obsptr <- peek obsptrptr
buf <- packBS obsptr availOut'
pure (rc, buf)
readBrotliDecoder :: BrotliDecoder -> Int -> ST s (BrotliState, ByteString)
readBrotliDecoder (BrotliDecoder fp) maxobs
= unsafeIOToST $ withForeignPtr fp $ \encPtr -> do
allocaPoke (fromIntegral maxobs) $ \availOutPtr -> do
alloca $ \obsptrptr -> do
rc <- fromHsBrotliState <$>
c_BrotliDecoderTakeOutput encPtr availOutPtr obsptrptr
availOut' <- peek availOutPtr
obsptr <- peek obsptrptr
buf <- packBS obsptr availOut'
pure (rc, buf)
data CompressionMode
= CompressionModeGeneric
| CompressionModeText
| CompressionModeFont
deriving (Eq,Read,Show,Typeable)
data CompressionLevel
= CompressionLevel0
| CompressionLevel1
| CompressionLevel2
| CompressionLevel3
| CompressionLevel4
| CompressionLevel5
| CompressionLevel6
| CompressionLevel7
| CompressionLevel8
| CompressionLevel9
| CompressionLevel10
| CompressionLevel11
deriving (Eq,Ord,Read,Show,Enum,Typeable,Bounded)
data CompressionWindowSize
= CompressionWindowBits10
| CompressionWindowBits11
| CompressionWindowBits12
| CompressionWindowBits13
| CompressionWindowBits14
| CompressionWindowBits15
| CompressionWindowBits16
| CompressionWindowBits17
| CompressionWindowBits18
| CompressionWindowBits19
| CompressionWindowBits20
| CompressionWindowBits21
| CompressionWindowBits22
| CompressionWindowBits23
| CompressionWindowBits24
deriving (Eq,Ord,Read,Show,Typeable,Bounded)
instance Enum CompressionWindowSize where
toEnum i = case i of
10 -> CompressionWindowBits10
11 -> CompressionWindowBits11
12 -> CompressionWindowBits12
13 -> CompressionWindowBits13
14 -> CompressionWindowBits14
15 -> CompressionWindowBits15
16 -> CompressionWindowBits16
17 -> CompressionWindowBits17
18 -> CompressionWindowBits18
19 -> CompressionWindowBits19
20 -> CompressionWindowBits20
21 -> CompressionWindowBits21
22 -> CompressionWindowBits22
23 -> CompressionWindowBits23
24 -> CompressionWindowBits24
_ -> error "toEnum(CompressionWindowSize): bad argument"
fromEnum x = case x of
CompressionWindowBits10 -> 10
CompressionWindowBits11 -> 11
CompressionWindowBits12 -> 12
CompressionWindowBits13 -> 13
CompressionWindowBits14 -> 14
CompressionWindowBits15 -> 15
CompressionWindowBits16 -> 16
CompressionWindowBits17 -> 17
CompressionWindowBits18 -> 18
CompressionWindowBits19 -> 19
CompressionWindowBits20 -> 20
CompressionWindowBits21 -> 21
CompressionWindowBits22 -> 22
CompressionWindowBits23 -> 23
CompressionWindowBits24 -> 24
foreign import capi "hs_brotli.h BrotliEncoderCreateInstance"
c_BrotliEncoderCreateInstance :: Ptr () -> Ptr () -> Ptr () -> IO (Ptr BrotliEncoder)
foreign import capi "hs_brotli.h &BrotliEncoderDestroyInstance"
cp_BrotliEncoderDestroyInstance :: FunPtr (Ptr BrotliEncoder -> IO ())
foreign import capi "hs_brotli.h HsBrotliEncoderCompressStream"
c_BrotliEncoderCompressStream :: Ptr BrotliEncoder
-> Word32
{-# LINE 393 "src/LibBrotli.hsc" #-}
-> Ptr CSize
-> Ptr (Ptr Word8)
-> Ptr CSize
-> Ptr (Ptr Word8)
-> Ptr CSize
-> IO HsBrotliState
foreign import capi unsafe "hs_brotli.h HsBrotliEncoderTakeOutput"
c_BrotliEncoderTakeOutput :: Ptr BrotliEncoder -> Ptr CSize -> Ptr (Ptr Word8) -> IO HsBrotliState
foreign import capi unsafe "hs_brotli.h BrotliEncoderVersion" brotliEncoderVersion :: Word32
foreign import capi unsafe "hs_brotli.h BrotliEncoderSetParameter"
c_BrotliEncoderSetParameter :: Ptr BrotliEncoder -> Word32 -> Word32 -> IO BrotliBool
{-# LINE 417 "src/LibBrotli.hsc" #-}
foreign import capi "hs_brotli.h BrotliDecoderCreateInstance"
c_BrotliDecoderCreateInstance :: Ptr () -> Ptr () -> Ptr () -> IO (Ptr BrotliDecoder)
foreign import capi "hs_brotli.h &BrotliDecoderDestroyInstance"
cp_BrotliDecoderDestroyInstance :: FunPtr (Ptr BrotliDecoder -> IO ())
foreign import capi "hs_brotli.h HsBrotliDecoderDecompressStream"
c_BrotliDecoderDecompressStream :: Ptr BrotliDecoder
-> Ptr CSize
-> Ptr (Ptr Word8)
-> Ptr CSize
-> Ptr (Ptr Word8)
-> Ptr CSize
-> IO Word32
{-# LINE 438 "src/LibBrotli.hsc" #-}
foreign import capi unsafe "hs_brotli.h HsBrotliDecoderTakeOutput"
c_BrotliDecoderTakeOutput :: Ptr BrotliDecoder -> Ptr CSize -> Ptr (Ptr Word8) -> IO HsBrotliState
foreign import capi unsafe "hs_brotli.h BrotliDecoderVersion" brotliDecoderVersion :: Word32
foreign import capi unsafe "hs_brotli.h BrotliDecoderSetParameter"
c_BrotliDecoderSetParameter :: Ptr BrotliDecoder -> Word32 -> Word32 -> IO BrotliBool
{-# LINE 453 "src/LibBrotli.hsc" #-}
foreign import capi unsafe "hs_brotli.h BrotliDecoderGetErrorCode"
c_BrotliDecoderGetErrorCode :: Ptr BrotliDecoder -> IO Int32
{-# LINE 456 "src/LibBrotli.hsc" #-}
foreign import capi unsafe "hs_brotli.h HsBrotliDecoderErrorString"
c_BrotliDecoderErrorString :: Int32 -> IO CString
{-# LINE 459 "src/LibBrotli.hsc" #-}