zlib binding providing Handle to compressed file.

David Roundy droundy at abridgegame.org
Sun Sep 14 19:52:59 EDT 2003


I've just created a binding to the gzopen function of zlib which causes it
to create a Handle.  The code currently only supports ReadMode and
WriteMode, and hFileSize won't work properly when reading a file.  In fact,
pretty much nothing but plain old reading and writing will work, but such
is life.

Anyhow in case anyone is interested, I'm attaching the code.  It creates a
pipe using pipe(2) and spawns a thread to pass the data between the pipe
and gzread or gzwrite.  It's not pretty, but it's better than any other
solution I could think of.  Suggestions or criticisms are welcome.
-- 
David Roundy
http://www.abridgegame.org/darcs
-------------- next part --------------
\begin{code}
module Zlib ( gzOpenFile, gzWriteFile, gzReadFile ) where

import IO
import System.IO ( hGetBuf, hPutBuf )
import Control.Concurrent ( forkIO )
import Monad ( when )
import Foreign.C.String ( CString, withCString )
import Foreign.Marshal.Array ( mallocArray, withArray, peekArray )
import Foreign.Marshal.Alloc ( free )
import Foreign.Ptr ( Ptr )
import Data.Word
import GHC.Handle ( openFd )

fdToReadHandle fd fn = openFd fd Nothing fn ReadMode False False
fdToWriteHandle fd fn = openFd fd Nothing fn WriteMode False False

gzOpenFile :: FilePath -> IOMode -> IO Handle
gzWriteFile :: FilePath -> String -> IO ()

gzOpenFile f ReadMode = 
    withCString f $ \fstr -> withCString "rb" $ \rb-> do
    gzf <- c_gzopen fstr rb
    withArray [0,0] $ \fds -> do
      err <- c_pipe fds
      when (err /= 0) $ error "Pipe problem!"
      [infd,outfd] <- peekArray 2 fds
      writeH <- fdToWriteHandle (fromIntegral outfd) f
      buf <- mallocArray 1024
      forkIO $ gzreader gzf writeH buf
      fdToReadHandle (fromIntegral infd) f
          where gzreader gzf h buf =
                    do done <- hIsClosed h
                       if done
                          then do c_gzclose gzf
                                  free buf
                                  hClose h
                          else do l <- c_gzread gzf buf 1024
                                  hPutBuf h buf l
                                  if l < 1024
                                     then do free buf
                                             c_gzclose gzf
                                             hClose h
                                     else gzreader gzf h buf
gzOpenFile f WriteMode = 
    withCString f $ \fstr -> withCString "wb" $ \wb-> do
    gzf <- c_gzopen fstr wb
    withArray [0,0] $ \fds -> do
      err <- c_pipe fds
      when (err /= 0) $ error "Pipe problem!"
      [infd,outfd] <- peekArray 2 fds
      readH <- fdToReadHandle (fromIntegral infd) f
      buf <- mallocArray 1024
      forkIO $ gzwriter gzf readH buf
      fdToWriteHandle (fromIntegral outfd) f
          where gzwriter gzf h buf =
                    do done <- hIsEOF h
                       if done
                          then do c_gzclose gzf
                                  free buf
                                  hClose h
                          else do l <- hGetBuf h buf 1024
                                  c_gzwrite gzf buf l
                                  gzwriter gzf h buf

gzWriteFile f s = do h <- gzOpenFile f WriteMode
                     hPutStr h s
                     hClose h

gzReadFile f s = do h <- gzOpenFile f WriteMode
                    hGetContents h

foreign import ccall unsafe "static unistd.h pipe" c_pipe
    :: Ptr Int -> IO Int
foreign import ccall unsafe "static unistd.h read" c_read
    :: Ptr Word8 -> Int -> IO Int

foreign import ccall unsafe "static zlib.h gzopen" c_gzopen
    :: CString -> CString -> IO (Ptr ())
foreign import ccall unsafe "static zlib.h gzclose" c_gzclose
    :: Ptr () -> IO ()
foreign import ccall unsafe "static zlib.h gzread" c_gzread
    :: Ptr () -> Ptr Word8 -> Int -> IO Int
foreign import ccall unsafe "static zlib.h gzwrite" c_gzwrite
    :: Ptr () -> Ptr Word8 -> Int -> IO ()
\end{code}


More information about the Haskell-Cafe mailing list