packages feed

zstd-0.1.0.0: examples/low-level/DictionaryCompression.hs

module Main (main) where

import Codec.Compression.Zstd.Efficient
import Control.Monad (forM_)
import System.Environment (getArgs, getProgName)
import System.Exit (exitFailure)
import System.FilePath (addExtension, splitExtension)
import System.IO (hPutStrLn, stderr)
import qualified Data.ByteString as B

main :: IO ()
main = do
  args <- getArgs
  case args of
    "-c":dictName:files -> do
      dict <- (createCDict 3 . mkDict) <$> B.readFile dictName
      compress dict files
    "-d":dictName:files -> do
      dict <- (createDDict . mkDict) <$> B.readFile dictName
      decompress dict files
    "-t":dictSize:dictName:files ->
      case reads dictSize of
        [(size,['k'])] -> train (size * 1024) dictName files
        [(size,['m'])] -> train (size * 1048576) dictName files
        [(size,"")]    -> train size dictName files
        _           -> do
          program <- getProgName
          hPutStrLn stderr $ "usage: " ++ program ++ " -t SIZE DICT [FILES]"
          exitFailure
    _ -> do
      program <- getProgName
      hPutStrLn stderr $ "usage: " ++ program ++ " -[cdt] ARGS"
      exitFailure

compress :: CDict -> [FilePath] -> IO ()
compress dict files = do
  withCCtx $ \ctx ->
    forM_ files $ \file -> do
      content <- compressUsingCDict ctx dict =<< B.readFile file
      B.writeFile (addExtension file "zst") content

decompress :: DDict -> [FilePath] -> IO ()
decompress dict files = do
  withDCtx $ \ctx ->
    forM_ files $ \file -> do
      result <- decompressUsingDDict ctx dict =<< B.readFile file
      let newFile = case splitExtension file of
            (prefix,"zst") -> prefix
            _              -> addExtension file "dzst"
      case result of
        Skip          -> hPutStrLn stderr ("NOTE: skipping " ++ file)
        Error desc    -> hPutStrLn stderr ("ERROR (" ++ file ++ "): " ++ desc)
        Decompress bs -> B.writeFile newFile bs

train :: Int -> FilePath -> [FilePath] -> IO ()
train size dictName files = do
  md <- trainFromSamples size <$> mapM B.readFile files
  case md of
    Left err -> do
      hPutStrLn stderr ("ERROR: " ++ err)
      exitFailure
    Right dict -> B.writeFile dictName (fromDict dict)