challenge データの圧縮と展開

データを圧縮するcompress、展開するdecompressという関数やメソッドなどを書いてください。データはバイト列でもストリームでもそれ以外の形式でもOKです。

圧縮形式は問いませんが、できるだけ一般的なフォーマット(zip,lzhなど)でお願いします。

また、標準以外のライブラリを使う場合には出典の記載をお願いします。

「○○でも実用的な圧縮/展開プログラムがかけるんだぞ!」というのを、ぜひ示してください。

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"

Index

Feed

Other

Link

Pathtraq

loading...