sak-0.1.3.0: src/Compression.cpphs
module Compression ( Compression (..)
, detectCompression
, toCompressor
, toDecompressor
, toFileCompressor
, toFileDecompressor
, uncompressedExt
, check
, ext
-- * Utilities
, fileSize
) where
#ifdef BROTLI
import qualified Codec.Compression.Brotli as Br
#endif
import qualified Codec.Compression.BZip as BZip
import qualified Codec.Compression.GZip as GZip
import qualified Codec.Compression.Lzma as Lzma
import qualified Codec.Compression.Lzo as Lzo
#ifdef SNAPPY
import qualified Codec.Compression.Snappy.BSL as Snappy
#endif
import qualified Codec.Compression.Zlib as Zlib
import qualified Codec.Compression.Zstd.Lazy as Zstd
import qualified Codec.Lz4 as Lz4
import qualified Codec.Lzip as Lzip
import Compression.Level
import Compression.Type
import qualified Data.ByteString.Lazy as BSL
import Data.List (isSuffixOf)
import System.FilePath (dropExtension, (-<.>))
import System.IO (IOMode (ReadMode), hFileSize, withFile)
ext :: Compression -> String
ext Lzma = ".xz"
ext Lzip = ".lz"
ext BZip = ".bz2"
ext GZip = ".gz"
ext Zstd = ".zst"
ext Lz4 = ".lz4"
ext Z = ".Z"
#ifdef BROTLI
ext Brotli = ".br"
#endif
#ifdef SNAPPY
ext Snappy = ".sz"
#endif
ext Lzo = ".lzo"
ext None = ""
uncompressedExt :: FilePath -> FilePath
uncompressedExt fp | ".tlz" `isSuffixOf` fp = fp -<.> ".tar"
| ".txz" `isSuffixOf` fp = fp -<.> ".tar"
| ".tlz4" `isSuffixOf` fp = fp -<.> ".tar"
| ".tgz" `isSuffixOf` fp = fp -<.> ".tar"
| ".cpgz" `isSuffixOf` fp = fp -<.> ".cpio"
| ".cpbz2" `isSuffixOf` fp = fp -<.> ".cpio"
| ".xcfgz" `isSuffixOf` fp = fp -<.> ".xcf"
| ".xcfbz2" `isSuffixOf` fp = fp -<.> ".xcf"
| ".tbz2" `isSuffixOf` fp = fp -<.> "tar"
| ".tbz" `isSuffixOf` fp = fp -<.> "tar"
| ".tbr" `isSuffixOf` fp = fp -<.> "tar"
| ".tsz" `isSuffixOf` fp = fp -<.> "tar"
| ".tzo" `isSuffixOf` fp = fp -<.> "tar"
| otherwise = dropExtension fp
detectCompression :: FilePath -> Compression
detectCompression fp
| ".xz" `isSuffixOf` fp = Lzma
| ".lzma" `isSuffixOf` fp = Lzma
| ".txz" `isSuffixOf` fp = Lzma
| ".lz" `isSuffixOf` fp = Lzip
| ".tlz" `isSuffixOf` fp = Lzip
| ".tbz2" `isSuffixOf` fp = BZip
| ".tbz" `isSuffixOf` fp = BZip
| ".bz2" `isSuffixOf` fp = BZip
| ".gz" `isSuffixOf` fp = GZip
| ".tgz" `isSuffixOf` fp = GZip
| ".Z" `isSuffixOf` fp = Z
| ".zst" `isSuffixOf` fp = Zstd
| ".lz4" `isSuffixOf` fp = Lz4
| ".xcfgz" `isSuffixOf` fp = GZip
| ".xcfbz2" `isSuffixOf` fp = BZip
| ".cpgz" `isSuffixOf` fp = GZip
| ".cpbz2" `isSuffixOf` fp = BZip
#ifdef BROTLI
| ".br" `isSuffixOf` fp = Brotli
#endif
#ifdef SNAPPY
| ".sz" `isSuffixOf` fp = Snappy
#endif
| ".lzo" `isSuffixOf` fp = Lzo
| ".tzo" `isSuffixOf` fp = Lzo
| ".lrz" `isSuffixOf` fp = Lrzip
| otherwise = None -- error "Suffix not supported or invalid"
toFileDecompressor :: Compression -> FilePath -> IO BSL.ByteString
toFileDecompressor Lz4 = lz4DecompressFile
toFileDecompressor x = fmap (toDecompressor x) . BSL.readFile
toDecompressor :: Compression -> BSL.ByteString -> BSL.ByteString
toDecompressor Lzma = Lzma.decompress
toDecompressor Lzip = Lzip.decompress
toDecompressor BZip = BZip.decompress
toDecompressor GZip = GZip.decompress
toDecompressor Z = Zlib.decompress
toDecompressor Zstd = Zstd.decompress
toDecompressor Lz4 = Lz4.decompress
#ifdef BROTLI
toDecompressor Brotli = Br.decompress
#endif
#ifdef SNAPPY
toDecompressor Snappy = Snappy.decompress
#endif
toDecompressor Lzo = Lzo.decompressFile
toDecompressor None = id
check :: Compression -> BSL.ByteString -> IO ()
check = (forceBSL .) . toDecompressor
fileSize :: FilePath -> IO Integer
fileSize fp = withFile fp ReadMode hFileSize
lz4DecompressFile :: FilePath -> IO BSL.ByteString
lz4DecompressFile fp = do
fSz <- fileSize fp
let f = if fSz <= 32 * 1024
then Lz4.decompressBufSz (32 * 1024)
else Lz4.decompressBufSz (128 * 1024)
f <$> BSL.readFile fp
forceBSL :: BSL.ByteString -> IO ()
forceBSL bsl = last (BSL.toChunks bsl) `seq` mempty