データの圧縮と展開
Posted feedbacks - Haskell
Win32にはLZExpand.hというAPIセットがあります。これはLZWコンプレスされたファイルの中身にアクセスするAPIなのですが、実はコンプレスをするAPIがついてきていません。じゃぁ、どうやってコンプレスするのかというと、どうやら、そこはcompress.exeというツールを使ってくれということのようです。
ですので、今回はCompress.exeでファイルを圧縮して、それを解凍するコードを書いてみました。
LZExpandのAPIをインポートするFFI宣言がなかったので、そっからやってみました。
ビルドのときはLZExpandが入っているlz32.libを追加リンクモジュールとして指定してやる必要があります。
GHC 6.10.1でやりました。
動いただけでびっくりです。はい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | {-
ghc --make compr.hs -fglasgow-exts -o compr.exe -llz32 -L%LIBDIR%
-}
module Main where
import Foreign
import System.Cmd
import System.Win32.Types
import Control.Exception
oF_READ = 0 :: WORD
oF_CREATE = 0x1000 :: WORD
lZERROR_BADINHANDLE = -1 ::INT
lZERROR_GLOBALLOC = -5 ::INT
lZERROR_BADOUTHANDLE = -2 ::INT
lZERROR_READ = -3 ::INT
lZERROR_WRITE = -4 ::INT
lZERROR_GLOBLOCK = -6 ::INT
lZERROR_BADVALUE = -7 ::INT
lZERROR_UNKNOWNALG = -8 ::INT
type LPOFSTRUCT = Addr
withOFStruct :: (LPOFSTRUCT -> IO a) -> IO a
withOFStruct f =
allocaBytes (136) $ \ p -> do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) p (136::BYTE)
f p
lZOpenFile :: String -> WORD -> IO INT
lZOpenFile str wd = do
c_fnm <- newTString str
h <- failIf (err) "LZOpenFile" $
withOFStruct (\ofs -> c_LZOpenFile c_fnm ofs wd)
return h
where
err i = (i == lZERROR_BADINHANDLE) ||
(i == lZERROR_GLOBALLOC)
foreign import stdcall unsafe "lzExpand.h LZOpenFileW"
c_LZOpenFile :: LPCTSTR -> LPOFSTRUCT -> WORD -> IO INT
foreign import stdcall unsafe "lzExpand.h LZClose"
lZClose :: INT -> IO ()
lZCopy :: INT -> INT -> IO ()
lZCopy r w = do
failIf (err) "LZCopy" (c_LzCopy r w)
return ()
where
err i = (i == lZERROR_BADINHANDLE) ||
(i == lZERROR_BADOUTHANDLE) ||
(i == lZERROR_GLOBLOCK) ||
(i == lZERROR_READ) ||
(i == lZERROR_GLOBALLOC)
foreign import stdcall unsafe "lzExpand.h LZCopy"
c_LzCopy :: INT -> INT -> IO LONG
withLZHandle :: (INT -> IO ()) -> INT -> IO ()
withLZHandle f i = do
finally (f i) $ lZClose I
compress :: String -> String -> IO()
compress fnmR fnmW = do
system $ "compress " ++ fnmR ++ " " ++ fnmW
return ()
uncompress :: String -> String -> IO()
uncompress fnmR fnmW = do
lZOpenFile fnmR oF_READ >>= withLZHandle (\r ->
lZOpenFile fnmW oF_CREATE >>= withLZHandle (\w ->
lZCopy r w))
main = do
system "echo > foo"
compress "foo" "bar"
uncompress "bar" "baz"
|

mattsan
#8262()
Rating1/5=0.20
データを圧縮するcompress、展開するdecompressという関数やメソッドなどを書いてください。データはバイト列でもストリームでもそれ以外の形式でもOKです。
圧縮形式は問いませんが、できるだけ一般的なフォーマット(zip,lzhなど)でお願いします。
また、標準以外のライブラリを使う場合には出典の記載をお願いします。
「○○でも実用的な圧縮/展開プログラムがかけるんだぞ!」というのを、ぜひ示してください。
[ reply ]