1. Sergey Astanin
  2. hs-libzip

Commits

Sergey Astanin  committed a53901e Merge

merge 0.11-bindings-libzip into default

  • Participants
  • Parent commits 43d47e6, d2c72b1
  • Branches default

Comments (0)

Files changed (18)

File .hgignore

View file
  • Ignore whitespace
 LibZip/dist
 bindings-libzip/dist
 *.hpc
+bindings-libzip/cabal-dev*
+LibZip/cabal-dev*

File .hgtags

View file
  • Ignore whitespace
 71ad184b549e688ddb1c4638726d309ef3a615ad bindings-libzip-0.1.0.3
 e135bf9f13c7929142752aa47e08694ee90a1cbf 0.2.0.4
 409697501a72d0a8eecae0b650e239e8cd8b1415 bindings-libzip-0.1.0.4
+86380ecbc8d9f81b99078023876022c9645b596d 0.10
+35d24d59f502be0ae6326c03b669835fe1846590 0.10.1
+d0ccd9e8af3ccde789f149846f0d1d01f10d9063 0.10.2

File LibZip/Codec/Archive/LibZip.hs

View file
  • Ignore whitespace
     , Entry
     , ZipStat(..)
     -- * Archive operations
-    , withArchive, getZip
+    , withArchive, withEncryptedArchive, getZip
     , numFiles, fileName, nameLocate, fileNames
     , fileSize, fileSizeIx
     , fileStat, fileStatIx
     , deleteFile, deleteFileIx
     , renameFile, renameFileIx
-    , addFile, addDirectory
+    , addFile, addFileWithFlags
+    , addDirectory, addDirectoryWithFlags
     , replaceFile, replaceFileIx
+    , setFileCompression, setFileCompressionIx
     , sourceBuffer, sourceFile, sourceZip
     , PureSource(..), sourcePure
     , getComment, setComment, removeComment
 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.String (withCString, peekCString)
+import Foreign.C.Types (CInt, CULLong)
 import Foreign.Marshal.Alloc (alloca)
 import Foreign.Marshal.Array (allocaArray, peekArray, withArrayLen, pokeArray)
 import Foreign.Marshal.Utils (with)
 import Foreign.Ptr (Ptr, nullPtr, castPtr)
 import Foreign.Storable (Storable, peek, poke, pokeElemOff, sizeOf)
 import qualified Control.Exception as E
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.UTF8 as UTF8
 
 --
 -- Types
 -- | 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
 
 --
   c'zip_open path' (combine flags) errp >>= \z ->
   if z == nullPtr
     then peek errp >>= E.throwIO. errFromCInt
-    else do
+    else withOpenArchive z action
+
+
+-- | Top-level wrapper for operations with an open encrypted archive.
+-- 'withEncryptedArchive' opens and closes the file automatically.
+-- On error it throws 'ZipError'.
+withEncryptedArchive :: [OpenFlag]   -- ^ Checks for consistency or existence.
+                     -> String       -- ^ Encryption password.
+                     -> FilePath     -- ^ Filename of the zip archive.
+                     -> Archive a    -- ^ Action to don with the archive.
+                     -> IO a
+withEncryptedArchive flags password path action =
+    withCString password $ \password' ->
+    withCString path $ \path' ->
+    alloca $ \errp ->
+    c'zip_open path' (combine flags) errp >>= \z ->
+    if z == nullPtr
+       then peek errp >>= E.throwIO. errFromCInt
+       else do
+         r <- c'zip_set_default_password z password'
+         if r /= 0
+            then get_error z >>= E.throwIO
+            else withOpenArchive z action
+
+
+withOpenArchive :: Zip -> Archive a -> IO a
+withOpenArchive z action = do
       r <- fst `liftM` runStateT action z
       e <- c'zip_close z
       if e /= 0
         then get_error z >>= E.throwIO
         else return r
 
+
 -- | Get the number of entries in the archive.
-numFiles :: Archive Int
-numFiles = do
+numFiles :: [FileFlag]  -- ^ 'FileUNCHANGED' can be used to return
+                        -- the original unchanged number of entries.
+         -> 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.
+fileName :: [FileFlag]  -- ^ 'FileUNCHANGED' flag can be used to
+                        -- return the original unchanged filename.
+         -> Integer     -- ^ Position index of a file in the archive.
          -> Archive FilePath  -- ^ Name of the file in the archive.
 fileName flags i = do
   z <- getZip
     doIf' (n /= nullPtr) z $ peekCString n
 
 -- | Locate an entry (get its index) in the archive by its name.
-nameLocate :: [FileFlag]  -- ^ Filename lookup mode.
+nameLocate :: [FileFlag]
+                -- ^ Filename lookup mode.
+                --   'FileNOCASE':     ignore case distinctions (only for ASCII).
+                --   'FileNODIR':      ignore directory part of the file name.
+                --   'FileENC_RAW':    compare against unmodified names as it is
+                --                     in the ZIP archive.
+                --   'FileENC_GUESS':  (default) guess encoding of the name in
+                --                     the ZIP archive and convert it to UTF-8,
+                --                     if necessary.
+                --   'FileENC_STRICT': follow the ZIP specification and expect
+                --                     CP-437 encoded names in the ZIP archive
+                --                     (except if they are explicitly marked as
+                --                     UTF-8). Convert it to UTF-8 before comparing.
            -> 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
        doIf' (r == 0) z $ toZipStat =<< peek stat
 
 -- | Delete file from the archive.
-deleteFile :: [FileFlag]  -- ^ Filename lookup mode.
+deleteFile :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
            -> FilePath    -- ^ Filename.
            -> Archive ()
 deleteFile flags name = do
   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
      else lift $ get_error z >>= E.throwIO
 
 -- | Rename file in the archive.
-renameFile :: [FileFlag]  -- ^ Filename lookup mode.
+renameFile :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
            -> FilePath    -- ^ Old name.
            -> FilePath    -- ^ New name.
            -> Archive ()
 renameFile flags oldname newname = do
   mbi <- nameLocate flags oldname
-  maybe (lift $ E.throwIO ErrNOENT) (\i -> renameFileIx i newname) mbi
+  maybe (lift $ E.throwIO ErrNOENT)
+            (\i -> renameFileIx i (UTF8.fromString newname) [FileENC_UTF_8])
+            mbi
 
 -- | Rename file (referenced by position index) in the archive.
-renameFileIx :: Int  -- ^ Position index of a file in the archive.
-             -> FilePath -- ^ New name.
+renameFileIx :: Integer       -- ^ Position index of a file in the archive.
+             -> BS.ByteString -- ^ New name.
+             -> [FileFlag]    -- ^ Name encoding flags.
+                              -- 'FileENC_GUESS': guess encoding of the name (default).
+                              -- 'FileENC_UTF_8': interpret name as UTF-8.
+                              -- 'FileENC_CP437': interpret name as CP-437.
              -> Archive ()
-renameFileIx i newname = do
+renameFileIx i newname flags = do
   z <- getZip
-  r <- lift $ withCString newname $ c'zip_rename z (fromIntegral i)
+  r <- lift $ BS.useAsCString newname $ \s ->
+       c'zip_file_rename z (fromIntegral i) s (combine flags)
   if r == 0
      then return ()
      else lift $ get_error z >>= E.throwIO
 addFile :: FilePath   -- ^ Name of the file to create.
         -> ZipSource  -- ^ Source where file data is obtained from.
         -> Archive Int  -- ^ Position index of the new file.
-addFile name src = do
+addFile name src =
+  let utf8name = UTF8.fromString name
+  in  addFileWithFlags [FileENC_UTF_8] utf8name src
+
+addFileWithFlags
+    :: [FileFlag]   -- ^ Can be a combination of 'FileOVERWRITE' and/or one of
+                    -- filename encoding flags: 'FileENC_GUESS' (default),
+                    -- 'FileENC_UTF_8', 'FileENC_CP437'.
+    -> BS.ByteString   -- ^ Name of the file to create.
+    -> ZipSource       -- ^ Source where file data is obtained from.
+    -> Archive Int     -- ^ Position index of the new file.
+addFileWithFlags flags namebytes src = do
   z <- getZip
-  lift $ withCString name $ \name' -> do
-    i <- c'zip_add z name' src
+  lift $ BS.useAsCString namebytes $ \name' -> do
+    i <- c'zip_file_add z name' src (combine flags)
     if i < 0
        then c'zip_source_free src >> get_error z >>= E.throwIO
        else return $ fromIntegral i
 -- | Add a directory to the archive.
 addDirectory :: FilePath     -- ^ Directory's name in the archive.
              -> Archive Int  -- ^ Position index of the new directory entry.
-addDirectory name = do
+addDirectory name =
+  let utf8name = UTF8.fromString name
+  in  addDirectoryWithFlags [FileENC_UTF_8] utf8name
+
+-- | Add a directory to the archive.
+addDirectoryWithFlags
+    :: [FileFlag]        -- ^ Can be one of filename encoding flags:
+                         -- 'FileENC_GUESS (default), 'FileENC_UTF_8', 'FileENC_CP437'.
+    -> BS.ByteString     -- ^ Directory's name in the archive.
+    -> Archive Int       -- ^ Position index of the new directory entry.
+addDirectoryWithFlags flags name = do
   z <- getZip
-  r <- lift $ withCString name $ c'zip_add_dir z
+  r <- lift $ BS.useAsCString name $
+       \name'-> c'zip_dir_add z name' (combine flags)
   if r < 0
      then lift $ get_error z >>= E.throwIO
      else return (fromIntegral r)
 
 -- | Replace a file in the archive.
-replaceFile :: [FileFlag]  -- ^ Filename lookup mode.
+replaceFile :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
             -> FilePath    -- ^ File to replace.
             -> ZipSource   -- ^ Source where the new file data is obtained from.
             -> Archive ()
   maybe (lift $ c'zip_source_free src >> E.throwIO ErrNOENT)
         (\i -> replaceFileIx i src >> return ()) mbi
 
+-- | Set compression method for a file in the archive.
+setFileCompression
+    :: [FileFlag]   -- ^ Filename lookup mode (see 'nameLocate').
+    -> FilePath     -- ^ Filename.
+    -> ZipCompMethod  -- ^ Compression method.
+                      -- As of libzip 0.11, the following methods are supported:
+                      -- 'CompDEFAULT', 'CompSTORE', 'CompDEFLATE'.
+    -> Archive ()
+setFileCompression flags name method = do
+  mbi <- nameLocate flags name
+  maybe (lift $ E.throwIO ErrNOENT) (\i -> setFileCompressionIx i method) mbi
+
+-- | Set compression method for a file in the archive.
+setFileCompressionIx
+    :: Integer   -- ^ Position index of a file in the archive.
+    -> ZipCompMethod  -- ^ Compression method.
+                      -- As of libzip 0.11, the following methods are supported:
+                      -- 'CompDEFAULT', 'CompSTORE', 'CompDEFLATE'.
+    -> Archive ()
+setFileCompressionIx i method = do
+  z <- getZip
+  lift $ do
+    r <- c'zip_set_file_compression z (fromIntegral i) (fromIntegral . fromEnum $ method) 0
+    if r /= 0
+       then get_error z >>= E.throwIO
+       else return ()
+
 -- | 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
   z <- getZip
   lift $ do
-    r <- c'zip_replace z (fromIntegral i) src
+    r <- c'zip_file_replace z (fromIntegral i) src 0
     if r < 0
        then c'zip_source_free src >> get_error z >>= E.throwIO
        else return ()
 
 -- | 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
-      state <- peek (castPtr pState :: Ptr st)
-      case readSrc (src { srcState = state }) (fromIntegral len) state of
-        Just (len',bs,state') -> do
+      s <- peek (castPtr pState :: Ptr st)
+      case readSrc (src { srcState = s }) (fromIntegral len) s of
+        Just (len',bs,s') -> do
           pokeArray (castPtr pData :: Ptr Word8) (map (toEnum.fromEnum) bs)
-          poke (castPtr pState) state'
+          poke (castPtr pState) s'
           return (fromIntegral len')
         Nothing -> return (-1)
   | cmd == c'ZIP_SOURCE_CLOSE = return 0
       return $ fromIntegral (2 * sizeOf esys)
   | cmd == c'ZIP_SOURCE_FREE = return 0
   | otherwise = return (-1)
-        
+
 -- | Get zip archive comment.
-getComment :: [FileFlag]  -- ^ 'FileUNCHANGED' can be used.
+getComment :: [FileFlag]  -- ^ Can be a combination of 'FileUNCHANGED' and/or
+                          -- one of 'FileENC_GUESS' (default), 'FileENC_STRICT' (CP-437).
            -> Archive (Maybe String)
 getComment flags = do
   z <- getZip
          return (c,n)
   if  c == nullPtr
     then return Nothing
-    else lift $ peekCString c >>= return . Just . take (fromIntegral n)
+    else lift $ BS.packCStringLen (c, fromIntegral n) >>= return . Just . UTF8.toString
 
 -- | Set zip archive comment.
 setComment :: String   -- ^ Comment message.
            -> Archive ()
 setComment msg = do
   z <- getZip
-  r <- lift $ withCStringLen msg $ \(msg',i') ->
+  let utf8msg = UTF8.fromString msg
+  r <- lift $ BS.useAsCStringLen utf8msg $ \(msg',i') ->
        c'zip_set_archive_comment z msg' (fromIntegral i')
   if r < 0
      then lift $ get_error z >>= E.throwIO
      else return ()
 
 -- | Get comment for a file in the archive.
-getFileComment :: [FileFlag]  -- ^ Filename lookup mode.
+getFileComment :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
                -> FilePath    -- ^ Filename
                -> Archive (Maybe String)
 getFileComment flags name = do
   mbi <- nameLocate flags name
-  maybe (lift $ E.throwIO ErrNOENT) (getFileCommentIx flags) mbi
+  -- Backwards compatibility with LibZip < 0.11: FileUNCHANGED flag from
+  -- the filename lookup mode was used to get the original unchanged comment.
+  -- Please don't rely on this feature and use 'getFileCommentIx' instead.
+  let comment_flags = filter (== FileUNCHANGED) flags
+  maybe (lift $ E.throwIO ErrNOENT)
+            (\i -> do
+                 mbs <- getFileCommentIx comment_flags i
+                 -- 'FileENC_GUESS' is default => mbs is UTF-8 encoded
+                 return $ liftM UTF8.toString mbs
+            ) mbi
 
 -- | Get comment for a file in the archive (referenced by position index).
-getFileCommentIx :: [FileFlag]  -- ^ FileUNCHANGED can be used.
-                 -> Int         -- ^ Position index of the file.
-                 -> Archive (Maybe String)
+getFileCommentIx :: [FileFlag]  -- ^ Comment lookup flags.
+                          --   'FileUNCHANGED':  return the original unchanged comment.
+                          --   'FileENC_RAW':    return the unmodified commment as it is.
+                          --   'FileENC_GUESS':  (default) guess the encoding of the comment
+                          --                     and convert it to UTF-8, if necessary.
+                          --   'FileENC_STRICT': follow the ZIP specification for file names
+                          --                     and extend it to file comments, expect
+                          --                     them to be encoded in CP-437. Convert it
+                          --                     to UTF-8.
+                 -> Integer     -- ^ Position index of the file.
+                 -> Archive (Maybe BS.ByteString)
 getFileCommentIx flags i = do
   z <- getZip
   (c,n) <- lift $ alloca $ \lenp -> do
-           c <- c'zip_get_file_comment z (fromIntegral i) lenp (combine flags)
+           c <- c'zip_file_get_comment z (fromIntegral i) lenp (combine flags)
            n <- peek lenp
            return (c,n)
   if c == nullPtr
      then return Nothing
-     else lift $ peekCString c >>= return . Just . take (fromIntegral n)
+     else lift $ BS.packCStringLen (c,fromIntegral n) >>= return . Just
 
 -- | Set comment for a file in the archive.
-setFileComment :: [FileFlag]   -- ^ Name lookup mode.
+setFileComment :: [FileFlag]   -- ^ Filename lookup mode (see 'nameLocate').
                -> FilePath     -- ^ Filename.
                -> String       -- ^ New file comment.
                -> Archive ()
 setFileComment flags path comment = do
   mbi <- nameLocate flags path
-  maybe (lift $ E.throwIO ErrNOENT) (flip setFileCommentIx comment) mbi
+  let utf8comment = UTF8.fromString comment
+  let cflags = [FileENC_UTF_8]
+  maybe (lift $ E.throwIO ErrNOENT)
+            (\i -> setFileCommentIx i utf8comment cflags)
+            mbi
 
 -- | Set comment for a file in the archive (referenced by position index).
-setFileCommentIx :: Int        -- ^ Position index of a file in the archive.
-                 -> String     -- ^ New file comment. 
+setFileCommentIx :: Integer        -- ^ Position index of a file in the archive.
+                 -> BS.ByteString  -- ^ New file comment.
+                 -> [FileFlag]     -- ^ Comment encoding flags.
+                                   -- 'FileENC_GUESS': guess encoding of the comment (default).
+                                   -- 'FileENC_UTF_8': interpret comment as UTF-8.
+                                   -- 'FileENC_CP437': interpret comment as CP-437.
                  -> Archive ()
-setFileCommentIx i comment = do
+setFileCommentIx i comment cflags = do
   z <- getZip
-  r <- lift $ withCStringLen comment $ \(msg,len) ->
-       c'zip_set_file_comment z (fromIntegral i) msg (fromIntegral len)
+  r <- lift $ BS.useAsCStringLen comment $ \(msg,len) ->
+       c'zip_file_set_comment z (fromIntegral i) msg (fromIntegral len) (combine cflags)
   if r < 0
      then lift $ get_error z >>= E.throwIO
      else return ()
 
 -- | Remove comment for a file in the archive.
-removeFileComment :: [FileFlag]  -- ^ Filename lookup mode.
+removeFileComment :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
                   -> FilePath    -- ^ Filename.
                   -> Archive ()
 removeFileComment flags path = 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
+  let flags = 0   -- file name encoding flags (*_FL_*) are irrelevant
   z <- getZip
-  r <- lift $ c'zip_set_file_comment z (fromIntegral i) nullPtr 0
+  r <- lift $ c'zip_file_set_comment z (fromIntegral i) nullPtr 0 flags
   if r < 0
      then lift $ get_error z >>= E.throwIO
      else return ()
 
 -- | Undo changes to a file in the archive.
-unchangeFile :: [FileFlag]  -- ^ Filename lookup mode.
+unchangeFile :: [FileFlag]  -- ^ Filename lookup mode (see 'nameLocate').
              -> FilePath    -- ^ Filename.
              -> Archive ()
 unchangeFile flags name = do
   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

  • Ignore whitespace
--- | 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

View file
  • Ignore whitespace
     , toZipStat
     , OpenFlag(..)
     , FileFlag(..)
+    , ArchiveFlag(..)
+    , CodecFlag(..)
     , ZipError(..)
     , ZipCompMethod(..)
     , ZipEncryptionMethod(..)
     , combine
     ) where
-    
+
 import Data.Bits ((.|.))
 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)
 type ZipFile = Ptr C'zip_file
 
 -- | Handler of data source for new files in the zip archive.
+-- Constructors: 'sourceBuffer', 'sourceFile', 'sourceZip', 'sourcePure'.
 type ZipSource = Ptr C'zip_source
 
 -- |  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.
 data OpenFlag
   = CreateFlag      -- ^ Create an archive if it does not exist.
   | ExclFlag        -- ^ Error if the archive already exists.
   | CheckConsFlag   -- ^ Check archive's consistency and error on failure.
+  | TruncateFlag    -- ^ If archive exists, ignore its current content.
   deriving (Show,Eq)
 
 instance Enum OpenFlag where
   fromEnum CheckConsFlag = c'ZIP_CHECKCONS
   fromEnum CreateFlag = c'ZIP_CREATE
   fromEnum ExclFlag = c'ZIP_EXCL
+  fromEnum TruncateFlag = c'ZIP_TRUNCATE
   toEnum x | x == c'ZIP_CHECKCONS = CheckConsFlag
   toEnum x | x == c'ZIP_CREATE = CreateFlag
   toEnum x | x == c'ZIP_EXCL = ExclFlag
+  toEnum x | x == c'ZIP_TRUNCATE = TruncateFlag
   toEnum _ = undefined
 
 -- | Flags for accessing files in the archive.
   | FileCOMPRESSED  -- ^ Read the compressed data.
   | FileUNCHANGED   -- ^ Read the original data, ignore changes.
   | FileRECOMPRESS  -- ^ Force recompression of data.
+  | FileENCRYPTED   -- ^ Read encrypted data (implies FileCOMPRESSED).
+  | FileENC_GUESS   -- ^ Guess string encoding (default).
+  | FileENC_RAW     -- ^ Get unmodified string.
+  | FileENC_STRICT  -- ^ Follow specification strictly.
+  | FileLOCAL       -- ^ In local header.
+  | FileCENTRAL     -- ^ In central directory.
+  | FileENC_UTF_8   -- ^ String is UTF-8 encoded.
+  | FileENC_CP437   -- ^ String is CP437 encoded.
+  | FileOVERWRITE   -- ^ When adding files: if file name exists, overwrite.
   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
+  fromEnum FileENC_GUESS = c'ZIP_FL_ENC_GUESS
+  fromEnum FileENC_RAW = c'ZIP_FL_ENC_RAW
+  fromEnum FileENC_STRICT = c'ZIP_FL_ENC_STRICT
+  fromEnum FileLOCAL = c'ZIP_FL_LOCAL
+  fromEnum FileCENTRAL = c'ZIP_FL_CENTRAL
+  fromEnum FileENC_UTF_8 = c'ZIP_FL_ENC_UTF_8
+  fromEnum FileENC_CP437 = c'ZIP_FL_ENC_CP437
+  fromEnum FileOVERWRITE = c'ZIP_FL_OVERWRITE
   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 x | x == c'ZIP_FL_ENC_GUESS = FileENC_GUESS
+  toEnum x | x == c'ZIP_FL_ENC_RAW = FileENC_RAW
+  toEnum x | x == c'ZIP_FL_ENC_STRICT = FileENC_STRICT
+  toEnum x | x == c'ZIP_FL_LOCAL = FileLOCAL
+  toEnum x | x == c'ZIP_FL_CENTRAL = FileCENTRAL
+  toEnum x | x == c'ZIP_FL_ENC_UTF_8 = FileENC_UTF_8
+  toEnum x | x == c'ZIP_FL_ENC_CP437 = FileENC_CP437
+  toEnum x | x == c'ZIP_FL_OVERWRITE = FileOVERWRITE
   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
+    | CodecDECODE
+    deriving (Show, Eq)
+
+instance Enum CodecFlag where
+    fromEnum CodecENCODE = c'ZIP_CODEC_ENCODE
+    fromEnum CodecDECODE = c'ZIP_CODEC_DECODE
+    toEnum x | x == c'ZIP_CODEC_ENCODE = CodecENCODE
+    toEnum x | x == c'ZIP_CODEC_DECODE = CodecDECODE
+    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/LICENSE

View file
  • Ignore whitespace
-Copyright (c) 2009, 2010, Sergey Astanin
+Copyright (c) 2009-2013, Sergey Astanin
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without

File LibZip/LibZip.cabal

View file
  • Ignore whitespace
 Name:          LibZip
-Version:       0.2.0.4
+Version:       0.11
 License:       BSD3
 License-File:  LICENSE
 Author:        Sergey Astanin
 Maintainer:    Sergey Astanin <s.astanin@gmail.com>
-Homepage:      http://bitbucket.org/jetxee/hs-libzip/
-Bug-reports:   http://bitbucket.org/jetxee/hs-libzip/issues/
+Homepage:      http://bitbucket.org/astanin/hs-libzip/
+Bug-reports:   http://bitbucket.org/astanin/hs-libzip/issues/
 
 Category:      Codec, Foreign
 Synopsis:      Bindings to libzip, a library for manipulating zip archives.
   This package allows to use it from Haskell code.
 
 Build-Type:     Simple
-Cabal-Version:  >= 1.2.3
-Tested-With:    GHC == 7.0.1, GHC == 7.2.1, GHC == 7.4.1
+Cabal-Version:  >= 1.8
 
 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
+      base >= 4.0
+    , bindings-libzip >= 0.11 && < 0.12
     , bytestring
     , filepath
     , time
     , mtl
+    , bytestring
+    , utf8-string
   GHC-Options:
       -Wall
 
+Test-Suite test-libzip
+  Type:                 exitcode-stdio-1.0
+  Main-Is:              runTests.hs
+  Build-Depends:
+      LibZip
+    , base >= 4.0
+    , bindings-libzip >= 0.11 && < 0.12
+    , directory
+    , filepath
+    , HUnit
+    , mtl
+    , time
+    , bytestring
+    , utf8-string

File LibZip/Setup.lhs

View file
  • Ignore whitespace
 #!/usr/bin/env runhaskell
+> module Main where
+>
 > import Distribution.Simple
-> import System.Cmd (system)
-> import System.Exit (ExitCode(..))
-> import Distribution.PackageDescription (emptyHookedBuildInfo)
 >
-> main = defaultMainWithHooks simpleUserHooks
->   { runTests = runUnitTests
->   }
->
->
-> runUnitTests _ _ _ _ =
->   system "runhaskell -lzip -fno-warn-warnings-deprecations runTests.hs" >>=
->   onExit "\nSome tests did not pass." ()
->
-> onExit :: String -> a -> ExitCode -> IO a
-> onExit errmsg okvalue r =
->   case r of
->     ExitSuccess -> return okvalue
->     _           -> fail errmsg
+> main :: IO ()
+> main = defaultMain

File LibZip/Tests/Common.hs

View file
  • Ignore whitespace
 module Tests.Common
-    ( testzip, testfiles, lastfile, lastfilesize
+    ( testzip, encryptedzip, testfiles, lastfile, lastfilesize
     , world_txt
     , toUpper, toLower, map2
     ) where
 import Data.Char (toUpper, toLower)
 
 testzip = "Tests/test.zip"
+encryptedzip = "Tests/encrypted.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

  • Ignore whitespace
-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

View file
  • Ignore whitespace
 import Foreign.Storable
 import Foreign.Ptr (Ptr, castPtr)
 
+import Control.Monad (liftM2)
 import System.Directory (doesFileExist, getTemporaryDirectory, removeFile)
 import System.FilePath ((</>))
+import System.IO (openFile, hClose, hFileSize, IOMode(..))
 import Test.HUnit
 import qualified Control.Exception as E
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.UTF8 as UTF8
 
 monadicTests = TestList
   [ "read list of files" ~: do
       files <- withArchive [] testzip $ fileNames []
       files @?= testfiles
+
   , "read file size" ~: do
       sz <- withArchive [] testzip $ fileSize [] lastfile
       sz @?= lastfilesize
+
   , "case-insensitive file names" ~: do
       sz <- withArchive [] testzip $
               fileSize [FileNOCASE] (map2 toUpper toLower $ lastfile)
       sz @?= lastfilesize
+
   , "open error if exists (with ExclFlag)" ~: do
       err <- catchZipError
              (withArchive [ExclFlag] testzip $ lift $ E.throwIO ErrOK)
              (return . id)
       err @?= ErrEXISTS
+
   , "open error if archive does not exists" ~: do
       err <- catchZipError
              (withArchive [] "notexists.zip" $ return ErrOK)
              (return . id)
       err @?= ErrOPEN
+
   , "read file" ~: do
       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 $
                fromFile [] lastfile $ do
                   skipBytes 13
                   readBytes 10
       txt @?= (take 10 . drop 13 $ world_txt)
+
   , "create an archive/use sourceBuffer" ~: do
       tmpzip <- getTmpFileName "test_LibZip_sourceBuffer.zip"
       i <- withArchive [CreateFlag] tmpzip $ do
            txt <- withArchive [] f $ fileContents [] "hello/world.txt"
            removeFile f
            (txt, i) @?= (world_txt, 1)
+
+  , "create an archive with Unicode filenames" ~: do
+      tmpzip <- getTmpFileName "test_LibZip_unicode_filenames.zip"
+      let dir = "\x4e16\x754c"
+      let name1 = "\x4e16\x754c/привет.txt"
+      let name2 = "\x4e16\x754c/мир.txt"
+      i <- withArchive [CreateFlag] tmpzip $ do
+           addDirectory dir
+           addFile name1 =<< sourceBuffer world_txt
+           addFileWithFlags [FileENC_UTF_8] (UTF8.fromString name2) =<< sourceBuffer world_txt
+      tmpzip `doesExistAnd` \f -> do
+           names <- withArchive [] f $ fileNames []
+           removeFile f
+           names @?= [dir ++ "/", name1, name2]
+
   , "create an archive/use sourceFile" ~: do
       tmpzip <- getTmpFileName "test_LibZip_sourceFile.zip"
       tmpsrc <- getTmpFileName "test_LibZip_sourceFile.txt"
            removeFile tmpzip
            removeFile tmpsrc
            txt @?= world_txt
+
   , "create an archive/use sourceZip" ~: do
       tmpzip <- getTmpFileName "test_LibZip_sourceZip.zip"
       withArchive [] testzip $ do
            txt <- withArchive [] f $ fileContents [] "world.txt"
            removeFile tmpzip
            txt @?= world_txt
+
   , "create an archive/use sourcePure" ~: do
       tmpzip <- getTmpFileName "test_LibZip_sourcePure.zip"
       let src = PureSource
            txt <- withArchive [] f $ fileContents [] "world.txt"
            removeFile tmpzip
            txt @?= world_txt
+
   , "delete a file" ~: do
       let orig = [("one", "one"), ("two", "two")]
       let final = init orig
       fs_final <- withArchive [] tmpzip $ fileNames []
       removeFile tmpzip
       (fs_orig, fs_final) @?= (map fst orig, map fst final)
+
   , "attempt to delete a non-existing file" ~: do
       tmpzip <- getTmpFileName "test_LibZip_delete_ne.zip"
       mkArchive tmpzip [("world.txt", world_txt)]
             (return . id)
       removeFile tmpzip
       (r1, r2) @?= (ErrNOENT, ErrINVAL)
+
   , "rename a file" ~: do
       tmpzip <- getTmpFileName "test_LibZip_rename.zip"
       mkArchive tmpzip [("world.txt", world_txt)]
               fileNames []
       removeFile tmpzip
       fs @?= ["hello.txt"]
+
   , "attempt to rename a non-existing file" ~: do
       tmpzip <- getTmpFileName "test_LibZip_rename_ne.zip"
       mkArchive tmpzip [("world.txt", world_txt)]
             (return . id)
       removeFile tmpzip
       r @?= ErrNOENT
-  , "attempt to rename to an empty name" ~: do
-      tmpzip <- getTmpFileName "test_LibZip_rename_inval.zip"
-      mkArchive tmpzip [("world.txt", world_txt)]
-      r <- catchZipError
-             (withArchive [] tmpzip $ do
-              renameFile [] "world.txt" ""
-              return ErrOK)
-             (return . id)
-      removeFile tmpzip
-      r @?= ErrINVAL
+
+  -- -- libzip 0.11 renames an entry to an empty string without errors;
+  -- the test is disabled.
+  --
+  -- , "attempt to rename to an empty name" ~: do
+  --     tmpzip <- getTmpFileName "test_LibZip_rename_inval.zip"
+  --     mkArchive tmpzip [("world.txt", world_txt)]
+  --     r <- catchZipError
+  --            (withArchive [] tmpzip $ do
+  --             renameFile [] "world.txt" ""
+  --             return ErrOK)
+  --            (return . id)
+  --     removeFile tmpzip
+  --     r @?= ErrINVAL
+
   , "replace a file" ~: do
       tmpzip <- getTmpFileName "test_LibZip_replace.zip"
       mkArchive tmpzip [("hello/",""), ("hello/world.txt", "old contents")]
               replaceFile [] "hello/world.txt" =<< sourceBuffer world_txt
       txt <- withArchive [] tmpzip $ fileContents [] "hello/world.txt"
       txt @?= world_txt
+      removeFile tmpzip
+
+  , "set file compression method" ~: do
+      tmpzip1 <- getTmpFileName "test_LibZip_compression_DEFLATE.zip"
+      tmpzip2 <- getTmpFileName "test_LibZip_compression_some.zip"
+      tmpzip3 <- getTmpFileName "test_LibZip_compression_STORE.zip"
+      -- archive contents with high level of duplicity (compressibility)
+      let long_text = concat $ replicate 100 world_txt
+      let contents = [ ("hello.txt", long_text), ("world.txt", long_text) ]
+      -- all files are compressed
+      mkArchive tmpzip1 contents
+      withArchive [] tmpzip1 $ do
+        n <- numFiles []
+        flip mapM_ [0..n-1] $ \i -> setFileCompressionIx i CompDEFLATE
+      -- only some files are compessed
+      mkArchive tmpzip2 contents
+      withArchive [] tmpzip2 $ do
+        setFileCompression [] "hello.txt" CompSTORE
+        setFileCompression [] "world.txt" CompDEFLATE
+      -- uncompressed archive
+      mkArchive tmpzip3 contents
+      withArchive [] tmpzip3 $ do
+        n <- numFiles []
+        flip mapM_ [0..n-1] $ \i -> setFileCompressionIx i CompSTORE
+      -- compare file sizes
+      sz1 <- getFileSize tmpzip1
+      sz2 <- getFileSize tmpzip2
+      sz3 <- getFileSize tmpzip3
+      removeFile tmpzip1
+      removeFile tmpzip2
+      removeFile tmpzip3
+      (liftM2 (<) sz1 sz2, liftM2 (<) sz2 sz3) @?= (Just True, Just True)
+
   , "set/get/remove archive comment" ~: do
       c1 <- withArchive [] testzip $ getComment []
       tmpzip <- getTmpFileName "test_LibZip_comment.zip"
       withArchive [] tmpzip $ removeComment
       c2_removed <- withArchive [] tmpzip $ getComment []
       removeFile tmpzip
-      (c1, c2, c2_added, c2_removed) @?= (Nothing, Nothing, Just com, Nothing)
+      -- libzip-0.11 returns an empty string, instead of NULL pointer in 0.10.
+      -- Haskell LibZip reflects it by returning Just "" rather than Nothing.
+      (c1, c2, c2_added, c2_removed) @?= (Just "", Just "", Just com, Just "")
+
+  , "set/get Unicode archive comment" ~: do
+      tmpzip <- getTmpFileName "test_LibZip_Unicode_comment.zip"
+      mkArchive tmpzip [("hello/",""), ("hello/world.txt", world_txt)]
+      let unicodeComment = "Привет, мир!"
+      withArchive [] tmpzip $ setComment unicodeComment
+      comment <- withArchive [] tmpzip $ getComment []
+      removeFile tmpzip
+      comment @?= (Just unicodeComment)
+
   , "set/get/remove file comment" ~: do
       tmpzip <- getTmpFileName "test_LibZip_file_comment.zip"
       let world_path = "hello/world.txt"
       withArchive [] tmpzip $ removeFileComment [] world_path
       c_off' <- get_comm
       removeFile tmpzip
-      (c_off, c_on, c_off') @?= (Nothing, Just world_comm, Nothing)
+      -- libzip-0.11 returns an empty string, instead of NULL pointer in 0.10.
+      -- Haskell LibZip reflects it by returning Just "" rather than Nothing.
+      (c_off, c_on, c_off') @?= (Just "", Just world_comm, Just "")
+
+  , "set/get Unicode file comment" ~: do
+      tmpzip <- getTmpFileName "test_LibZip_file_comment.zip"
+      let world_path = "hello/world.txt"
+      let world_comm = "\1087\1088\1080\1074\1077\1090"
+      let world_comm2 = [208,188,208,184,209,128]
+      mkArchive tmpzip [("hello/",undefined), (world_path,world_txt)]
+      let get_comm = withArchive [] tmpzip $ getFileComment [] world_path
+      c_off <- get_comm
+      withArchive [] tmpzip $ setFileComment [] world_path world_comm
+      c_on <- get_comm
+      withArchive [] tmpzip $ setFileCommentIx 1 (BS.pack world_comm2) [FileENC_UTF_8]
+      c_on2 <- get_comm
+      removeFile tmpzip
+      (c_off, c_on, c_on2) @?= (Just "", Just "привет", Just "мир")
+
   , "unchange file" ~: do
       tmpzip <- getTmpFileName "test_LibZip_unchange_file.zip"
       mkArchive tmpzip [("world.txt",world_txt)]
                           unchangeFile [] "world.txt"
                           getFileComment [] "world.txt"
       removeFile tmpzip
-      c @?= Nothing
+      -- libzip-0.11 returns an empty string, instead of NULL pointer in 0.10.
+      -- Haskell LibZip reflects it by returning Just "" rather than Nothing.
+      c @?= Just ""
+
   , "unchange archive" ~: do
       tmpzip <- getTmpFileName "test_LibZip_unchange.zip"
       mkArchive tmpzip [("world.txt",world_txt)]
                           unchangeArchive
                           getComment []
       removeFile tmpzip
-      c @?= Nothing
+      -- libzip-0.11 returns an empty string, instead of NULL pointer in 0.10.
+      -- Haskell LibZip reflects it by returning Just "" rather than Nothing.
+      c @?= Just ""
+
   , "unchange all" ~: do
       tmpzip <- getTmpFileName "test_LibZip_unchange_all.zip"
       mkArchive tmpzip [("world.txt",world_txt)]
                           c2 <- getFileComment [] "world.txt"
                           return (c1,c2)
       removeFile tmpzip
-      c @?= (Nothing,Nothing)
+      -- libzip-0.11 returns an empty string, instead of NULL pointer in 0.10.
+      -- Haskell LibZip reflects it by returning Just "" rather than Nothing.
+      c @?= (Just "", Just "")
 
+  , "read a file from an encrypted archive" ~: do
+      txt <- withEncryptedArchive [] "purity" encryptedzip $ fileContents [] lastfile
+      txt @?= world_txt
+      -- libzip-0.11 doesn't support creating encrypted archives yet
   ]
 
 getTmpFileName basename = do
 
 mkArchive :: (Enum a) => FilePath -> [(FilePath, [a])] -> IO ()
 mkArchive zipname contents =
-  withArchive [CreateFlag] zipname $
+  withArchive [CreateFlag] zipname $ populateArchive contents
+
+populateArchive :: (Enum a) => [(FilePath, [a])] -> Archive ()
+populateArchive contents =
     mapM_ (\(f,d) ->
                if last f == '/'
                   then addDirectory f
                   else addFile f =<< sourceBuffer d
           ) contents
-  
 
-  
+getFileSize :: FilePath -> IO (Maybe Integer)
+getFileSize path =
+    E.handle handler $
+     E.bracket (openFile path ReadMode) (hClose) $
+          \h -> do
+            size <- hFileSize h
+            return $ Just size
+  where
+    handler :: E.SomeException -> IO (Maybe Integer)
+    handler _ = return Nothing

File LibZip/Tests/encrypted.zip

  • Ignore whitespace
Binary file added.

File LibZip/examples/hzip.hs

View file
  • Ignore whitespace
 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

  • Ignore whitespace
--- 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

View file
  • Ignore whitespace
-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

View file
  • Ignore whitespace
 #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.11. 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
 
 #opaque_t zip
 #opaque_t zip_file
 #opaque_t zip_source
+#integral_t zip_flags_t
 
 -- flags for zip_open
 
 #num ZIP_CREATE
 #num ZIP_EXCL
 #num ZIP_CHECKCONS
+#num ZIP_TRUNCATE
 
 -- flags for zip_name_locate, zip_fopen, zip_stat, ...
 
 #num ZIP_FL_COMPRESSED
 #num ZIP_FL_UNCHANGED
 #num ZIP_FL_RECOMPRESS
+#num ZIP_FL_ENCRYPTED
+#num ZIP_FL_ENC_GUESS
+#num ZIP_FL_ENC_RAW
+#num ZIP_FL_ENC_STRICT
+#num ZIP_FL_LOCAL
+#num ZIP_FL_CENTRAL
+#num ZIP_FL_ENC_UTF_8
+#num ZIP_FL_ENC_CP437
+#num ZIP_FL_OVERWRITE
+
 
 -- archive global flags flags
 
 #num ZIP_AFL_TORRENT
+#num ZIP_AFL_RDONLY
+
+-- new extra field
+
+#num ZIP_EXTRA_FIELD_ALL
+#num ZIP_EXTRA_FIELD_NEW
+
+-- flags for compression and encryption sources
+
+#num ZIP_CODEC_DECODE
+#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 regexp: struct \([a-z0-9_]*\) \* -> Ptr <\1> )
+--    FILE -> CFile
+--    int -> CInt
+--    zip_uint8_t -> CUChar
+--    zip_int16_t -> CShort
+--    zip_uint16_t -> CUShort
+--    zip_int32_t -> CInt
+--    zip_uint32_t -> CUInt
+--    zip_int64_t -> CLLong
+--    zip_uint64_t -> CULLong
+--    void -> ()
+--    const ->
+--    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
+-- deprecated API
 
--- int zip_close(struct zip *);
-#ccall zip_close , Ptr <zip> -> IO CInt
+#ccall zip_add , Ptr <zip> -> CString -> Ptr <zip_source> -> IO (CLLong)
+#ccall zip_add_dir , Ptr <zip> -> CString -> IO (CLLong)
+#ccall zip_get_file_comment , Ptr <zip> -> CULLong -> Ptr CInt -> CInt -> IO (CString)
+#ccall zip_get_num_files , Ptr <zip> -> IO (CInt)
+#ccall zip_rename , Ptr <zip> -> CULLong -> CString -> IO (CInt)
+#ccall zip_replace , Ptr <zip> -> CULLong -> Ptr <zip_source> -> IO (CInt)
+#ccall zip_set_file_comment , Ptr <zip> -> CULLong -> CString -> CInt -> IO (CInt)
 
--- int zip_delete(struct zip *, int);
-#ccall zip_delete , Ptr <zip> -> CInt -> IO CInt
+-- the rest of the API
 
--- void zip_error_clear(struct zip *);
+#ccall zip_archive_set_tempdir , Ptr <zip> -> CString -> IO (CInt)
+#ccall zip_file_add , Ptr <zip> -> CString -> Ptr <zip_source> -> <zip_flags_t> -> IO (CLLong)
+#ccall zip_dir_add , Ptr <zip> -> CString -> <zip_flags_t> -> IO (CLLong)
+#ccall zip_close , Ptr <zip> -> IO (CInt)
+#ccall zip_discard , Ptr <zip> -> IO ()
+#ccall zip_delete , Ptr <zip> -> CULLong -> IO (CInt)
+#ccall zip_file_extra_field_delete , Ptr <zip> -> CULLong -> CUShort -> <zip_flags_t> -> IO (CInt)
+#ccall zip_file_extra_field_delete_by_id , Ptr <zip> -> CULLong -> CUShort -> CUShort -> <zip_flags_t> -> 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_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_file_strerror , Ptr <zip_file> -> IO (CString)
+#ccall zip_fopen , Ptr <zip> -> CString -> <zip_flags_t> -> IO (Ptr <zip_file>)
+#ccall zip_fopen_encrypted , Ptr <zip> -> CString -> <zip_flags_t> -> CString -> IO (Ptr <zip_file>)
+#ccall zip_fopen_index , Ptr <zip> -> CULLong -> <zip_flags_t> -> IO (Ptr <zip_file>)
+#ccall zip_fopen_index_encrypted , Ptr <zip> -> CULLong -> <zip_flags_t> -> CString -> IO (Ptr <zip_file>)
+#ccall zip_fread , Ptr <zip_file> -> Ptr () -> CULLong -> IO (CLLong)
+#ccall zip_get_archive_comment , Ptr <zip> -> Ptr CInt -> <zip_flags_t> -> IO (CString)
+#ccall zip_get_archive_flag , Ptr <zip> -> <zip_flags_t> -> <zip_flags_t> -> IO (CInt)
+#ccall zip_file_get_comment , Ptr <zip> -> CULLong -> Ptr CUInt -> <zip_flags_t> -> IO (CString)
+#ccall zip_file_extra_field_get , Ptr <zip> -> CULLong -> CUShort -> Ptr CUShort -> Ptr CUShort -> <zip_flags_t> -> IO (Ptr CUChar)
+#ccall zip_file_extra_field_get_by_id , Ptr <zip> -> CULLong -> CUShort -> CUShort -> Ptr CUShort -> <zip_flags_t> -> IO (Ptr CUChar)
+#ccall zip_file_extra_fields_count , Ptr <zip> -> CULLong -> <zip_flags_t> -> IO (CShort)
+#ccall zip_file_extra_fields_count_by_id , Ptr <zip> -> CULLong -> CUShort -> <zip_flags_t> -> IO (CShort)
+#ccall zip_get_name , Ptr <zip> -> CULLong -> <zip_flags_t> -> IO (CString)
+#ccall zip_get_num_entries , Ptr <zip> -> <zip_flags_t> -> IO (CLLong)
+#ccall zip_name_locate , Ptr <zip> -> CString -> <zip_flags_t> -> IO (CLLong)
 #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_file_rename , Ptr <zip> -> CULLong -> CString -> <zip_flags_t> -> IO (CInt)
+#ccall zip_file_replace , Ptr <zip> -> CULLong -> Ptr <zip_source> -> <zip_flags_t> -> IO (CInt)
+#ccall zip_set_archive_comment , Ptr <zip> -> CString -> CUShort -> IO (CInt)
+#ccall zip_set_archive_flag , Ptr <zip> -> <zip_flags_t> -> CInt -> IO (CInt)
+#ccall zip_set_default_password , Ptr <zip> -> CString -> IO (CInt)
+#ccall zip_file_set_comment , Ptr <zip> -> CULLong -> CString -> CUShort -> <zip_flags_t> -> IO (CInt)
+#ccall zip_set_file_compression , Ptr <zip> -> CULLong -> CInt -> CUInt -> IO (CInt)
+#ccall zip_file_extra_field_set , Ptr <zip> -> CULLong -> CUShort -> CUShort -> Ptr CUChar -> CUShort -> <zip_flags_t> -> 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 -> <zip_flags_t> -> CULLong -> CLLong -> IO (Ptr <zip_source>)
+#ccall zip_stat , Ptr <zip> -> CString -> <zip_flags_t> -> Ptr <zip_stat> -> IO (CInt)
+#ccall zip_stat_index , Ptr <zip> -> CULLong -> <zip_flags_t> -> 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/LICENSE

View file
  • Ignore whitespace
-Copyright Sergey Astanin 2010
+Copyright Sergey Astanin 2010-2013
 
 All rights reserved.
 

File bindings-libzip/bindings-libzip.cabal

View file
  • Ignore whitespace
 Name:                bindings-libzip
-Version:             0.1.0.4
+Version:             0.11
 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.11) library.
   For higher-level interface please use LibZip package:
   <http://hackage.haskell.org/package/LibZip>
 
-Homepage:            http://bitbucket.org/jetxee/hs-libzip/
+Homepage:            http://bitbucket.org/astanin/hs-libzip/
 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
 
 Flag NoPkgConfig
   Description: Do not use pkg-config to check for library dependencies.
         Bindings.LibZip
 
   Build-Depends:
-        base >= 4.0 && < 4.6