module Codec.Compression.LZF (compress,decompress,compressString,decompressString) where
import Data.Char(ord,chr)
import Control.Monad (when)
import Foreign
import Foreign.C
{-# CFILES liblzf-1.5/lzf_c.c liblzf-1.5/lzf_d.c #-}
foreign import ccall unsafe "lzf_compress" _compress :: Ptr a -> CUInt -> Ptr b -> CUInt -> IO CUInt
foreign import ccall unsafe "lzf_decompress" _decompress :: Ptr a -> CUInt -> Ptr b -> CUInt -> IO CUInt
-- | Compress a block of data. The length of data is
-- not recorded. Returns the length of output or 0
-- if it is longer than the size of the output buffer.
compress :: Ptr a -> Int -> Ptr b -> Int -> IO Int
compress input ilen output olen = do
res <- _compress input (fromIntegral ilen) output (fromIntegral olen)
return (fromIntegral res)
-- | Decompress a block of data. Returns the length
-- of data uncompressed or 0 on error.
decompress :: Ptr a -> Int -> Ptr b -> Int -> IO Int
decompress input ilen output olen = do
res <- _decompress input (fromIntegral ilen) output (fromIntegral olen)
return (fromIntegral res)
-- | Compress a string with worst case length = original + 1.
-- The first char of the string contains the length of the original.
compressString :: String -> IO String
compressString str =
withCStringLen str $ \(inp,len) ->
allocaBytes len $ \out -> do
res <- compress inp len out (len-2)
if res == 0 then return ("\0"++str)
else do c <- peekCStringLen (out,res)
return (chr len:c)
-- | Decompress a string compressed with compressString.
decompressString :: String -> IO String
decompressString ('\0':rest) = return rest
decompressString (ol:str) =
withCStringLen str $ \(inp,len) -> do
let olen = ord ol
allocaBytes olen $ \out -> do
res <- decompress inp len out olen
when (res == 0) $ fail "Codec.Compression.LZF.decompressString"
peekCStringLen (out,res)
{-
t s = do c <- compressString s
d <- decompressString c
putStrLn $ unwords ["lzf test",show $ length s,"=>",show $ length c,show (s==d)]
-}