Commits

Sergey Astanin  committed 86380ec

Update bindings and high-level interface for libzip == 0.10.

libzip 0.10 has changed some structures and is not binary compatible
with libzip 0.9. Now it uses uint64_t almost everywhere for size and
position (high-level Haskell bindings now use Integer instead of
Int). libzip 0.10 now also supports encryption (not yet supported by
high-level Haskell bindings).

Major changes:

* Re-write low-level bindings according to new libzip 0.10 API
* Use Integer for size and position instead of Int
* Legacy 0.0 API of the library has been removed.
* Depend on libzip == 0.10 to avoid broken library in the future
* New version numbers: the first two numbers to coincide with the
corresponding libzip version (hence, 0.10); both for bindings-libzip
and high-level LibZip packages.

  • Participants
  • Parent commits 43d47e6
  • Branches 0.10-bindings-libzip
  • Tags 0.10

Comments (0)

Files changed (13)

 LibZip/dist
 bindings-libzip/dist
 *.hpc
+bindings-libzip/cabal-dev*
+LibZip/cabal-dev*

File LibZip/Codec/Archive/LibZip.hs

 import Data.Time.Clock (UTCTime, getCurrentTime)
 import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
 import Data.Word (Word8)
+import Control.Monad (when)
 import Control.Monad.State.Strict
     (StateT(..), MonadState(..), MonadTrans(..), lift, liftM)
 import Foreign.C.Error (Errno(..), eINVAL)
 import Foreign.C.String (withCString, withCStringLen, peekCString)
-import Foreign.C.Types (CInt, CSize)
+import Foreign.C.Types (CInt, CULLong)
 import Foreign.Marshal.Alloc (alloca)
 import Foreign.Marshal.Array (allocaArray, peekArray, withArrayLen, pokeArray)
 import Foreign.Marshal.Utils (with)
 -- | Monadic computation to read from open archive entries.
 -- See 'fromFile' and 'fromFileIx'.
 type Entry a = StateT
-    (ZipFile,Int,[FileFlag])   -- (file, position index, access flags)
-    (StateT Zip IO)            -- archive monad
+    (ZipFile,Integer,[FileFlag])   -- (file, position index, access flags)
+    (StateT Zip IO)                -- archive monad
     a
 
 --
         else return r
 
 -- | Get the number of entries in the archive.
-numFiles :: Archive Int
-numFiles = do
+numFiles :: [FileFlag] -> Archive Integer
+numFiles flags  = do
   z <- getZip
-  lift $ fromIntegral `liftM` c'zip_get_num_files z
+  lift $ fromIntegral `liftM` c'zip_get_num_entries z (combine flags)
 
 -- | Get name of an entry in the archive by its index.
 fileName :: [FileFlag]  -- ^ 'FileUNCHANGED' flag can be used.
-         -> Int         -- ^ Position index of a file in the archive.
+         -> Integer     -- ^ Position index of a file in the archive.
          -> Archive FilePath  -- ^ Name of the file in the archive.
 fileName flags i = do
   z <- getZip
 -- | Locate an entry (get its index) in the archive by its name.
 nameLocate :: [FileFlag]  -- ^ Filename lookup mode.
            -> FilePath    -- ^ Name of the file in the archive.
-           -> Archive (Maybe Int)  -- ^ 'Just' position index if found.
+           -> Archive (Maybe Integer)  -- ^ 'Just' position index if found.
 nameLocate flags name = do
   z <- getZip
   lift $
 fileNames :: [FileFlag]  -- ^ 'FileUNCHANGED' flag is accepted.
           -> Archive [FilePath]
 fileNames flags = do
-  n <- numFiles
+  n <- numFiles flags
   mapM (fileName flags) [0..n-1]
 
 -- | Get size of a file in the archive.
 fileSize :: [FileFlag]  -- ^ Filename lookup mode, 'FileUNCHANGED' can be used.
          -> FilePath    -- ^ Name of the file in the archive.
-         -> Archive Int -- ^ File size.
+         -> Archive Integer -- ^ File size.
 fileSize flags name = fileStat flags name >>= return . zs'size
 
 -- | Get size of a file in the archive (by index).
 fileSizeIx :: [FileFlag]  -- ^ 'FileUNCHANGED' is accepted.
-           -> Int         -- ^ Position index of a file in the archive.
-           -> Archive Int -- ^ File size.
+           -> Integer     -- ^ Position index of a file in the archive.
+           -> Archive Integer -- ^ File size.
 fileSizeIx flags i = fileStatIx flags i >>= return . zs'size
 
 -- | Get information about a file in the archive.
 
 -- | Get information about a file in the archive (by index).
 fileStatIx :: [FileFlag]  -- ^ 'FileUNCHANGED' can be used.
-           -> Int         -- ^ Position index of a file in the archive.
+           -> Integer     -- ^ Position index of a file in the archive.
            -> Archive ZipStat  -- ^ Information about the file.
 fileStatIx flags i = do
   z <- getZip
   maybe (lift $ E.throwIO ErrNOENT) deleteFileIx mbi
 
 -- | Delete file (referenced by position index) from the archive.
-deleteFileIx :: Int  -- ^ Position index of a file in the archive.
+deleteFileIx :: Integer  -- ^ Position index of a file in the archive.
              -> Archive ()
 deleteFileIx i = do
   z <- getZip
   maybe (lift $ E.throwIO ErrNOENT) (\i -> renameFileIx i newname) mbi
 
 -- | Rename file (referenced by position index) in the archive.
-renameFileIx :: Int  -- ^ Position index of a file in the archive.
+renameFileIx :: Integer  -- ^ Position index of a file in the archive.
              -> FilePath -- ^ New name.
              -> Archive ()
 renameFileIx i newname = do
         (\i -> replaceFileIx i src >> return ()) mbi
 
 -- | Replace a file in the archive (referenced by position index).
-replaceFileIx :: Int       -- ^ Position index of a file in the archive.
+replaceFileIx :: Integer   -- ^ Position index of a file in the archive.
               -> ZipSource -- ^ Source where the new file data is obtained from
               -> Archive ()
 replaceFileIx i src = do
 
 -- | Create a data source from a file.
 sourceFile :: FilePath   -- ^ File to open.
-           -> Int        -- ^ Offset from the beginning of the file.
-           -> Int        -- ^ The number of bytes to read. If @0@ or @-1@,
+           -> Integer    -- ^ Offset from the beginning of the file.
+           -> Integer    -- ^ The number of bytes to read. If @0@ or @-1@,
                          -- the read till the end of file.
            -> Archive ZipSource
 sourceFile name offset len = do
 -- | Create a data source from a file in the zip archive.
 sourceZip :: [FileFlag]  -- ^ 'FileUNCHANGED' and 'FileRECOMPRESS' can be used.
           -> Zip         -- ^ Source archive.
-          -> Int         -- ^ Position index of a file in the source archive.
-          -> Int         -- ^ Offset from the beginning of the file.
-          -> Int         -- ^ The number of bytes to read. If @0@ or @-1@,
+          -> Integer     -- ^ Position index of a file in the source archive.
+          -> Integer     -- ^ Offset from the beginning of the file.
+          -> Integer     -- ^ The number of bytes to read. If @0@ or @-1@,
                          -- then read till the end of file.
           -> Archive ZipSource
 sourceZip flags srcz srcidx offset len = do
 
 -- | Create a data source from a 'PureSource'.
 -- Note: input of @[a]@ is converted to @[Word8]@ internally.
-sourcePure :: (Enum a, Storable a, Storable st)
-           => PureSource a st -> Archive ZipSource
+sourcePure :: (Enum a, Storable a, Storable st, Integral szt)
+           => PureSource a st szt -> Archive ZipSource
 sourcePure pureSrc = do
   z <- getZip
   lift $ do
 -- | Wrapper for a user-provided pure function to be used with 'sourcePure'.
 -- Data size should be known in advance ('srcSize').
 -- The function should support reading by chunks ('readSrc').
-data PureSource a st = PureSource {
-    srcState :: st   -- ^ Initial state of the source.
-  , srcSize  :: Int  -- ^ Total size of the data.
-  , srcMTime :: Maybe UTCTime  -- ^ Modification time (current time if Nothing).
-  , readSrc  :: Int -> st -> Maybe (Int, [a], st) -- ^ Read a chunk of the data,
-                -- return @Just@ the size of data read, the data themselves and
-                -- the new state of the source, or @Nothing@ on error.
+data PureSource a st szt = PureSource {
+    srcState :: st     -- ^ Initial state of the source.
+  , srcSize  :: szt    -- ^ Total size of the data.
+  , srcMTime :: Maybe UTCTime
+                -- ^ Modification time (current time if Nothing).
+  , readSrc  :: szt -> st -> Maybe (szt, [a], st)
+                -- ^ Read a chunk of the data, return @Just@ the size
+                -- of data read, the data themselves and the new state
+                -- of the source, or @Nothing@ on error.
   }
 
-runPureSource :: (Enum a, Storable a, Storable st)
-              => PureSource a st
-              -> (Ptr () -> Ptr () -> CSize -> C'zip_source_cmd -> IO CSize)
+runPureSource :: (Enum a, Storable a, Storable st, Integral szt) =>
+       PureSource a st szt
+    -> (Ptr () -> Ptr () -> CULLong -> C'zip_source_cmd -> IO CULLong)
 runPureSource src pState pData len cmd
   | cmd == c'ZIP_SOURCE_OPEN = return 0
   | cmd == c'ZIP_SOURCE_READ = do
 
 -- | Get comment for a file in the archive (referenced by position index).
 getFileCommentIx :: [FileFlag]  -- ^ FileUNCHANGED can be used.
-                 -> Int         -- ^ Position index of the file.
+                 -> Integer     -- ^ Position index of the file.
                  -> Archive (Maybe String)
 getFileCommentIx flags i = do
   z <- getZip
   maybe (lift $ E.throwIO ErrNOENT) (flip setFileCommentIx comment) mbi
 
 -- | Set comment for a file in the archive (referenced by position index).
-setFileCommentIx :: Int        -- ^ Position index of a file in the archive.
+setFileCommentIx :: Integer    -- ^ Position index of a file in the archive.
                  -> String     -- ^ New file comment. 
                  -> Archive ()
 setFileCommentIx i comment = do
   maybe (lift $ E.throwIO ErrNOENT) removeFileCommentIx mbi
 
 -- | Remove comment for a file in the archive (referenced by position index).
-removeFileCommentIx :: Int  -- ^ Position index of a file in the archive.
+removeFileCommentIx :: Integer -- ^ Position index of a file in the archive.
                     -> Archive ()
 removeFileCommentIx i = do
   z <- getZip
   maybe (lift $ E.throw ErrNOENT) unchangeFileIx mbi
 
 -- | Undo changes to a file in the archive (referenced by position index).
-unchangeFileIx :: Int  -- ^ Position index of a file in the archive.
+unchangeFileIx :: Integer  -- ^ Position index of a file in the archive.
                -> Archive ()
 unchangeFileIx i = do
   z <- getZip
 -- an 'Archive' action (see also 'withArchive'). 'fromFileIx' can be replaced
 -- with 'fileContentsIx' to read an entire file at once.
 fromFileIx :: [FileFlag] -- ^ 'FileCOMPRESSED' and 'FileUNCHANGED' can be used.
-           -> Int        -- ^ Position index of a file in the archive.
+           -> Integer    -- ^ Position index of a file in the archive.
            -> Entry a    -- ^ Action with the file.
            -> Archive a
 fromFileIx flags i action = do
 -- | Read at most @n@ bytes from the file.
 readBytes ::
     (Enum a)
-    => Int       -- ^ The number of bytes to read.
+    => Integer   -- ^ The number of bytes to read.
     -> Entry [a] -- ^ Bytes read.
 readBytes n = do
+  lift . lift $
+    when (n > toInteger (maxBound::Int))
+      (E.throwIO ErrMEMORY) -- allocaArray can't allocate > (maxBound::Int)
   (zf,_,_) <- get
-  lift . lift $ allocaArray n $ \buf -> do
+  lift . lift $ allocaArray (fromIntegral n) $ \buf -> do
          nread <- c'zip_fread zf (castPtr buf) (fromIntegral n)
          if nread < 0
             then
               return . map (toEnum . fromEnum) $ bs
 
 -- | Skip @n@ bytes from the open file. Note: this is not faster than reading.
-skipBytes :: Int -> Entry ()
+skipBytes :: Integer -> Entry ()
 skipBytes n = (readBytes n :: Entry [Word8]) >> return ()
 
 -- | Read entire file contents.
 -- 'readContents' from within 'Archive' monad.
 fileContentsIx :: (Enum a)
     => [FileFlag]
-    -> Int
+    -> Integer
     -> Archive [a]
 fileContentsIx flags i = fromFileIx flags i readContents
 

File LibZip/Codec/Archive/LibZip/LegacyZeroZero.hsc

--- | This module is a backwards compatible replacement for @Codec.Archive.LibZip@ module of LibZip 0.0.x. This API is deprecated, please don't use it in new code.
-module Codec.Archive.LibZip.LegacyZeroZero
-  {-# DEPRECATED "Please upgrade to monadic Codec.Archive.LibZip" #-}
-  (
-  -- * Types
-  Zip,ZipFile,OpenFlag(..),FileFlag(..),ZipError(..)
-  ,Word8
-  -- * High-level interface
-  ,withZip,getFiles,getFileSize
-  ,readZipFile,readZipFile'
-  ,readZipFileHead,readZipFileHead'
-  -- * Low-level bindings
-  ,open,close,get_num_files,get_name
-  ,fopen,fopen_index,fclose,fread
-   -- * Utilities
-   ,catchZipError,isFile,isDir
-  ) where
-
-import Control.Monad (liftM)
-import Data.Word (Word8)
-import Foreign.C.String (withCString,peekCString)
-import Foreign.Marshal.Alloc (alloca)
-import Foreign.Marshal.Array (allocaArray, peekArray)
-import Foreign.Ptr (Ptr, nullPtr, castPtr)
-import Foreign.Storable (peek)
-import qualified Control.Exception as E
-import qualified Data.ByteString as B
-
-import Bindings.LibZip
-import Codec.Archive.LibZip.Types
-import Codec.Archive.LibZip.Errors
-
--- | Open zip archive specified by /path/ and return its handler on success.
-open :: String   -- ^ /path/ of the file to open
-     -> [OpenFlag]  -- ^ open mode
-     -> IO Zip  -- ^ handler of the open zip archive
-open path flags =
-  withCString path $ \path' ->
-  alloca $ \errp -> do
-  z <- c'zip_open path' (combine flags) errp
-  if z /= nullPtr
-    then return z
-    else peek errp >>= E.throwIO . errFromCInt
-
--- | Close zip archive.
-close :: Zip -> IO ()
-close z | z == nullPtr = E.throwIO ErrINVAL
-close z = do
-  r <- c'zip_close z
-  if r == 0
-    then return ()
-    else E.throwIO =<< get_error z
-
--- | Return the number of files in the archive.
-get_num_files :: Zip -> IO Int
-get_num_files z | z == nullPtr = E.throwIO ErrINVAL
-get_num_files z = fromIntegral `liftM` c'zip_get_num_files z
-
--- | Get name of file by index.
-get_name :: Zip -> Int -> [FileFlag] -> IO String
-get_name z _ _ | z == nullPtr = E.throwIO ErrINVAL
-get_name z i flags = do
-  n <- c'zip_get_name z (fromIntegral i) (combine flags)
-  if n /= nullPtr
-    then peekCString n
-    else E.throwIO =<< get_error z
-
--- | Open file in zip archive for reading.
-fopen :: Zip -> String -> [FileFlag] -> IO ZipFile
-fopen z _ _ | z == nullPtr = E.throwIO ErrINVAL
-fopen z fn flags = withCString fn $ \fn' ->
-  returnNotNull z =<< c'zip_fopen z fn' (combine flags)
-
--- | Open n-th file in zip archive for reading.
-fopen_index :: Zip -> Int -> [FileFlag] -> IO ZipFile
-fopen_index z _ _ | z == nullPtr = E.throwIO ErrINVAL
-fopen_index z i flags =
-  returnNotNull z =<< c'zip_fopen_index z (fromIntegral i) (combine flags)
-
--- | Close file in zip archive.
-fclose :: ZipFile -> IO ()
-fclose zf =
-   errorOrNothing =<< c'zip_fclose zf
-   where errorOrNothing 0 = return ()
-         errorOrNothing e = E.throwIO (errFromCInt e)
-
--- | Read from file in zip archive.
-fread :: ZipFile -> Int -> IO [Word8]
-fread zf count =
-  allocaArray count $ \buf -> do
-  rcount <- c'zip_fread zf (castPtr buf) (fromIntegral count)
-  if rcount < 0
-    then E.throwIO ErrREAD
-    else peekArray (fromIntegral rcount) buf
-
--- High level Haskell wrappers
-
--- | Open zip archive, do something, and close the archive.
-withZip :: String -- ^ /path/ of the file to open
-        -> [OpenFlag] -- ^ open mode
-        -> (Zip -> IO a) -- ^ action to do on zip arhive
-        -> IO a
-withZip filename flags action = do
-  z <- open filename flags
-  result <- action z
-  close z
-  return result
-
--- | Get names of the files in archive.
-getFiles :: Zip -> [FileFlag] -> IO [String]
-getFiles z flags = do
-  n <- get_num_files z
-  mapM (\i -> get_name z i flags) [0..(n-1)]
-
--- | Get size of the file in archive.
-getFileSize :: Zip        -- ^ zip archive
-            -> String     -- ^ name of the file in the archive
-            -> [FileFlag] -- ^ file name mode
-            -> IO Int
-getFileSize z name flags =
-  withCString name $ \name' ->
-  alloca $ \stat -> do
-  ret <- c'zip_stat z name' (combine flags) stat
-  if ret /= 0
-    then E.throwIO =<< get_error z
-    else return . fromIntegral . c'zip_stat'size =<< peek stat
-
--- | Read uncompressed file from the archive. Produce a strict ByteString.
-readZipFile :: Zip -- ^ zip archive
-         -> String -- ^ name of the file in the archive
-         -> [FileFlag] -- ^ file name mode
-         -> IO B.ByteString
-readZipFile z fname flags = return . B.pack =<< readZipFile' z fname flags
-
--- | Read uncompressed file from the archive. Produce a list of 'Word8'.
-readZipFile' :: Zip -- ^ zip archive
-         -> String -- ^ name of the file in the archive
-         -> [FileFlag] -- ^ file name mode
-         -> IO [Word8]
-readZipFile' z fname flags = do
-  sz <- getFileSize z fname flags
-  readZipFileHead' z fname flags sz
-
--- | Read beginning of the uncompressed file from the archive. Produce a list of 'Word8'.
-readZipFileHead' :: Zip -- ^ zip archive
-         -> String -- ^ name of the file in the archive
-         -> [FileFlag] -- ^ file name mode
-         -> Int -- ^ how many bytes to read
-         -> IO [Word8]
-readZipFileHead' z fname flags n = do
-  f <- fopen z fname flags
-  bytes <- fread f n
-  fclose f
-  return bytes
-
--- | Read beginning of the uncompressed file from the archive. Produce a strict ByteString.
-readZipFileHead :: Zip -- ^ zip archive
-         -> String -- ^ name of the file in the archive
-         -> [FileFlag] -- ^ file name mode
-         -> Int -- ^ how many bytes to read
-         -> IO B.ByteString
-readZipFileHead z fname flags n = return . B.pack =<< readZipFileHead' z fname flags n
-
-
--- | Return True if path is a file name, not a directory name (does not end with '/').
-isFile :: String -> Bool
-isFile filename = (lastMay filename /= Just '/')
-
--- | Return True if path is a directory name (ends with '/').
-isDir :: String -> Bool
-isDir = not . isFile
-
-lastMay :: [a] -> Maybe a
-lastMay [] = Nothing
-lastMay xs = Just $ last xs
-
--- Return the second argument or throw the last libzip error.
-returnNotNull :: Zip -> Ptr a -> IO (Ptr a)
-returnNotNull z _ | z == nullPtr = E.throwIO ErrINVAL
-returnNotNull z ptr =
-  if ptr /= nullPtr
-    then return ptr
-    else E.throwIO =<< get_error z

File LibZip/Codec/Archive/LibZip/Types.hs

     , toZipStat
     , OpenFlag(..)
     , FileFlag(..)
+    , ArchiveFlag(..)
+    , CodecFlag(..)
     , ZipError(..)
     , ZipCompMethod(..)
     , ZipEncryptionMethod(..)
 import Data.Time (UTCTime)
 import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
 import Data.Typeable (Typeable)
-import Data.Word (Word)
+import Data.Word (Word, Word32, Word64)
 import Foreign.C.String (peekCString)
 import Foreign.C.Types ()
 import Foreign.Ptr (Ptr, nullPtr)
 
 -- |  File statistics expressed in native Haskell types.
 data ZipStat = ZipStat {
-      zs'name :: String
-    , zs'index :: Int
+      zs'valid :: Word64
+    , zs'name :: String
+    , zs'index :: Integer
+    , zs'size :: Integer
+    , zs'comp_size :: Integer
+    , zs'mtime :: UTCTime
     , zs'crc :: Word
-    , zs'mtime :: UTCTime
-    , zs'size :: Int
-    , zs'comp_size :: Int
     , zs'comp_method :: ZipCompMethod
     , zs'encryption_method :: ZipEncryptionMethod
+    , zs'flags :: Word32
     } deriving (Show, Eq)
 
 -- | Convert marshalled stat record.
 toZipStat :: C'zip_stat -> IO ZipStat
 toZipStat s = do
+    let valid = fromIntegral $ c'zip_stat'valid s
     let np = c'zip_stat'name s
     name <- if (np /= nullPtr) then peekCString np else return ""
     let idx = fromIntegral $ c'zip_stat'index s
     let comp_size = fromIntegral $ c'zip_stat'comp_size s
     let comp_meth = toEnum . fromIntegral $ c'zip_stat'comp_method s
     let enc_meth = toEnum . fromIntegral $ c'zip_stat'encryption_method s
-    return $ ZipStat name idx crc mtime size comp_size comp_meth enc_meth
+    let flags =  toEnum . fromIntegral $ c'zip_stat'flags s
+    return $ ZipStat valid name idx size comp_size mtime crc
+             comp_meth enc_meth flags
    
 
 -- | Flags for opening an archive.
   | FileCOMPRESSED  -- ^ Read the compressed data.
   | FileUNCHANGED   -- ^ Read the original data, ignore changes.
   | FileRECOMPRESS  -- ^ Force recompression of data.
+  | FileENCRYPTED   -- ^ Read encrypted data (implies FileCOMPRESSED).
   deriving (Show,Eq)
 
 instance Enum FileFlag where
   fromEnum FileNODIR = c'ZIP_FL_NODIR
   fromEnum FileRECOMPRESS = c'ZIP_FL_RECOMPRESS
   fromEnum FileUNCHANGED = c'ZIP_FL_UNCHANGED
+  fromEnum FileENCRYPTED = c'ZIP_FL_ENCRYPTED
   toEnum x | x == c'ZIP_FL_COMPRESSED = FileCOMPRESSED
   toEnum x | x == c'ZIP_FL_NOCASE = FileNOCASE
   toEnum x | x == c'ZIP_FL_NODIR = FileNODIR
   toEnum x | x == c'ZIP_FL_RECOMPRESS = FileRECOMPRESS
   toEnum x | x == c'ZIP_FL_UNCHANGED = FileUNCHANGED
+  toEnum x | x == c'ZIP_FL_ENCRYPTED = FileENCRYPTED
   toEnum _ = undefined
 
+
+-- | @libzip@ archive global flags
+data ArchiveFlag
+    = ArchiveTORRENT
+    | ArchiveRDONLY
+    deriving (Show, Eq)
+
+instance Enum ArchiveFlag where
+    fromEnum ArchiveTORRENT = c'ZIP_AFL_TORRENT
+    fromEnum ArchiveRDONLY = c'ZIP_AFL_RDONLY
+    toEnum x | x == c'ZIP_AFL_TORRENT = ArchiveTORRENT
+    toEnum x | x == c'ZIP_AFL_RDONLY = ArchiveRDONLY
+    toEnum _ = undefined
+
+
+-- | @libzip@ flags for compression and encryption sources
+data CodecFlag = CodecENCODE deriving (Show, Eq)
+
+instance Enum CodecFlag where
+    fromEnum CodecENCODE = c'ZIP_CODEC_ENCODE
+    toEnum x | x == c'ZIP_CODEC_ENCODE = CodecENCODE
+    toEnum _ = undefined
+
+
 -- | @libzip@ error codes.
 data ZipError
   = ErrOK             -- ^ No error.
   | ErrINCONS         -- ^ Zip archive inconsistent.
   | ErrREMOVE         -- ^ Can't remove file.
   | ErrDELETED        -- ^ Entry has been deleted.
+  | ErrENCRNOTSUPP    -- ^ Encryption method not supported.
+  | ErrRDONLY         -- ^ Read-only archive.
+  | ErrNOPASSWD       -- ^ No password provided.
+  | ErrWRONGPASSWD    -- ^ Wrong password provided.
   deriving (Eq, Typeable)
 
 instance Enum ZipError where
   fromEnum ErrWRITE = c'ZIP_ER_WRITE
   fromEnum ErrZIPCLOSED = c'ZIP_ER_ZIPCLOSED
   fromEnum ErrZLIB = c'ZIP_ER_ZLIB
+  fromEnum ErrENCRNOTSUPP = c'ZIP_ER_ENCRNOTSUPP
+  fromEnum ErrRDONLY = c'ZIP_ER_RDONLY
+  fromEnum ErrNOPASSWD = c'ZIP_ER_NOPASSWD
+  fromEnum ErrWRONGPASSWD = c'ZIP_ER_WRONGPASSWD
   toEnum x | x == c'ZIP_ER_CHANGED = ErrCHANGED
   toEnum x | x == c'ZIP_ER_CLOSE = ErrCLOSE
   toEnum x | x == c'ZIP_ER_COMPNOTSUPP = ErrCOMPNOTSUPP
   toEnum x | x == c'ZIP_ER_WRITE = ErrWRITE
   toEnum x | x == c'ZIP_ER_ZIPCLOSED = ErrZIPCLOSED
   toEnum x | x == c'ZIP_ER_ZLIB = ErrZLIB
+  toEnum x | x == c'ZIP_ER_ENCRNOTSUPP = ErrENCRNOTSUPP
+  toEnum x | x == c'ZIP_ER_RDONLY = ErrRDONLY
+  toEnum x | x == c'ZIP_ER_NOPASSWD = ErrNOPASSWD
+  toEnum x | x == c'ZIP_ER_WRONGPASSWD = ErrWRONGPASSWD
   toEnum _ = undefined
 
 instance E.Exception ZipError
   show ErrINCONS         =  "Zip archive inconsistent"
   show ErrREMOVE         =  "Can't remove file"
   show ErrDELETED        =  "Entry has been deleted"
+  show ErrENCRNOTSUPP    =  "Encryption method not supported"
+  show ErrRDONLY         =  "Read-only archive" 
+  show ErrNOPASSWD       =  "No password provided"
+  show ErrWRONGPASSWD    =  "Wrong password provided"
 
 -- | Compression methods.
 data ZipCompMethod
   toEnum x | x == c'ZIP_EM_UNKNOWN = EncryptUNKNOWN
   toEnum _ = undefined
 
--- | 
-
 combine :: (Enum a, Num b) => [a] -> b
 combine fs = fromIntegral . foldr (.|.) 0 $ map fromEnum fs
 

File LibZip/LibZip.cabal

 Name:          LibZip
-Version:       0.2.0.4
+Version:       0.10
 License:       BSD3
 License-File:  LICENSE
 Author:        Sergey Astanin
 
 Build-Type:     Simple
 Cabal-Version:  >= 1.2.3
-Tested-With:    GHC == 7.0.1, GHC == 7.2.1, GHC == 7.4.1
+Tested-With:    GHC == 7.0.3, GHC == 7.2.2, GHC == 7.4.1
 
 Extra-Source-Files:
-    examples/legacyUnzip.hs, examples/hzip.hs
-  , runTests.hs, Tests/Common.hs, Tests/LegacyTests.hs
+    examples/hzip.hs
+  , runTests.hs, Tests/Common.hs
   , Tests/MonadicTests.hs, Tests/test.zip
 
 Library
   Exposed-Modules:
       Codec.Archive.LibZip
       Codec.Archive.LibZip.Types
-      Codec.Archive.LibZip.LegacyZeroZero
   Other-Modules:
       Codec.Archive.LibZip.Errors
   Build-Depends:
       base >= 4.0 && < 4.6
-    , bindings-libzip >= 0.1 && < 0.2
+    , bindings-libzip >= 0.10 && < 0.11
     , bytestring
     , filepath
     , time

File LibZip/Tests/Common.hs

 testzip = "Tests/test.zip"
 testfiles = [ "hello/", "hello/world.txt" ]
 lastfile = last testfiles
-lastfilesize = 71 :: Int
+lastfilesize = 71 :: Integer
 
 world_txt = "And God saw everything that he had made,\
             \ and behold, it was very good.\n"

File LibZip/Tests/LegacyTests.hs

-module Tests.LegacyTests
-    ( legacyTests
-    ) where
-
-import Codec.Archive.LibZip.LegacyZeroZero
-
-import Tests.Common
-
-import qualified Data.ByteString as B
-import Test.HUnit
-
-legacyTests = TestList
-  [ "read list of files" ~: do
-      files <- withZip testzip [] $ \z -> getFiles z [] :: IO [String]
-      files @?= testfiles
-  , "read file size" ~: do
-      sz <- withZip testzip [] $ \z -> getFileSize z lastfile []
-      sz @?= lastfilesize
-  , "case-insensitive file names" ~: do
-    sz <- withZip testzip [] $ \z ->
-          getFileSize z (map2 toUpper toLower $ lastfile) [FileNOCASE]
-    sz @?= lastfilesize
-  , "open error if exists (with ExclFlag)" ~: do
-    err <- catchZipError
-            (withZip testzip [ExclFlag] $ \_ -> return ErrOK)
-            (return . id)
-    err @?= ErrEXISTS
-  , "read file" ~: do
-    txt <- withZip testzip [] $ \z -> readZipFile z lastfile []
-    txt @?= toByteString world_txt
-  , "open file by index" ~: do
-    txt <- withZip testzip [] $ \z -> do
-        f <- fopen_index z 1 [] -- index 0 is of the parent dir
-        bytes <- fread f (length world_txt)
-        return $ B.pack bytes
-    txt @?= toByteString world_txt
-  ]
-
-
-toByteString :: String -> B.ByteString
-toByteString s = B.pack $ map (fromIntegral . fromEnum) s
-

File LibZip/Tests/MonadicTests.hs

       txt <- withArchive [] testzip $ fileContents [] lastfile
       txt @?= world_txt
   , "read file by index" ~: do
-      txt <- withArchive [] testzip $ fileContentsIx [] (length testfiles - 1)
+      let i = toInteger (length testfiles - 1)
+      txt <- withArchive [] testzip $ fileContentsIx [] i
       txt @?= world_txt
   , "skipBytes/readBytes" ~: do
       txt <- withArchive [] testzip $

File LibZip/examples/hzip.hs

 list :: FilePath -> IO ()
 list archive = do
   stats <- withArchive [] archive $ do
-             n <- numFiles
+             n <- numFiles []
              mapM (fileStatIx []) [0..(n-1)]
   mapM_ printEntry stats
   where
 extract :: FilePath -> FilePath -> [FilePath] -> IO ()
 extract outdir archive onlyFiles =
   withArchive [] archive $ do
-    n <- numFiles
+    n <- numFiles []
     mapM_ (extractEntry outdir onlyFiles) [0..(n-1)]
 
 -- silently overwrites existing files
-extractEntry :: FilePath -> [FilePath] -> Int -> Archive ()
+extractEntry :: FilePath -> [FilePath] -> Integer -> Archive ()
 extractEntry outdir onlyFiles i = do
   name <- fileName [] i
   let fspath = joinPath [outdir, name]

File LibZip/examples/legacyUnzip.hs

--- A simple unzip utility.
---
--- This is an example of using legacy LibZip-0.0 API.
---
-module Main where
-
-import qualified Data.ByteString as B
-import Control.Monad (forM_,when)
-import System.Directory (createDirectoryIfMissing)
-import System.Environment (getArgs)
-import System.FilePath (takeDirectory)
-
-import Codec.Archive.LibZip
-
-usage = "unzip [-l] file.zip [files]"
-
-main = do
-  args <- getArgs
-  let onlyList = "-l" `elem` args
-  let args' = filter (/= "-l") args
-  case args' of
-    [] -> putStrLn usage
-    (filename:files) -> do
-      catchZipError $
-        withZip filename [] $ \z -> do
-          files' <- getFiles z []
-          forM_ files' $ \f -> do
-            when (f `elem` files || null files) $
-              if onlyList
-                then putStrLn f
-                else saveFile f =<< readZipFile z f []
-      $ \e -> putStrLn $ "Error in " ++ filename ++ ": " ++ show e
-
-saveFile f contents = do
-  if isDir f
-    then createDirectoryIfMissing True $ takeDirectory f
-    else B.writeFile f contents
-

File LibZip/runTests.hs

-import Tests.LegacyTests (legacyTests)
 import Tests.MonadicTests (monadicTests)
 
 import System.Exit
 import Test.HUnit
 
 allTests = TestList
-  [ "Legacy API" ~: legacyTests
-  , "Monadic API" ~: monadicTests
+  [ "Monadic API" ~: monadicTests
   ]
 
 main = do

File bindings-libzip/Bindings/LibZip.hsc

 #include <bindings.dsl.h>
 #include <zip.h>
 
--- | This module provides automatic low-level bindings to @libzip@ library.
--- See also:
+-- | This module provides automatic low-level bindings to @libzip@
+-- library, version 0.10. See also:
 --
 --   * @libzip@ documention: <http://nih.at/libzip/libzip.html> and @zip.h@
 --
 --   * <http://hackage.haskell.org/package/LibZip>
 --
 
+
 module Bindings.LibZip where
 #strict_import
 
 #num ZIP_FL_COMPRESSED
 #num ZIP_FL_UNCHANGED
 #num ZIP_FL_RECOMPRESS
+#num ZIP_FL_ENCRYPTED
 
 -- archive global flags flags
 
 #num ZIP_AFL_TORRENT
+#num ZIP_AFL_RDONLY
+
+-- flags for compression and encryption sources
+
+#num ZIP_CODEC_ENCODE
 
 -- libzip error codes
 
 #num ZIP_ER_INCONS
 #num ZIP_ER_REMOVE
 #num ZIP_ER_DELETED
+#num ZIP_ER_ENCRNOTSUPP
+#num ZIP_ER_RDONLY
+#num ZIP_ER_NOPASSWD
+#num ZIP_ER_WRONGPASSWD
 
 -- type of system error value
 
 #num ZIP_SOURCE_ERROR
 #num ZIP_SOURCE_FREE
 
--- typedef ssize_t (*zip_source_callback)(void *state, void *data,
---                                        size_t len, enum zip_source_cmd cmd);
-#callback zip_source_callback , Ptr () -> Ptr () -> CSize -> <zip_source_cmd> -> IO CSize
+-- typedef zip_int64_t (*zip_source_callback)(void *, void *, zip_uint64_t, enum zip_source_cmd);
+#callback zip_source_callback , Ptr () -> Ptr () -> CULLong -> <zip_source_cmd> -> IO CULLong
+
+#num ZIP_SOURCE_ERR_LOWER
+
+#num ZIP_STAT_NAME
+#num ZIP_STAT_INDEX
+#num ZIP_STAT_SIZE
+#num ZIP_STAT_COMP_SIZE
+#num ZIP_STAT_MTIME
+#num ZIP_STAT_CRC
+#num ZIP_STAT_COMP_METHOD
+#num ZIP_STAT_ENCRYPTION_METHOD
+#num ZIP_STAT_FLAGS
 
 #opaque_t time_t
 
+-- struct zip_stat {
+--     zip_uint64_t valid;                 /* which fields have valid values */
+--     const char *name;                   /* name of the file */
+--     zip_uint64_t index;                 /* index within archive */
+--     zip_uint64_t size;                  /* size of file (uncompressed) */
+--     zip_uint64_t comp_size;             /* size of file (compressed) */
+--     time_t mtime;                       /* modification time */
+--     zip_uint32_t crc;                   /* crc of file data */
+--     zip_uint16_t comp_method;           /* compression method used */
+--     zip_uint16_t encryption_method;     /* encryption method used */
+--     zip_uint32_t flags;                 /* reserved for future use */
+-- };
 #starttype struct zip_stat
+#field valid, CULLong
 #field name, Ptr CChar
-#field index, CInt
+#field index, CULLong
+#field size, CULLong
+#field comp_size, CULLong
+#field mtime, CTime
 #field crc, CUInt
-#field mtime, CTime
-#field size, CSize
-#field comp_size, CSize
 #field comp_method, CUShort
 #field encryption_method, CUShort
+#field flags, CUInt
 #stoptype
 
--- int zip_add(struct zip *, const char *, struct zip_source *);
-#ccall zip_add , Ptr <zip> -> CString -> Ptr <zip_source> -> IO CInt
+-- make every declaration one-line, and replace
+--    ZIP_EXTERN ->
+--    const char * -> CString
+--    char * -> Ptr CChar
+--    struct foo * -> Ptr <foo>  -- with regexps
+--    FILE -> CFile
+--    int -> CInt
+--    zip_int64_t -> CLLong
+--    zip_uint64_t -> CULLong
+--    void -> ()
+--    zip_source_callback -> <zip_source_callback>
+--    foo * -> Ptr foo   -- with regexps
+--    regexp-replace "\(.*\)\(zip_[a-z0-9_]+\)(\(.*\));" "#ccall \2 , \3 -> IO (\1)"
 
--- int zip_add_dir(struct zip *, const char *);
-#ccall zip_add_dir , Ptr <zip> -> CString -> IO CInt
-
--- int zip_close(struct zip *);
-#ccall zip_close , Ptr <zip> -> IO CInt
-
--- int zip_delete(struct zip *, int);
-#ccall zip_delete , Ptr <zip> -> CInt -> IO CInt
-
--- void zip_error_clear(struct zip *);
+#ccall zip_add , Ptr <zip> -> CString -> Ptr <zip_source> -> IO (CLLong)
+#ccall zip_add_dir , Ptr <zip> -> CString -> IO (CLLong)
+#ccall zip_close , Ptr <zip> -> IO (CInt)
+#ccall zip_delete , Ptr <zip> -> CULLong -> IO (CInt)
 #ccall zip_error_clear , Ptr <zip> -> IO ()
-
--- void zip_error_get(struct zip *, int *, int *);
 #ccall zip_error_get , Ptr <zip> -> Ptr CInt -> Ptr CInt -> IO ()
-
--- int zip_error_get_sys_type(int);
-#ccall zip_error_get_sys_type , CInt -> IO CInt
-
--- int zip_error_to_str(char *, size_t, int, int);
-#ccall zip_error_to_str , Ptr Char -> CSize -> CInt -> CInt -> IO CInt
-
--- int zip_fclose(struct zip_file *);
-#ccall zip_fclose , Ptr <zip_file> -> IO CInt
-
--- void zip_file_error_clear(struct zip_file *);
+#ccall zip_error_get_sys_type , CInt -> IO (CInt)
+#ccall zip_error_to_str , Ptr CChar -> CULLong -> CInt -> CInt -> IO (CInt)
+#ccall zip_fclose , Ptr <zip_file> -> IO (CInt)
+#ccall zip_fdopen , CInt -> CInt -> Ptr CInt -> IO (Ptr <zip>)
 #ccall zip_file_error_clear , Ptr <zip_file> -> IO ()
-
--- void zip_file_error_get(struct zip_file *, int *, int *);
 #ccall zip_file_error_get , Ptr <zip_file> -> Ptr CInt -> Ptr CInt -> IO ()
-
--- const char *zip_file_strerror(struct zip_file *);
-#ccall zip_file_strerror , Ptr <zip_file> -> IO CString
-
--- struct zip_file *zip_fopen(struct zip *, const char *, int);
+#ccall zip_file_strerror , Ptr <zip_file> -> IO (CString)
 #ccall zip_fopen , Ptr <zip> -> CString -> CInt -> IO (Ptr <zip_file>)
-
--- struct zip_file *zip_fopen_index(struct zip *, int, int);
-#ccall zip_fopen_index , Ptr <zip> -> CInt -> CInt -> IO (Ptr <zip_file>)
-
--- ssize_t zip_fread(struct zip_file *, void *, size_t);
-#ccall zip_fread , Ptr <zip_file> -> Ptr () -> CSize -> IO CSize
-
--- const char *zip_get_archive_comment(struct zip *, int *, int);
-#ccall zip_get_archive_comment , Ptr <zip> -> Ptr CInt -> CInt -> IO CString
-
--- int zip_get_archive_flag(struct zip *, int, int);
-#ccall zip_get_archive_flag , Ptr <zip> -> CInt -> CInt -> IO CInt
-
--- const char *zip_get_file_comment(struct zip *, int, int *, int);
-#ccall zip_get_file_comment , Ptr <zip> -> CInt -> Ptr CInt -> CInt -> IO CString
-
--- const char *zip_get_name(struct zip *, int, int);
-#ccall zip_get_name , Ptr <zip> -> CInt -> CInt -> IO CString
-
--- int zip_get_num_files(struct zip *);
-#ccall zip_get_num_files , Ptr <zip> -> IO CInt
-
--- int zip_name_locate(struct zip *, const char *, int);
-#ccall zip_name_locate , Ptr <zip> -> CString -> CInt -> IO CInt
-
--- struct zip *zip_open(const char *, int, int *);
+#ccall zip_fopen_encrypted , Ptr <zip> -> CString -> CInt -> CString -> IO (Ptr <zip_file>)
+#ccall zip_fopen_index , Ptr <zip> -> CULLong -> CInt -> IO (Ptr <zip_file>)
+#ccall zip_fopen_index_encrypted , Ptr <zip> -> CULLong -> CInt -> CString -> IO (Ptr <zip_file>)
+#ccall zip_fread , Ptr <zip_file> -> Ptr () -> CULLong -> IO (CLLong)
+#ccall zip_get_archive_comment , Ptr <zip> -> Ptr CInt -> CInt -> IO (CString)
+#ccall zip_get_archive_flag , Ptr <zip> -> CInt -> CInt -> IO (CInt)
+#ccall zip_get_file_comment , Ptr <zip> -> CULLong -> Ptr CInt -> CInt -> IO (CString)
+#ccall zip_get_file_extra , Ptr <zip> -> CULLong -> Ptr CInt -> CInt -> IO (CString)
+#ccall zip_get_name , Ptr <zip> -> CULLong -> CInt -> IO (CString)
+#ccall zip_get_num_entries , Ptr <zip> -> CInt -> IO (CULLong)
+#ccall zip_get_num_files , Ptr <zip> -> IO (CInt)
+#ccall zip_name_locate , Ptr <zip> -> CString -> CInt -> IO (CInt)
 #ccall zip_open , CString -> CInt -> Ptr CInt -> IO (Ptr <zip>)
-
--- int zip_rename(struct zip *, int, const char *);
-#ccall zip_rename , Ptr <zip> -> CInt -> CString -> IO CInt
-
--- int zip_replace(struct zip *, int, struct zip_source *);
-#ccall zip_replace , Ptr <zip> -> CInt -> Ptr <zip_source> -> IO CInt
-
--- int zip_set_archive_comment(struct zip *, const char *, int);
-#ccall zip_set_archive_comment , Ptr <zip> -> CString -> CInt -> IO CInt
-
--- int zip_set_archive_flag(struct zip *, int, int);
-#ccall zip_set_archive_flag , Ptr <zip> -> CInt -> CInt -> IO CInt
-
--- int zip_set_file_comment(struct zip *, int, const char *, int);
-#ccall zip_set_file_comment , Ptr <zip> -> CInt -> CString -> CInt -> IO CInt
-
--- struct zip_source *zip_source_buffer(struct zip *, const void *, off_t, int);
-#ccall zip_source_buffer , Ptr <zip> -> Ptr () -> CSize -> CInt -> IO (Ptr <zip_source>)
-
--- struct zip_source *zip_source_file(struct zip *, const char *, off_t, off_t);
-#ccall zip_source_file , Ptr <zip> -> CString -> CSize -> CSize -> IO (Ptr <zip_source>)
-
--- struct zip_source *zip_source_filep(struct zip *, FILE *, off_t, off_t);
-#ccall zip_source_filep , Ptr <zip> -> Ptr CFile -> CSize -> CSize -> IO (Ptr <zip_source>)
-
--- void zip_source_free(struct zip_source *);
+#ccall zip_rename , Ptr <zip> -> CULLong -> CString -> IO (CInt)
+#ccall zip_replace , Ptr <zip> -> CULLong -> Ptr <zip_source> -> IO (CInt)
+#ccall zip_set_archive_comment , Ptr <zip> -> CString -> CInt -> IO (CInt)
+#ccall zip_set_archive_flag , Ptr <zip> -> CInt -> CInt -> IO (CInt)
+#ccall zip_set_default_password , Ptr <zip> -> CString -> IO (CInt)
+#ccall zip_set_file_comment , Ptr <zip> -> CULLong -> CString -> CInt -> IO (CInt)
+#ccall zip_set_file_extra , Ptr <zip> -> CULLong -> CString -> CInt -> IO (CInt)
+#ccall zip_source_buffer , Ptr <zip> -> Ptr () -> CULLong -> CInt -> IO (Ptr <zip_source>)
+#ccall zip_source_file , Ptr <zip> -> CString -> CULLong -> CLLong -> IO (Ptr <zip_source>)
+#ccall zip_source_filep , Ptr <zip> -> Ptr CFile -> CULLong -> CLLong -> IO (Ptr <zip_source>)
 #ccall zip_source_free , Ptr <zip_source> -> IO ()
-
--- struct zip_source *zip_source_function(struct zip *, zip_source_callback, void *);
 #ccall zip_source_function , Ptr <zip> -> <zip_source_callback> -> Ptr () -> IO (Ptr <zip_source>)
-
--- struct zip_source *zip_source_zip(struct zip *, struct zip *, int, int, off_t, off_t);
-#ccall zip_source_zip , Ptr <zip> -> Ptr <zip> -> CInt -> CInt -> CSize -> CSize -> IO (Ptr <zip_source>)
-
--- int zip_stat(struct zip *, const char *, int, struct zip_stat *);
-#ccall zip_stat , Ptr <zip> -> CString -> CInt -> Ptr <zip_stat> -> IO CInt
-
--- int zip_stat_index(struct zip *, int, int, struct zip_stat *);
-#ccall zip_stat_index , Ptr <zip> -> CInt -> CInt -> Ptr <zip_stat> -> IO CInt
-
--- void zip_stat_init(struct zip_stat *);
+#ccall zip_source_zip , Ptr <zip> -> Ptr <zip> -> CULLong -> CInt -> CULLong -> CLLong -> IO (Ptr <zip_source>)
+#ccall zip_stat , Ptr <zip> -> CString -> CInt -> Ptr <zip_stat> -> IO (CInt)
+#ccall zip_stat_index , Ptr <zip> -> CULLong -> CInt -> Ptr <zip_stat> -> IO (CInt)
 #ccall zip_stat_init , Ptr <zip_stat> -> IO ()
-
--- const char *zip_strerror(struct zip *);
-#ccall zip_strerror , Ptr <zip> -> IO CString
-
--- int zip_unchange(struct zip *, int);
-#ccall zip_unchange , Ptr <zip> -> CInt -> IO CInt
-
--- int zip_unchange_all(struct zip *);
-#ccall zip_unchange_all , Ptr <zip> -> IO CInt
-
--- int zip_unchange_archive(struct zip *);
-#ccall zip_unchange_archive , Ptr <zip> -> IO CInt
-
+#ccall zip_strerror , Ptr <zip> -> IO (CString)
+#ccall zip_unchange , Ptr <zip> -> CULLong -> IO (CInt)
+#ccall zip_unchange_all , Ptr <zip> -> IO (CInt)
+#ccall zip_unchange_archive , Ptr <zip> -> IO (CInt)

File bindings-libzip/bindings-libzip.cabal

 Name:                bindings-libzip
-Version:             0.1.0.4
+Version:             0.10
 Synopsis:            Low level bindings to libzip.
 Description:
-  This package provides low-level bindings to libzip library.
+  This package provides low-level bindings to libzip (v0.10) library.
   For higher-level interface please use LibZip package:
   <http://hackage.haskell.org/package/LibZip>
 
 Build-type:          Simple
 
 Cabal-version:       >=1.2.3
-Tested-with:         GHC == 7.0.1, GHC == 7.2.1, GHC == 7.4.1
+Tested-with:         GHC == 7.0.3, GHC == 7.2.2, GHC == 7.4.1
 
 Flag NoPkgConfig
   Description: Do not use pkg-config to check for library dependencies.
     Includes: zip.h
     Extra-Libraries: zip z
   else
-    PkgConfig-Depends: libzip >= 0.9
+    PkgConfig-Depends: libzip == 0.10
 
   GHC-Options:
-        -Wall
+        -Wall -fno-warn-unused-imports