packages feed

bz2 0.1.1.1 → 1.0.0.0

raw patch · 15 files changed

+349/−256 lines, 15 filesdep +deepseqdep +directorydep +temporarydep ~basedep ~filepathPVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq, directory, temporary

Dependency ranges changed: base, filepath

API changes (from Hackage documentation)

- Codec.Compression.BZip.Foreign: BzConfigError :: BZError
- Codec.Compression.BZip.Foreign: BzDataError :: BZError
- Codec.Compression.BZip.Foreign: BzDataErrorMagic :: BZError
- Codec.Compression.BZip.Foreign: BzFinish :: BZAction
- Codec.Compression.BZip.Foreign: BzFinishOk :: BZError
- Codec.Compression.BZip.Foreign: BzFlush :: BZAction
- Codec.Compression.BZip.Foreign: BzFlushOk :: BZError
- Codec.Compression.BZip.Foreign: BzIoError :: BZError
- Codec.Compression.BZip.Foreign: BzMemError :: BZError
- Codec.Compression.BZip.Foreign: BzOk :: BZError
- Codec.Compression.BZip.Foreign: BzOutbuffFull :: BZError
- Codec.Compression.BZip.Foreign: BzParamError :: BZError
- Codec.Compression.BZip.Foreign: BzRun :: BZAction
- Codec.Compression.BZip.Foreign: BzRunOk :: BZError
- Codec.Compression.BZip.Foreign: BzSequenceError :: BZError
- Codec.Compression.BZip.Foreign: BzStreamEnd :: BZError
- Codec.Compression.BZip.Foreign: BzUnexpectedEof :: BZError
- Codec.Compression.BZip.Foreign: bZ2BzBuffToBuffCompress :: Ptr a -> Ptr a -> CUInt -> CInt -> CInt -> CInt -> IO CUInt
- Codec.Compression.BZip.Foreign: bZ2BzBuffToBuffDecompress :: Ptr a -> Ptr a -> CUInt -> Bool -> CInt -> IO (BZError, CUInt)
- Codec.Compression.BZip.Foreign: bZ2BzCompress :: BzStreamPtr -> BZAction -> IO BZError
- Codec.Compression.BZip.Foreign: bZ2BzCompressEnd :: BzStreamPtr -> IO ()
- Codec.Compression.BZip.Foreign: bZ2BzCompressInit :: BzStreamPtr -> CInt -> CInt -> CInt -> IO ()
- Codec.Compression.BZip.Foreign: bZ2BzDecompress :: BzStreamPtr -> IO BZError
- Codec.Compression.BZip.Foreign: bZ2BzDecompressEnd :: BzStreamPtr -> IO ()
- Codec.Compression.BZip.Foreign: bZ2BzDecompressInit :: BzStreamPtr -> CInt -> Bool -> IO ()
- Codec.Compression.BZip.Foreign: bZ2BzRead :: BzFilePtr -> Ptr a -> CInt -> IO (CInt, BZError)
- Codec.Compression.BZip.Foreign: bZ2BzReadClose :: BzFilePtr -> IO BZError
- Codec.Compression.BZip.Foreign: bZ2BzReadGetUnused :: BzFilePtr -> IO (BZError, Ptr a, CInt)
- Codec.Compression.BZip.Foreign: bZ2BzReadOpen :: FilePtr -> CInt -> Bool -> Ptr a -> CInt -> IO (BzFilePtr, BZError)
- Codec.Compression.BZip.Foreign: bZ2BzWrite :: BzFilePtr -> Ptr a -> CInt -> IO BZError
- Codec.Compression.BZip.Foreign: bZ2BzWriteClose :: BzFilePtr -> Bool -> IO (BZError, CUInt, CUInt)
- Codec.Compression.BZip.Foreign: bZ2BzWriteClose64 :: BzFilePtr -> Bool -> IO (BZError, CUInt, CUInt, CUInt, CUInt)
- Codec.Compression.BZip.Foreign: bZ2BzWriteOpen :: FilePtr -> CInt -> CInt -> CInt -> IO (BzFilePtr, BZError)
- Codec.Compression.BZip.Foreign: bZ2BzlibVersion :: String
- Codec.Compression.BZip.Foreign: bZMaxUnused :: Integral a => a
- Codec.Compression.BZip.Foreign: data BZAction
- Codec.Compression.BZip.Foreign: data BZError
- Codec.Compression.BZip.Foreign: data BzFile
- Codec.Compression.BZip.Foreign: data BzStream
- Codec.Compression.BZip.Foreign: data FilePtr
- Codec.Compression.BZip.Foreign: instance GHC.Classes.Eq Codec.Compression.BZip.Foreign.BZError
- Codec.Compression.BZip.Foreign: instance GHC.Enum.Enum Codec.Compression.BZip.Foreign.BZAction
- Codec.Compression.BZip.Foreign: instance GHC.Enum.Enum Codec.Compression.BZip.Foreign.BZError
- Codec.Compression.BZip.Foreign: instance GHC.Exception.Type.Exception Codec.Compression.BZip.Foreign.BZError
- Codec.Compression.BZip.Foreign: instance GHC.Show.Show Codec.Compression.BZip.Foreign.BZError
- Codec.Compression.BZip.Foreign: type BzFilePtr = Ptr (BzFile)
- Codec.Compression.BZip.Foreign: type BzStreamPtr = Ptr (BzStream)
+ Codec.Compression.BZip: BzConfigError :: BZError
+ Codec.Compression.BZip: BzDataError :: BZError
+ Codec.Compression.BZip: BzDataErrorMagic :: BZError
+ Codec.Compression.BZip: BzFinishOk :: BZError
+ Codec.Compression.BZip: BzFlushOk :: BZError
+ Codec.Compression.BZip: BzIoError :: BZError
+ Codec.Compression.BZip: BzMemError :: BZError
+ Codec.Compression.BZip: BzOk :: BZError
+ Codec.Compression.BZip: BzOutbuffFull :: BZError
+ Codec.Compression.BZip: BzParamError :: BZError
+ Codec.Compression.BZip: BzRunOk :: BZError
+ Codec.Compression.BZip: BzSequenceError :: BZError
+ Codec.Compression.BZip: BzStreamEnd :: BZError
+ Codec.Compression.BZip: BzUnexpectedEof :: BZError
+ Codec.Compression.BZip: bZ2BzlibVersion :: String
+ Codec.Compression.BZip: data BZError

Files

CHANGELOG.md view
@@ -1,5 +1,15 @@ # bz2 +## 1.0.0.0++  * Remove `Codec.Compression.BZip.Foreign`+  * Use `ForeignPtr` under the hood+  * Lazier streaming; memory use should be sensible++## 0.1.1.2++  * Use `ForeignPtr`s under the hood in various places (over `bracket`)+ ## 0.1.1.1    * Haddock improvements
+ Makefile view
@@ -0,0 +1,16 @@+.PHONY: clean++SHELL := bash+MAKEFLAGS += --warn-undefined-variables --no-builtin-rules -j+.DELETE_ON_ERROR:++setup: valgrind-3.15.0.tar++clean:+	rm -rf .stack-work dist-newstyle dist *.tar* *.hp *.prof stack.yaml.lock tags *.svg++valgrind-3.15.0.tar.bz2:+	wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 -O $@++valgrind-3.15.0.tar: valgrind-3.15.0.tar.bz2+	bzip2 -d $< --keep
README.md view
@@ -11,3 +11,9 @@   * Uses [c2hs](https://github.com/haskell/c2hs) rather than     [hsc2hs](https://hackage.haskell.org/package/hsc2hs) and thus has a larger     dependency footprint++## Backpack Integration++`bz2` implements+[`bzip-signature`](http://hackage.haskell.org/package/bzip-signature), which+makes it interchangeable with `bzlib`.
bench/Bench.hs view
@@ -3,7 +3,14 @@ import qualified Codec.Compression.BZip as BZ2 import           Criterion.Main import qualified Data.ByteString.Lazy   as BSL+import           System.FilePath        ((</>))+import           System.IO.Temp         (withSystemTempDirectory) +decompressDump :: IO ()+decompressDump = withSystemTempDirectory "bz2" $+    \fp -> BSL.writeFile (fp </> "valgrind-3.15.0.tar") =<<+        (BZ2.decompress <$> BSL.readFile "valgrind-3.15.0.tar.bz2")+ decompressFile :: FilePath -> IO BSL.ByteString decompressFile = fmap BZ2.decompress . BSL.readFile @@ -12,7 +19,9 @@  main :: IO () main =-    defaultMain [ bgroup "decompress"+    defaultMain [ bgroup "decompressDump"+                      [ bench "decompress + write to file" $ nfIO decompressDump ]+                , bgroup "decompress"                       [ bench "decompress file" $ nfIO (decompressFile "test/data/sample1.bz2")                       , bench "decompress file" $ nfIO (decompressFile "test/data/sample2.bz2")                       , bench "decompress file" $ nfIO (decompressFile "test/data/sample3.bz2")
bz2.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.18 name:               bz2-version:            0.1.1.1+version:            1.0.0.0 license:            BSD3 license-file:       LICENSE copyright:          Copyright: (c) 2020 Vanessa McHale@@ -19,7 +19,10 @@     test/data/sample2.bz2     test/data/sample3.bz2 -extra-source-files: cbits/bzlib_private.h+extra-source-files:+    cbits/bzlib_private.h+    Makefile+ extra-doc-files:     README.md     CHANGELOG.md@@ -34,10 +37,7 @@     manual:      True  library-    exposed-modules:-        Codec.Compression.BZip-        Codec.Compression.BZip.Foreign-+    exposed-modules:  Codec.Compression.BZip     c-sources:         cbits/bzlib.c         cbits/randtable.c@@ -49,12 +49,15 @@      hs-source-dirs:   src     other-modules:+        Codec.Compression.BZip.Foreign.Common+        Codec.Compression.BZip.Foreign.Compress+        Codec.Compression.BZip.Foreign.Decompress         Codec.Compression.BZip.Common         Codec.Compression.BZip.Unpack         Codec.Compression.BZip.Pack      default-language: Haskell2010-    other-extensions: DeriveDataTypeable+    other-extensions: DeriveDataTypeable TupleSections     include-dirs:     cbits     install-includes: cbits/bzlib.h     ghc-options:      -Wall@@ -86,7 +89,9 @@         filepath >=1.4.0.0,         tasty -any,         tasty-golden -any,-        tasty-hunit -any+        tasty-hunit -any,+        deepseq -any,+        directory -any      if impl(ghc >=8.0)         ghc-options:@@ -109,6 +114,8 @@         base -any,         bz2 -any,         criterion -any,+        filepath -any,+        temporary -any,         bytestring -any      if impl(ghc >=8.0)@@ -121,3 +128,19 @@      if impl(ghc >=8.2)         ghc-options: -Wcpp-undef++benchmark bz2-mem+    type:             exitcode-stdio-1.0+    main-is:          Mem.hs+    hs-source-dirs:   mem+    default-language: Haskell2010+    ghc-options:      -Wall+    build-depends:+        base -any,+        bz2 -any,+        filepath -any,+        temporary -any,+        bytestring -any++    if impl(ghc >=8.0)+        ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates
+ mem/Mem.hs view
@@ -0,0 +1,21 @@+module Main (main) where++import           Codec.Compression.BZip (compress, decompress)+import qualified Data.ByteString.Lazy   as BSL+import           System.FilePath        ((</>))+import           System.IO.Temp         (withSystemTempDirectory)++main :: IO ()+main =+    compressDump *>+    decompressDump++decompressDump :: IO ()+decompressDump = withSystemTempDirectory "bz2" $+    \fp -> BSL.writeFile (fp </> "valgrind-3.15.0.tar") =<<+        (decompress <$> BSL.readFile "valgrind-3.15.0.tar.bz2")++compressDump :: IO ()+compressDump = withSystemTempDirectory "bz2" $+    \fp -> BSL.writeFile (fp </> "valgrind-3.15.0.tar.bz2") =<<+        (compress <$> BSL.readFile "valgrind-3.15.0.tar")
src/Codec/Compression/BZip.hs view
@@ -5,10 +5,12 @@                                 compress                               , compressWith                               , decompress-                              -- * Low-level bindings-                              , module Codec.Compression.BZip.Foreign+                              -- * Errors+                              , BZError (..)+                              -- * Miscellany+                              , bZ2BzlibVersion                               ) where -import           Codec.Compression.BZip.Foreign+import           Codec.Compression.BZip.Foreign.Common import           Codec.Compression.BZip.Pack import           Codec.Compression.BZip.Unpack
src/Codec/Compression/BZip/Common.chs view
@@ -1,6 +1,6 @@ module Codec.Compression.BZip.Common ( bzStreamInit ) where -import Codec.Compression.BZip.Foreign (BzStream)+import Codec.Compression.BZip.Foreign.Common (BzStream) import Control.Applicative import Foreign.Ptr (nullFunPtr, nullPtr, Ptr) import Foreign.Marshal (mallocBytes)
− src/Codec/Compression/BZip/Foreign.chs
@@ -1,132 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}---- | This module uses exceptions behind the scenes------ Consult the upstream [documentation](https://www.sourceware.org/bzip2/docs.html) for how to use this library.------ For struct accessors, I recommend using [c2hs](http://hackage.haskell.org/package/c2hs).-module Codec.Compression.BZip.Foreign ( -- * Types-                                        BZAction (..)-                                      , BZError (..)-                                      , BzStream-                                      , BzStreamPtr-                                      , BzFile-                                      , BzFilePtr-                                      , FilePtr-                                      -- * Low-level functions-                                      , bZ2BzCompressInit-                                      , bZ2BzCompress-                                      , bZ2BzCompressEnd-                                      , bZ2BzDecompressInit-                                      , bZ2BzDecompress-                                      , bZ2BzDecompressEnd-                                      -- * High-level functions-                                      , bZ2BzReadOpen-                                      , bZ2BzReadClose-                                      , bZ2BzReadGetUnused-                                      , bZ2BzRead-                                      , bZ2BzWriteOpen-                                      , bZ2BzWrite-                                      , bZ2BzWriteClose-                                      , bZ2BzWriteClose64-                                      -- * Macros-                                      , bZMaxUnused-                                      -- * Utility functions-                                      , bZ2BzBuffToBuffCompress-                                      , bZ2BzBuffToBuffDecompress-                                      -- * Contributed functions-                                      , bZ2BzlibVersion-                                      ) where--import Control.Applicative-import Control.Exception (Exception, throw)-import Control.Monad ((<=<))-import Data.Typeable (Typeable)-import Foreign.C.Types (CInt, CUInt)-import Foreign.Marshal (alloca)-import Foreign.Ptr (castPtr, Ptr)-import Foreign.Storable (peek)--#include <bzlib.h>--{# enum define BZAction { BZ_RUN as BzRun-                        , BZ_FLUSH as BzFlush-                        , BZ_FINISH as BzFinish-                        }-  #}--{# enum define BZError { BZ_OK as BzOk-                       , BZ_RUN_OK as BzRunOk-                       , BZ_FLUSH_OK as BzFlushOk-                       , BZ_FINISH_OK as BzFinishOk-                       , BZ_STREAM_END as BzStreamEnd-                       , BZ_SEQUENCE_ERROR as BzSequenceError-                       , BZ_PARAM_ERROR as BzParamError-                       , BZ_MEM_ERROR as BzMemError-                       , BZ_DATA_ERROR as BzDataError-                       , BZ_DATA_ERROR_MAGIC as BzDataErrorMagic-                       , BZ_IO_ERROR as BzIoError-                       , BZ_UNEXPECTED_EOF as BzUnexpectedEof-                       , BZ_OUTBUFF_FULL as BzOutbuffFull-                       , BZ_CONFIG_ERROR as BzConfigError-                       } deriving (Eq, Show, Typeable)-  #}--instance Exception BZError where---- | Abstract type-data BzStream---- | Abstract type-data BzFile--{#pointer *bz_stream as BzStreamPtr -> BzStream #}--- | @FILE*@ in C.-{#pointer *FILE as FilePtr newtype #}-{#pointer *BZFILE as BzFilePtr -> BzFile #}---- Low-level functions-{# fun BZ2_bzCompressInit as ^ { `BzStreamPtr', `CInt', `CInt', `CInt' } -> `()' bzWrap*- #}-{# fun BZ2_bzCompress as ^ { `BzStreamPtr', `BZAction' } -> `BZError' bzWrap* #}-{# fun BZ2_bzCompressEnd as ^ { `BzStreamPtr' } -> `()' bzWrap*- #}-{# fun BZ2_bzDecompressInit as ^ { `BzStreamPtr', `CInt', `Bool' } -> `()' bzWrap*- #}-{# fun BZ2_bzDecompress as ^ { `BzStreamPtr' } -> `BZError' bzWrap* #}-{# fun BZ2_bzDecompressEnd as ^ { `BzStreamPtr' } -> `()' bzWrap*- #}---- High-level functions-{# fun BZ2_bzReadOpen as ^ { alloca- `BZError' peekBZError*, `FilePtr', `CInt', `Bool', castPtr `Ptr a', `CInt' } -> `BzFilePtr' #}-{# fun BZ2_bzReadClose as ^ { alloca- `BZError' peekBZError*, `BzFilePtr' } -> `()' #}-{# fun BZ2_bzReadGetUnused as ^ { alloca- `BZError' peekBZError*, `BzFilePtr', alloca- `Ptr a' peekVoidPtr*, alloca- `CInt' peek* } -> `()' #}-{# fun BZ2_bzRead as ^ { alloca- `BZError' peekBZError*, `BzFilePtr', castPtr `Ptr a', `CInt' } -> `CInt' #}-{# fun BZ2_bzWriteOpen as ^ { alloca- `BZError' peekBZError*, `FilePtr', `CInt', `CInt', `CInt' } -> `BzFilePtr' #}-{# fun BZ2_bzWrite as ^ { alloca- `BZError' peekBZError*, `BzFilePtr', castPtr `Ptr a', `CInt' } -> `()' #}-{# fun BZ2_bzWriteClose as ^ { alloca- `BZError' peekBZError*, `BzFilePtr', `Bool', alloca- `CUInt' peek*, alloca- `CUInt' peek* } -> `()' #}-{# fun BZ2_bzWriteClose64 as ^ { alloca- `BZError' peekBZError*, `BzFilePtr', `Bool', alloca- `CUInt' peek*, alloca- `CUInt' peek*, alloca- `CUInt' peek*, alloca- `CUInt' peek* } -> `()' #}---- Macros-bZMaxUnused :: Integral a => a-bZMaxUnused = {# const BZ_MAX_UNUSED #}---- Utility functions-{# fun BZ2_bzBuffToBuffCompress as ^ { castPtr `Ptr a', alloca- `CUInt' peek*, castPtr `Ptr a', `CUInt', `CInt', `CInt', `CInt' } -> `()' bzWrap*- #}-{# fun BZ2_bzBuffToBuffDecompress as ^ { castPtr `Ptr a', alloca- `CUInt' peek*, castPtr `Ptr a', `CUInt', `Bool', `CInt' } -> `BZError' bzWrap* #}---- Contributed functions-{# fun pure BZ2_bzlibVersion as ^ { } -> `String' #}--peekVoidPtr :: Ptr (Ptr ()) -> IO (Ptr a)-peekVoidPtr = fmap castPtr . peek--peekBZError :: Ptr CInt -> IO BZError-peekBZError = bzWrap <=< peek--bzWrap :: CInt -> IO BZError-bzWrap err =-    let err' = toEnum (fromIntegral err) in-    case err' of-        BzOk        -> pure err'-        BzRunOk     -> pure err'-        BzFlushOk   -> pure err'-        BzFinishOk  -> pure err'-        BzStreamEnd -> pure err'-        x           -> throw x
+ src/Codec/Compression/BZip/Foreign/Common.chs view
@@ -0,0 +1,60 @@+{-# LANGUAGE DeriveDataTypeable #-}++module Codec.Compression.BZip.Foreign.Common ( -- * Types+                                               BZAction (..)+                                             , BZError (..)+                                             , BzStream+                                             -- * Helper+                                             , bzWrap+                                             -- * Contributed functions+                                             , bZ2BzlibVersion+                                             ) where++import Control.Applicative+import Control.Exception (Exception, throw)+import Data.Typeable (Typeable)+import Foreign.C.Types (CInt)++#include <bzlib.h>++{# enum define BZAction { BZ_RUN as BzRun+                        , BZ_FLUSH as BzFlush+                        , BZ_FINISH as BzFinish+                        }+  #}++{# enum define BZError { BZ_OK as BzOk+                       , BZ_RUN_OK as BzRunOk+                       , BZ_FLUSH_OK as BzFlushOk+                       , BZ_FINISH_OK as BzFinishOk+                       , BZ_STREAM_END as BzStreamEnd+                       , BZ_SEQUENCE_ERROR as BzSequenceError+                       , BZ_PARAM_ERROR as BzParamError+                       , BZ_MEM_ERROR as BzMemError+                       , BZ_DATA_ERROR as BzDataError+                       , BZ_DATA_ERROR_MAGIC as BzDataErrorMagic+                       , BZ_IO_ERROR as BzIoError+                       , BZ_UNEXPECTED_EOF as BzUnexpectedEof+                       , BZ_OUTBUFF_FULL as BzOutbuffFull+                       , BZ_CONFIG_ERROR as BzConfigError+                       } deriving (Eq, Show, Typeable)+  #}++instance Exception BZError where++-- | Abstract type+data BzStream++-- Contributed functions+{# fun pure BZ2_bzlibVersion as ^ { } -> `String' #}++bzWrap :: CInt -> IO BZError+bzWrap err =+    let err' = toEnum (fromIntegral err) in+    case err' of+        BzOk        -> pure err'+        BzRunOk     -> pure err'+        BzFlushOk   -> pure err'+        BzFinishOk  -> pure err'+        BzStreamEnd -> pure err'+        x           -> throw x
+ src/Codec/Compression/BZip/Foreign/Compress.chs view
@@ -0,0 +1,16 @@+module Codec.Compression.BZip.Foreign.Compress ( bZ2BzCompressInit+                                               , bZ2BzCompress+                                               , bZ2BzCompressEnd+                                               , BzStreamPtr+                                               ) where++{# import Codec.Compression.BZip.Foreign.Common #}++import Foreign.C.Types (CInt)++#include <bzlib.h>++{#pointer *bz_stream as BzStreamPtr foreign finalizer BZ2_bzCompressEnd as ^ -> BzStream #}++{# fun BZ2_bzCompressInit as ^ { `BzStreamPtr', `CInt', `CInt', `CInt' } -> `()' bzWrap*- #}+{# fun BZ2_bzCompress as ^ { `BzStreamPtr', `BZAction' } -> `BZError' bzWrap* #}
+ src/Codec/Compression/BZip/Foreign/Decompress.chs view
@@ -0,0 +1,16 @@+module Codec.Compression.BZip.Foreign.Decompress ( bZ2BzDecompressInit+                                                 , bZ2BzDecompress+                                                 , bZ2BzDecompressEnd+                                                 , BzStreamPtr+                                                 ) where++{# import Codec.Compression.BZip.Foreign.Common #}++import Foreign.C.Types (CInt)++#include <bzlib.h>++{#pointer *bz_stream as BzStreamPtr foreign finalizer BZ2_bzDecompressEnd as ^ -> BzStream #}++{# fun BZ2_bzDecompressInit as ^ { `BzStreamPtr', `CInt', `Bool' } -> `()' bzWrap*- #}+{# fun BZ2_bzDecompress as ^ { `BzStreamPtr' } -> `BZError' bzWrap* #}
src/Codec/Compression/BZip/Pack.chs view
@@ -1,28 +1,30 @@+{-# LANGUAGE TupleSections #-}+ module Codec.Compression.BZip.Pack ( compress                                    , compressWith                                    ) where -import Codec.Compression.BZip.Foreign+import Codec.Compression.BZip.Foreign.Common+import Codec.Compression.BZip.Foreign.Compress import Codec.Compression.BZip.Common import Control.Applicative-import Control.Arrow (second)-import Control.Exception (bracket)+import Control.Monad.ST.Lazy as LazyST+import Control.Monad.ST.Lazy.Unsafe as LazyST import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Unsafe as BS import Foreign.C.Types (CInt)+import Foreign.ForeignPtr (castForeignPtr, ForeignPtr, newForeignPtr, mallocForeignPtrBytes, withForeignPtr) import Foreign.Ptr (Ptr, castPtr, nullPtr)-import Foreign.Marshal.Alloc (free, mallocBytes)-import System.IO.Unsafe (unsafeDupablePerformIO)  #include <bzlib.h> -{-# NOINLINE compress #-} -- | @since 0.1.1.0 compress :: BSL.ByteString -> BSL.ByteString compress = compressWith 9 30 -{-# NOINLINE compressWith #-}+type Step = Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])+ -- | See [bzlib manual](https://www.sourceware.org/bzip2/manual/manual.html#bzcompress-init) -- for information on compression parameters. --@@ -31,75 +33,90 @@              -> CInt -- ^ Work factor (@0-250@)              -> BSL.ByteString              -> BSL.ByteString-compressWith blkSize wf bsl = unsafeDupablePerformIO $+compressWith blkSize wf bsl =     let bss = BSL.toChunks bsl in-    BSL.fromChunks <$> bracket-        (do { p <- bzStreamInit ; bzCompressInit blkSize wf p ; pure p })-        bZ2BzCompressEnd-        (\p -> bzCompressChunks p bss)+    BSL.fromChunks $ LazyST.runST $ do+        (p, bufOut) <- LazyST.unsafeIOToST $ do+            ptr <- bzStreamInit+            p <- castForeignPtr <$> newForeignPtr bZ2BzCompressEnd (castPtr ptr)+            bzCompressInit blkSize wf p+            bufOut <- mallocForeignPtrBytes bufSz+            pure (p, bufOut) -bzCompressChunks :: Ptr BzStream -> [BS.ByteString] -> IO [BS.ByteString]-bzCompressChunks p bs =+        bzCompressChunks p bss bufOut -    bracket-        (mallocBytes bufSz)-        free-        (fmap snd . extractBuf bs)+bzCompressChunks :: ForeignPtr BzStream -> [BS.ByteString] -> ForeignPtr a -> LazyST.ST s [BS.ByteString]+bzCompressChunks ptr' bs bufO = do +    fillBuf ptr' Nothing bs pushBytes bufO+     where          -- corresponds to inner loop in zlib example-        fillBuf :: [BS.ByteString] -> BZAction -> Ptr a -> IO (BZError, [BS.ByteString])-        fillBuf bs' f bufOut = do+        fillBuf :: ForeignPtr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> Step -> ForeignPtr a -> LazyST.ST s [BS.ByteString]+        fillBuf pForeign passFwd bs' step bufOutForeign = do+            (ret, szOut, newBSAp, bs'', keepAlive) <- LazyST.unsafeIOToST $ do+                withForeignPtr pForeign $ \p ->+                    withForeignPtr bufOutForeign $ \bufOut -> do -            {# set bz_stream.avail_out #} p bufSz-            {# set bz_stream.next_out #} p (castPtr bufOut)+                        let act f = do -            ret <- bZ2BzCompress p f+                                {# set bz_stream.avail_out #} p bufSz+                                {# set bz_stream.next_out #} p (castPtr bufOut) -            szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p+                                bZ2BzCompress ptr' f -            let bytesAvail = bufSz - szOut+                        (ret, keepAlive, bs'') <- step p passFwd bs' act -            newBSAp <- if bytesAvail /= 0-                then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail)-                else pure id+                        szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p +                        let bytesAvail = bufSz - szOut++                        newBSAp <- if bytesAvail /= 0+                            then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail)+                            else pure id++                        pure (ret, szOut, newBSAp, bs'', keepAlive)++            let step' = if szOut == 0+                then keepBytesAlive+                else pushBytes+             if ret == BzStreamEnd-                then pure (ret, newBSAp [])-                else if szOut == 0-                    then second newBSAp <$> fillBuf bs' f bufOut-                    else second newBSAp <$> extractBuf bs' bufOut+                then pure (newBSAp [])+                else newBSAp <$> fillBuf pForeign keepAlive bs'' step' bufOutForeign -        -- corresponds to outer loop in zlib example-        extractBuf :: [BS.ByteString] -> Ptr a -> IO (BZError, [BS.ByteString])-        extractBuf [] bufOut = do+        keepBytesAlive :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])+        keepBytesAlive _ Nothing [] act = (, Nothing, []) <$> act BzFinish+        keepBytesAlive _ Nothing bs' act = (, Nothing, bs') <$> act BzRun+        keepBytesAlive _ passFwd@(Just b) [] act = do+            BS.unsafeUseAsCStringLen b $ \_ -> do -            (res, blocks) <- fillBuf [] BzFinish bufOut+                (, passFwd, []) <$> act BzFinish+        keepBytesAlive _ passFwd@(Just b) bs' act = do+            BS.unsafeUseAsCStringLen b $ \_ -> do -            if res == BzStreamEnd-                then pure (BzStreamEnd, blocks)-                else extractBuf [] bufOut+                (, passFwd, bs') <$> act BzRun -        extractBuf (b:bs') bufOut =+        pushBytes :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])+        pushBytes _ _ [] act = (, Nothing, []) <$> act BzFinish+        pushBytes p _ (b:bs') act =             BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do                  {# set bz_stream.avail_in #} p (fromIntegral sz)                 {# set bz_stream.next_in #} p buf -                (res, blocks) <- fillBuf bs' BzRun bufOut+                (, Just b, bs') <$> act BzRun -                if res == BzStreamEnd-                    then pure (BzStreamEnd, blocks)-                    else extractBuf bs' bufOut+bufSz :: Integral a => a+bufSz = 32 * 1024 -        bufSz :: Integral a => a-        bufSz = 32 * 1024+bzCompressInit :: CInt -> CInt -> ForeignPtr BzStream -> IO ()+bzCompressInit blkSize wf ptr' = do -bzCompressInit :: CInt -> CInt -> Ptr BzStream -> IO ()-bzCompressInit blkSize wf p = do+    withForeignPtr ptr' $ \p -> do -    {# set bz_stream.next_in #} p nullPtr-    {# set bz_stream.avail_in #} p 0+        {# set bz_stream.next_in #} p nullPtr+        {# set bz_stream.avail_in #} p 0 -    bZ2BzCompressInit p blkSize 0 wf+    bZ2BzCompressInit ptr' blkSize 0 wf
src/Codec/Compression/BZip/Unpack.chs view
@@ -1,99 +1,105 @@+{-# LANGUAGE TupleSections #-}+ module Codec.Compression.BZip.Unpack ( decompress                                      ) where -import Codec.Compression.BZip.Foreign+import Codec.Compression.BZip.Foreign.Common+import Codec.Compression.BZip.Foreign.Decompress import Codec.Compression.BZip.Common import Control.Applicative-import Control.Arrow (second)-import Control.Exception (bracket)+import Control.Monad.ST.Lazy as LazyST+import Control.Monad.ST.Lazy.Unsafe as LazyST import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Unsafe as BS+import qualified Data.ByteString.Lazy as BSL+import Foreign.ForeignPtr (newForeignPtr, castForeignPtr, ForeignPtr, mallocForeignPtrBytes, withForeignPtr) import Foreign.Ptr (Ptr, castPtr, nullPtr)-import Foreign.Marshal.Alloc (free, mallocBytes)-import System.IO.Unsafe (unsafeDupablePerformIO)  #include <bzlib.h> -{-# NOINLINE decompress #-} -- | Don't use this on pathological input; it may not be secure -- -- @since 0.1.1.0 decompress :: BSL.ByteString -> BSL.ByteString-decompress bsl = unsafeDupablePerformIO $+decompress bsl =     let bss = BSL.toChunks bsl in-    BSL.fromChunks <$> bracket-        (do { p <- bzStreamInit ; bzDecompressInit p ; pure p })-        bZ2BzDecompressEnd-        (\p -> bzDecompressChunks p bss)+    BSL.fromChunks $ LazyST.runST $ do+        (p, bufOut) <- LazyST.unsafeIOToST $ do+            ptr <- bzStreamInit+            p <- castForeignPtr <$> newForeignPtr bZ2BzDecompressEnd (castPtr ptr)+            bzDecompressInit p+            bufOut <- mallocForeignPtrBytes bufSz+            pure (p, bufOut) -bzDecompressChunks :: Ptr BzStream -> [BS.ByteString] -> IO [BS.ByteString]-bzDecompressChunks p bs =+        bzDecompressChunks p bss bufOut -    bracket-        (mallocBytes bufSz)-        free-        (fmap snd . extractBuf bs)+type Step = Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) +bzDecompressChunks :: ForeignPtr BzStream -> [BS.ByteString] -> ForeignPtr a -> LazyST.ST s [BS.ByteString]+bzDecompressChunks ptr' bs bufO =++    fillBuf ptr' Nothing bs pushBytes bufO+     where-        -        -- thing-to-cons-to (cdr) -> backward-traveling state (?)-        -- ret value -> forward-traveling state!-        -- stuff "remaining" to be fed in could be forward-traveling state ?-        -- -> [BS.ByteString] Writer + BZError state :p -        -- corresponds to inner loop in zlib example-        fillBuf :: [BS.ByteString] -> Ptr a -> IO (BZError, [BS.ByteString])-        fillBuf bs' bufOut = do+        fillBuf :: ForeignPtr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> Step -> ForeignPtr a -> LazyST.ST s [BS.ByteString]+        fillBuf pForeign passFwd bs' step bufOutForeign = do+            (ret, szOut, newBSAp, bs'', keepAlive) <- LazyST.unsafeIOToST $ do+                withForeignPtr pForeign $ \p ->+                    withForeignPtr bufOutForeign $ \bufOut -> do -            {# set bz_stream.avail_out #} p bufSz-            {# set bz_stream.next_out #} p (castPtr bufOut)+                            let act = do -            ret <- bZ2BzDecompress p+                                    {# set bz_stream.avail_out #} p bufSz+                                    {# set bz_stream.next_out #} p (castPtr bufOut) -            szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p+                                    bZ2BzDecompress ptr' -            let bytesAvail = bufSz - szOut+                            (ret, keepAlive, bs'') <- step p passFwd bs' act -            newBSAp <- if bytesAvail /= 0-                then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail)-                else pure id+                            szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p -            if ret == BzStreamEnd-                then pure (ret, newBSAp [])-                else if szOut == 0-                    then second newBSAp <$> fillBuf bs' bufOut-                    else second newBSAp <$> extractBuf bs' bufOut+                            let bytesAvail = bufSz - szOut -        -- corresponds to outer loop in zlib example-        extractBuf :: [BS.ByteString] -> Ptr a -> IO (BZError, [BS.ByteString])-        extractBuf [] bufOut = do+                            newBSAp <- if bytesAvail /= 0+                                then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail)+                                else pure id -            (res, blocks) <- fillBuf [] bufOut+                            pure (ret, szOut, newBSAp, bs'', keepAlive) -            if res == BzStreamEnd-                then pure (BzStreamEnd, blocks)-                else extractBuf [] bufOut+            let step' = if szOut == 0+                then keepBytesAlive+                else pushBytes -        extractBuf (b:bs') bufOut =+            if ret == BzStreamEnd+                then pure (newBSAp [])+                else newBSAp <$> fillBuf pForeign keepAlive bs'' step' bufOutForeign++        keepBytesAlive :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])+        keepBytesAlive _ Nothing bs' act = (, Nothing, bs') <$> act+        keepBytesAlive _ passFwd@(Just b) bs' act = do+            BS.unsafeUseAsCStringLen b $ \_ -> do++                (, passFwd, bs') <$> act++        pushBytes :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])+        pushBytes _ _ [] act = (, Nothing, []) <$> act+        pushBytes p _ (b:bs') act =             BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do                  {# set bz_stream.avail_in #} p (fromIntegral sz)                 {# set bz_stream.next_in #} p buf -                (res, blocks) <- fillBuf bs' bufOut--                if res == BzStreamEnd-                    then pure (BzStreamEnd, blocks)-                    else extractBuf bs' bufOut+                (, Just b, bs') <$> act -        bufSz :: Integral a => a-        bufSz = 32 * 1024+bufSz :: Integral a => a+bufSz = 32 * 1024 -bzDecompressInit :: Ptr BzStream -> IO ()-bzDecompressInit p = do+bzDecompressInit :: ForeignPtr BzStream -> IO ()+bzDecompressInit ptr' = do -    {# set bz_stream.next_in #} p nullPtr-    {# set bz_stream.avail_in #} p 0+    withForeignPtr ptr' $ \p -> do+        {# set bz_stream.next_in #} p nullPtr+        {# set bz_stream.avail_in #} p 0 -    bZ2BzDecompressInit p 0 False+    bZ2BzDecompressInit ptr' 0 False
test/Spec.hs view
@@ -1,7 +1,9 @@ module Main (main) where  import           Codec.Compression.BZip+import           Control.DeepSeq        (deepseq) import qualified Data.ByteString.Lazy   as BSL+import           System.Directory       (doesFileExist) import           System.FilePath        ((-<.>)) import           Test.Tasty import           Test.Tasty.Golden@@ -17,8 +19,29 @@     let actual = decompress (compress contents)     actual @?= contents +testValgrind :: TestTree+testValgrind = testCase "Unpack valgrind" $ do+    contents <- BSL.readFile "valgrind-3.15.0.tar.bz2"+    let actual = decompress contents+    assertBool "Unpacks w/o error" (actual `deepseq` True)++testValgrindPack :: TestTree+testValgrindPack = testCase "Pack valgrind" $ do+    contents <- BSL.readFile "valgrind-3.15.0.tar"+    let actual = compress contents+    assertBool "Packs w/o error" (actual `deepseq` True)+ main :: IO ()-main = defaultMain (testGroup "bz2" [testDecompression, testCompression])+main = do+    valgrind <- (&&) <$> doesFileExist "valgrind-3.15.0.tar.bz2" <*> doesFileExist "valgrind-3.15.0.tar"+    let go =+            if valgrind+                then (testValgrind:) . (testValgrindPack:)+                else id++    defaultMain $+        testGroup "bz2" (go [testDecompression, testCompression])+     where         testDecompression = testGroup "Decompress"             [ testDecompress "test/data/sample1.bz2"