packages feed

brotli-streams (empty) → 0.0.0.0

raw patch · 5 files changed

+306/−0 lines, 5 filesdep +HUnitdep +QuickCheckdep +basesetup-changed

Dependencies added: HUnit, QuickCheck, base, brotli, brotli-streams, bytestring, io-streams, test-framework, test-framework-hunit, test-framework-quickcheck2

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Herbert Valerio Riedel++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Herbert Valerio Riedel nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ brotli-streams.cabal view
@@ -0,0 +1,60 @@+cabal-version:       1.12+build-type:          Simple+name:                brotli-streams+version:             0.0.0.0++synopsis:            IO-Streams interface for Brotli (RFC7932) compression+homepage:            https://github.com/hvr/brotli-streams+bug-reports:         https://github.com/hvr/brotli-streams/issues+license:             BSD3+license-file:        LICENSE+author:              Herbert Valerio Riedel+maintainer:          hvr@gnu.org+copyright:           (c) 2016, Herbert Valerio Riedel+category:            Codec, Compression, IO-Streams++description:+    <http://brotli.org Brotli> (<https://tools.ietf.org/html/rfc7932 RFC7932>) is a generic-purpose lossless compression algorithm suitable for <https://en.wikipedia.org/wiki/HTTP_compression HTTP compression> that compresses data using a combination of a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling.+    .+    This package provides an IO-Streams interface for the Brotli compression algorithm.+    .+    Decompressing Brotli 'InputStreams' and compressing 'OutputStreams'+    to Brotli streams with tunable (de)compression parameters is supported.+    .++source-repository head+  type:     git+  location: https://github.com/hvr/brotli-streams.git++library+  default-language:    Haskell2010+  other-extensions:    Trustworthy++  hs-source-dirs:      src+  exposed-modules:     System.IO.Streams.Brotli++  build-depends:       base       >=4.5    && <4.13,+                       bytestring >=0.9.2  && <0.11,+                       io-streams >=1.3    && <1.6,+                       brotli     ==0.0.*++  ghc-options:         -Wall++test-suite lzma-streams-test+  default-language:    Haskell2010+  hs-source-dirs:      src-tests+  main-is:             lzma-streams-test.hs+  type:                exitcode-stdio-1.0++  build-depends:       base,+                       bytestring,+                       io-streams,+                       brotli-streams,++                       HUnit == 1.6.*,+                       QuickCheck == 2.13.*,+                       test-framework == 0.8.*,+                       test-framework-hunit == 0.3.*,+                       test-framework-quickcheck2 == 0.3.*++  ghc-options:         -Wall -threaded
+ src-tests/lzma-streams-test.hs view
@@ -0,0 +1,64 @@+import qualified System.IO.Streams.Brotli as Brotli+import qualified System.IO.Streams as Streams+import           Test.Framework+import           Test.Framework.Providers.HUnit+import           Test.Framework.Providers.QuickCheck2+import           Test.HUnit                           hiding (Test)+import qualified Data.ByteString as BS++import System.IO.Unsafe++main :: IO ()+main = defaultMain [ testGroup "System.IO.Streams.Brotli" tests ]+  where+    tests =  [ test0, test1, test2, prop1 ]++test0 :: Test+test0 = testCase "empty" $ (decode . encode) BS.empty @?= BS.empty++test1 :: Test+test1 = testCase "hello" $ (decode . encode) bs @?= bs+  where+    bs = BS.pack [104,101,108,108,111]++test2 :: Test+test2 = testCase "10MiB" $ (decode . encode) bs @?= bs+  where+    bs = BS.replicate (10*1024*1024) 0xaa++prop1 :: Test+prop1 = testProperty "random" go+  where+    go s = (decode . encode) bs == bs+      where+        bs = BS.pack s++{- concat not supported yet+prop2 :: Test+prop2 = testProperty "random-concat" go+  where+    go s s2 = decode (encode bs `BS.append` encode bs2) == bs `BS.append` bs2+      where+        bs  = BS.pack s+        bs2 = BS.pack s2+-}++encode :: BS.ByteString -> BS.ByteString+encode bs = unsafePerformIO $ do+    lst <- Streams.outputToList $ \obs -> do+        ibs  <- Streams.fromByteString bs+        obs' <- Brotli.compress obs+        Streams.connect ibs obs'++    return (BS.concat lst)+{-# NOINLINE encode #-}++decode :: BS.ByteString -> BS.ByteString+decode bs = unsafePerformIO $ do+    lst <- Streams.outputToList $ \obs -> do+        ibs  <- Streams.fromByteString bs+        ibs' <- Brotli.decompress ibs+        Streams.connect ibs' obs++    return (BS.concat lst)+{-# NOINLINE decode #-}
+ src/System/IO/Streams/Brotli.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE Trustworthy #-}++-- |+-- Module      : System.IO.Streams.Brotli+-- Copyright   : © 2016 Herbert Valerio Riedel+-- License     : BSD3+--+-- Maintainer  : hvr@gnu.org+--+-- Simple IO-Streams interface for Brotli compression (<https://tools.ietf.org/html/rfc7932 RFC7932>).+--+module System.IO.Streams.Brotli+    ( -- * Simple interface+      compress+    , decompress++      -- * Extended interface+      -- ** Compression+    , compressWith++    , Brotli.defaultCompressParams+    , Brotli.CompressParams+    , Brotli.compressLevel+    , Brotli.compressWindowSize+    , Brotli.compressMode+    , Brotli.compressSizeHint+    , Brotli.CompressionLevel(..)+    , Brotli.CompressionWindowSize(..)+    , Brotli.CompressionMode(..)++      -- ** Decompression+    , decompressWith++    , Brotli.defaultDecompressParams+    , Brotli.DecompressParams+    , Brotli.decompressDisableRingBufferReallocation++    ) where++import           Codec.Compression.Brotli (DecompressStream(..), CompressStream(..))+import qualified Codec.Compression.Brotli as Brotli++import           Control.Exception+import           Control.Monad+import           Data.ByteString        (ByteString)+import qualified Data.ByteString        as BS+import           Data.IORef+import           Data.Maybe+import           System.IO.Streams      (InputStream, OutputStream,+                                         makeInputStream, makeOutputStream)+import qualified System.IO.Streams      as Streams++-- | Decompress a Brotli-compressed 'InputStream' of strict 'ByteString's+decompress :: InputStream ByteString -> IO (InputStream ByteString)+decompress = decompressWith Brotli.defaultDecompressParams++-- | Like 'decompress' but with the ability to specify various decompression+-- parameters. Typical usage:+--+-- > decompressWith defaultDecompressParams { decompress... = ... }+decompressWith :: Brotli.DecompressParams -> InputStream ByteString -> IO (InputStream ByteString)+decompressWith parms ibs = do+    st <- newIORef =<< Brotli.decompressIO parms+    makeInputStream (go st)+  where+    go stref = do+        st' <- goFeed =<< readIORef stref+        case st' of+            DecompressInputRequired _ -> do+                writeIORef stref st'+                fail "the impossible happened"++            DecompressOutputAvailable outb next -> do+                writeIORef stref =<< next+                return (Just outb)++            DecompressStreamEnd leftover -> do+                unless (BS.null leftover) $ do+                    Streams.unRead leftover ibs+                writeIORef stref (DecompressStreamEnd BS.empty)+                return Nothing++            DecompressStreamError rc -> do+                writeIORef stref st'+                throwIO rc++    -- feed engine+    goFeed (DecompressInputRequired supply) =+        goFeed =<< supply . fromMaybe BS.empty =<< getChunk+    goFeed s = return s++    -- wrapper around 'read ibs' to retry until a non-empty ByteString or Nothing is returned+    getChunk = do+        mbs <- Streams.read ibs+        case mbs of+            Just bs | BS.null bs -> getChunk+            _                    -> return mbs++----------------------------------------------------------------------------+----------------------------------------------------------------------------++-- | Convert an 'OutputStream' that consumes compressed 'ByteString's+-- (in the Brotli format) into an 'OutputStream' that consumes+-- uncompressed 'ByteString's+compress :: OutputStream ByteString -> IO (OutputStream ByteString)+compress = compressWith Brotli.defaultCompressParams++-- | Like 'compress' but with the ability to specify various compression+-- parameters. Typical usage:+--+-- > compressWith defaultCompressParams { compress... = ... }+compressWith :: Brotli.CompressParams -> OutputStream ByteString -> IO (OutputStream ByteString)+compressWith parms obs = do+    st <- newIORef =<< Brotli.compressIO parms+    makeOutputStream (go st)+  where+    go stref (Just chunk) = do+        st <- readIORef stref+        st' <- case st of+            CompressInputRequired flush supply+              | BS.null chunk -> goOutput True =<< flush+              | otherwise     -> goOutput False =<< supply chunk+            _ -> fail "compressWith: unexpected state"+        writeIORef stref st'+        case st' of+            CompressInputRequired _ _ -> return ()+            _ -> fail "compressWith:  unexpected state"++    -- EOF+    go stref Nothing = do+        st <- readIORef stref+        st' <- case st of+            CompressInputRequired _ supply -> goOutput False =<< supply BS.empty+            _ -> fail "compressWith[EOF]: unexpected state"+        writeIORef stref st'+        case st' of+            CompressStreamEnd -> return ()+            _ -> fail "compressWith[EOF]:  unexpected state"++    -- Drain output from CompressStream+    goOutput flush st@(CompressInputRequired _ _) = do+        when flush $+            Streams.write (Just BS.empty) obs+        return st+    goOutput flush (CompressOutputAvailable obuf next) = do+        Streams.write (Just obuf) obs+        goOutput flush =<< next+    goOutput _ st@CompressStreamEnd = do+        Streams.write Nothing obs+        return st