Imported Upstream version 1.3.0 14/155014/1 upstream/1.3.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 12 Oct 2017 01:07:04 +0000 (10:07 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 12 Oct 2017 01:07:05 +0000 (10:07 +0900)
Change-Id: Ibd9f73ba201b84aadf496c1e7bdb1043505b5d08
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
65 files changed:
.hgtags
CMakeLists.txt
NEWS.md
README-snapshot.md
README.md
THANKS
TODO.md
cmake-config.h.in
configure.ac
lib/CMakeLists.txt
lib/Makefile.am
lib/compat.h
lib/mkstemp.c
lib/zip.h
lib/zip_algorithm_bzip2.c [new file with mode: 0644]
lib/zip_algorithm_deflate.c [new file with mode: 0644]
lib/zip_close.c
lib/zip_dirent.c
lib/zip_discard.c
lib/zip_err_str.c
lib/zip_fdopen.c
lib/zip_hash.c
lib/zip_new.c
lib/zip_open.c
lib/zip_progress.c [new file with mode: 0644]
lib/zip_random_unix.c
lib/zip_set_file_compression.c
lib/zip_source_compress.c [new file with mode: 0644]
lib/zip_source_crc.c
lib/zip_source_deflate.c [deleted file]
lib/zip_source_filep.c
lib/zip_source_get_compression_flags.c [moved from lib/zip_get_compression_implementation.c with 70% similarity]
lib/zip_source_win32a.c
lib/zip_source_win32w.c
lib/zip_source_window.c
lib/zip_source_zip_new.c
lib/zip_unchange_all.c
lib/zipint.h
man/zip_name_locate.mdoc
man/zip_set_file_compression.mdoc
man/zipmerge.mdoc
regress/CMakeLists.txt
regress/Makefile.am
regress/NiHTest.pm
regress/bigstored.zh
regress/encrypt-aes128-noentropy.zip
regress/encrypt-aes192-noentropy.zip
regress/encrypt-aes256-noentropy.zip
regress/encrypt-none.zip
regress/fdopen_ok.test [new file with mode: 0644]
regress/nonrandomopen.c
regress/runtest.in
regress/set_compression_bzip2_to_deflate.test [new file with mode: 0644]
regress/set_compression_deflate_to_bzip2.test [new file with mode: 0644]
regress/set_compression_store_to_bzip2.test [new file with mode: 0644]
regress/testbzip2.zip [new file with mode: 0644]
regress/tryopen.c
regress/utf-8-standardization-output.zip
regress/utf-8-standardization.test
src/zipcmp.c
src/zipmerge.c
src/ziptool.c
vstudio/vsbuild.cmd
xcode/config.h
xcode/libzip.xcodeproj/project.pbxproj

diff --git a/.hgtags b/.hgtags
index 0f2335e..989d2e2 100644 (file)
--- a/.hgtags
+++ b/.hgtags
@@ -19,3 +19,4 @@ bdc57015a9a903b1ec935295d77e54cb90800b3f brian-gladman-fcrypt-2008-11-18
 aefb3263e2449b0b62095b2e50e9010d073fb670 s
 aefb3263e2449b0b62095b2e50e9010d073fb670 s
 0000000000000000000000000000000000000000 s
+c43a9681c5ca2d577636a75dc1f29b384c82f51a rel-1-2-0
index d443757..b979444 100644 (file)
@@ -3,6 +3,7 @@
 # 2. installation not tested.
 # 3. Problems generating html pages.
 # 4. create usable libtool .la file
+# 5. runtest not created
 
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
@@ -20,7 +21,7 @@ INCLUDE(TestBigEndian)
 SET(PACKAGE "libzip")
 SET(PACKAGE_NAME ${PACKAGE})
 SET(PACKAGE_VERSION_MAJOR "1")
-SET(PACKAGE_VERSION_MINOR "2")
+SET(PACKAGE_VERSION_MINOR "3")
 SET(PACKAGE_VERSION_PATCH "0")
 #SET(VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}")
 SET(VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}")
@@ -29,6 +30,7 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 
 # Checks
 
+CHECK_FUNCTION_EXISTS(_chmod HAVE__CHMOD)
 CHECK_FUNCTION_EXISTS(_close HAVE__CLOSE)
 CHECK_FUNCTION_EXISTS(_dup HAVE__DUP)
 CHECK_FUNCTION_EXISTS(_fdopen HAVE__FDOPEN)
@@ -40,6 +42,8 @@ CHECK_FUNCTION_EXISTS(_strdup HAVE__STRDUP)
 CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
 CHECK_FUNCTION_EXISTS(_strtoi64 HAVE__STRTOI64)
 CHECK_FUNCTION_EXISTS(_strtoui64 HAVE__STRTOUI64)
+CHECK_FUNCTION_EXISTS(_umask HAVE__UMASK)
+CHECK_FUNCTION_EXISTS(_unlink HAVE__UNLINK)
 CHECK_FUNCTION_EXISTS(explict_bzero HAVE_EXPLICIT_BZERO)
 CHECK_FUNCTION_EXISTS(explicit_memset HAVE_EXPLICIT_MEMSET)
 CHECK_FUNCTION_EXISTS(fileno HAVE_FILENO)
@@ -98,8 +102,17 @@ IF(ZLIB_VERSION_STRING VERSION_LESS "1.1.2")
   MESSAGE(FATAL_ERROR "-- ZLIB version too old, please install at least v1.1.2")
 ENDIF(ZLIB_VERSION_STRING VERSION_LESS "1.1.2")
 
+FIND_PACKAGE(BZip2)
+IF(BZIP2_FOUND)
+  SET (HAVE_LIBBZ2 1)
+
+  INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
+  SET (OPTIONAL_LIBRARY ${BZIP2_LIBRARY})
+ENDIF(BZIP2_FOUND)
+
 IF(MSVC)
 ADD_DEFINITIONS("-D_CRT_SECURE_NO_WARNINGS")
+ADD_DEFINITIONS("-D_CRT_NONSTDC_NO_DEPRECATE")
 ENDIF(MSVC)
 
 ADD_DEFINITIONS("-DHAVE_CONFIG_H")
@@ -119,6 +132,18 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake-config.h.in
 CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake-zipconf.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/zipconf.h)
 
+# for tests
+
+SET(srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)
+SET(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)
+SET(top_builddir ${CMAKE_BINARY_DIR})
+
+CONFIGURE_FILE(regress/runtest.in ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest @ONLY)
+FILE(COPY ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest
+  DESTINATION ${CMAKE_BINARY_DIR}/regress
+  FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+)
+
 # installation
 
 INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zipconf.h DESTINATION lib/libzip/include)
diff --git a/NEWS.md b/NEWS.md
index 97bf2de..59357be 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,11 +1,20 @@
+1.3.0 [2017-09-02]
+==================
+
+* Support bzip2 compressed zip archives
+* Improve file progress callback code
+* Fix zip_fdopen()
+* CVE-2017-12858: Fix double free().
+* CVE-2017-14107: Improve EOCD64 parsing.
+
 1.2.0 [2017-02-19]
 ==================
 
 * Support for AES encryption (Winzip version), both encryption
-  and decryption.
-* Support legacy zip files with >64k entries.
-* Fix seeking in zip_source_file if start > 0.
-* Add zip_fseek() for seeking in uncompressed data.
+  and decryption
+* Support legacy zip files with >64k entries
+* Fix seeking in zip_source_file if start > 0
+* Add zip_fseek() for seeking in uncompressed data
 * Add zip_ftell() for telling position in uncompressed data.
 * Add zip_register_progress_callback() for UI updates during zip_close()
 
index f38d66c..6b8fd9d 100644 (file)
@@ -1,7 +1,17 @@
 To build libzip from the repository using autotools, you need to
 install autoconf, automake, and libtool; then run
-> autoreconf -fi
+```shell
+autoreconf -fi
+```
 
 Afterwards you can run configure as usual.
 
 Alternatively, use cmake.
+
+```shell
+mkdir build
+cd build
+cmake .. -DBUILD_SHARED_LIBS:BOOL=ON
+```
+
+If you prefer building a static library, leave define `BUILD_SHARED_LIBS` to `OFF`
index e5bb5d8..580b81b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -21,6 +21,10 @@ Additionally, you'll need zlib (at least version 1.1.2). It comes
 with most operating systems nowadays, or you can get it at
 >      http://www.zlib.net/
 
+For supporting bzip2-compressed zip archives, bzip2 from
+>      http://bzip.org/
+needs to be installed.
+
 When using a static Windows library, you need to define `ZIP_STATIC`
 when compiling packages using libzip.
 
@@ -28,7 +32,9 @@ If you make a binary distribution, please include a pointer to the
 distribution site:
 >      http://www.nih.at/libzip/
 
-The latest version can always be found there.
+The latest version can always be found there.  The official mercurial
+repository is at http://hg.nih.at/libzip/ and a read-only git mirror
+exists at https://github.com/nih-at/libzip/
 
 There is a mailing list for developers using libzip.  You can
 subscribe to it by sending a mail with the subject "subscribe
diff --git a/THANKS b/THANKS
index be0cca9..c1a7cec 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -3,6 +3,7 @@ and some other general information gathered from their sources.
 
 Thanks to these people for suggestions, testing, and bug reports:
 
+Agostino Sarubbo
 Alexander Galanin <al@galanin.nnov.ru>
 Alexandr Shadchin <alexandr.shadchin@gmail.com>
 Andrew Brampton <brampton@gmail.com>
@@ -12,6 +13,7 @@ BALATON Zoltan <balaton@eik.bme.hu>
 Benjamin Gilbert <bgilbert@backtick.net>
 Boaz Stolk <bstolk@aweta.nl>
 Bogdan <bogiebog@gmail.com>
+Brian 'geeknik' Carpenter <geeknik@protonmail.ch>
 Chris Nehren <cnehren+libzip@pobox.com>
 Coverity <info@coverity.com>
 Dane Springmeyer <dane.springmeyer@gmail.com>
diff --git a/TODO.md b/TODO.md
index 5cdb79c..2f99c2f 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -8,6 +8,11 @@ zip_set_archive_prefix(struct zip *za, const zip_uint8_t *data, zip_uint64_t len
 const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp);
 ````
 
+# Compression
+
+* Test CMAKE for bzip2
+* add lzma support
+
 # API Issues
 
 * `zip_get_archive_comment` has `int *lenp` argument.  Cleaner would be `zip_uint32_t *`.
@@ -24,13 +29,11 @@ const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp)
   * test cases encryption: no password, default password, file-specific password, 128/192/256, <=20, >20
   * support testing on Linux
   * support testing on macOS
-* xz support
 * consistently use `_zip_crypto_clear()` for passwords
-* implement compression flags for `zip_set_file_compression()`
-* support setting extra fields from zip_source
+* support setting extra fields from `zip_source`
   * introduce layers of extra fields:
     * original
-    * from zip_source
+    * from `zip_source`
     * manually set
   * when querying extra fields, search all of them in reverse order
   * add whiteout (deleted) flag
@@ -42,7 +45,9 @@ const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp)
 * set `O_CLOEXEC` flag after fopen and mkstemp
 * add append-only mode writing file to disk incrementally to keep memory usage low
 * `zip_file_set_mtime()`: support InfoZIP time stamps
-
+* `zipcmp`: support comparing more features:
+  * version needed/made by
+  * general purpose bit flags
 * support streaming output (creating new archive to e.g. stdout)
 * add functions to:
   * read/set ASCII file flag? (more general options?)
@@ -75,6 +80,7 @@ const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp)
 
 # Cleanup
 
+* go over cdir parser and rename various offset/size variables to make it clearer
 * use bool
 * use `ZIP_SOURCE_SUPPORTS_{READABLE,SEEKABLE,WRITABLE}`
 * use `zip_source_seek_compute_offset()`
@@ -91,6 +97,8 @@ const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp)
 
 # Test Case Issues
 
+* add test cases for lots of files (including too many)
+* add test cases for holes (between files, between files and cdir, between cdir and eocd, + zip64 where appropriate)
 * unchange on added file
 * test seek in `zip_source_crc()`
 * test cases for `set_extra*`, `delete_extra*`, `*extra_field*`
index 2260362..0d1839c 100644 (file)
@@ -5,6 +5,7 @@
 #endif
 /* BEGIN DEFINES */
 #cmakedefine HAVE___PROGNAME
+#cmakedefine HAVE__CHMOD
 #cmakedefine HAVE__CLOSE
 #cmakedefine HAVE__DUP
 #cmakedefine HAVE__FDOPEN
 #cmakedefine HAVE__STRICMP
 #cmakedefine HAVE__STRTOI64
 #cmakedefine HAVE__STRTOUI64
+#cmakedefine HAVE__UMASK
+#cmakedefine HAVE__UNLINK
 #cmakedefine HAVE_FILENO
 #cmakedefine HAVE_FSEEKO
 #cmakedefine HAVE_FTELLO
 #cmakedefine HAVE_GETPROGNAME
+#cmakedefine HAVE_LIBBZ2
 #cmakedefine HAVE_OPEN
 #cmakedefine HAVE_MKSTEMP
 #cmakedefine HAVE_SETMODE
index 6acd1e3..169d0f9 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ([2.60])
-AC_INIT([libzip],[1.2.0],[libzip@nih.at])
+AC_INIT([libzip],[1.3.0],[libzip@nih.at])
 AC_CONFIG_SRCDIR([lib/zip_add.c])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
@@ -49,11 +49,40 @@ then
     AC_MSG_ERROR([ZLIB version too old, please install at least v1.1.2])
 fi
 
+AC_ARG_WITH(bzip2,
+    [  --with-bzip2=PREFIX  specify prefix for bzip2 library],,
+    with_bzip2=yes)
+
+if test "$with_bzip2" != "yes"
+then
+    if test -f "$with_bzip2"/bzlib.h
+    then
+       # PREFIX is to uninstalled version in distribution directory
+       CFLAGS="$CFLAGS -I$with_bzip2"
+       LDFLAGS="$LDFLAGS -L$with_bzip2"
+    else if test -f "$with_bzip2"/include/bzlib.h
+    then
+       # PREFIX is installation prefix
+       CFLAGS="$CFLAGS -I$with_bzip2/include"
+       LDFLAGS="$LDFLAGS -L$with_bzip2/lib"
+    fi
+    fi
+fi
+if test "$with_bzip2" != "no"
+then
+    AC_CHECK_LIB(bz2, main)
+fi
+
 AC_EXEEXT
 
 LT_INIT
 
-AC_CHECK_FUNCS([_close _dup _fdopen _fileno _open _setmode _snprintf _strdup _stricmp _strtoi64 _strtoui64 explicit_bzero explicit_memset fileno fseeko ftello getopt getprogname open setmode snprintf strcasecmp strdup stricmp strtoll strtoull])
+if test "$enable_shared" = "yes"
+then
+    AC_DEFINE([HAVE_SHARED], [1], [Define when building shared libraries])
+fi
+
+AC_CHECK_FUNCS([_chmod _close _dup _fdopen _fileno _open _setmode _snprintf _strdup _stricmp _strtoi64 _strtoui64 _umask _unlink explicit_bzero explicit_memset fileno fseeko ftello getopt getprogname open setmode snprintf strcasecmp strdup stricmp strtoll strtoull])
 AC_CHECK_FUNCS([mkstemp], [], [AC_LIBOBJ(mkstemp)])
 
 dnl assume dlsym in libc, but check in libdl
index 1596f30..8bf304b 100644 (file)
@@ -57,6 +57,8 @@ SET(LIBZIP_SOURCES
   zip_add.c
   zip_add_dir.c
   zip_add_entry.c
+  zip_algorithm_bzip2.c
+  zip_algorithm_deflate.c
   zip_buffer.c
   zip_close.c
   zip_delete.c
@@ -95,9 +97,9 @@ SET(LIBZIP_SOURCES
   zip_fopen_index_encrypted.c
   zip_fread.c
   zip_fseek.c
+  zip_ftell.c
   zip_get_archive_comment.c
   zip_get_archive_flag.c
-  zip_get_compression_implementation.c
   zip_get_encryption_implementation.c
   zip_get_file_comment.c
   zip_get_name.c
@@ -109,6 +111,7 @@ SET(LIBZIP_SOURCES
   zip_name_locate.c
   zip_new.c
   zip_open.c
+  zip_progress.c
   zip_rename.c
   zip_replace.c
   zip_set_archive_comment.c
@@ -122,12 +125,13 @@ SET(LIBZIP_SOURCES
   zip_source_call.c
   zip_source_close.c
   zip_source_commit_write.c
+  zip_source_compress.c
   zip_source_crc.c
-  zip_source_deflate.c
   zip_source_error.c
   zip_source_filep.c
   zip_source_free.c
   zip_source_function.c
+  zip_source_get_compression_flags.c
   zip_source_is_deleted.c
   zip_source_layered.c
   zip_source_open.c
@@ -191,19 +195,11 @@ IF(NOT HAVE_MKSTEMP)
   SET(LIBZIP_EXTRA_FILES mkstemp.c)
 ENDIF(NOT HAVE_MKSTEMP)
 
-ADD_LIBRARY(zip SHARED ${LIBZIP_SOURCES} ${LIBZIP_EXTRA_FILES} ${LIBZIP_OPSYS_FILES})
+ADD_LIBRARY(zip ${LIBZIP_SOURCES} ${LIBZIP_EXTRA_FILES} ${LIBZIP_OPSYS_FILES})
 SET_TARGET_PROPERTIES(zip PROPERTIES VERSION 3.0 SOVERSION 3 )
-TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARY})
+TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARY} ${OPTIONAL_LIBRARY})
 INSTALL(TARGETS zip
   RUNTIME DESTINATION bin
   ARCHIVE DESTINATION lib
   LIBRARY DESTINATION lib)
 #CREATE_LIBTOOL_FILE(zip lib)
-
-#ADD_LIBRARY(zipstatic STATIC ${LIBZIP_SOURCES} ${LIBZIP_EXTRA_FILES} ${LIBZIP_OPSYS_FILES})
-#SET_TARGET_PROPERTIES(zipstatic PROPERTIES VERSION 3.0 SOVERSION 3 )
-#TARGET_LINK_LIBRARIES(zipstatic ${ZLIB_LIBRARY})
-#INSTALL(TARGETS zipstatic
-#  RUNTIME DESTINATION bin
-#  ARCHIVE DESTINATION lib
-#  LIBRARY DESTINATION lib)
index 42ecccd..e631db1 100644 (file)
@@ -33,6 +33,8 @@ libzip_la_SOURCES=\
        zip_add.c \
        zip_add_dir.c \
        zip_add_entry.c \
+       zip_algorithm_bzip2.c \
+       zip_algorithm_deflate.c \
        zip_buffer.c \
        zip_close.c \
        zip_delete.c \
@@ -74,7 +76,6 @@ libzip_la_SOURCES=\
        zip_ftell.c \
        zip_get_archive_comment.c \
        zip_get_archive_flag.c \
-       zip_get_compression_implementation.c \
        zip_get_encryption_implementation.c \
        zip_get_file_comment.c \
        zip_get_num_entries.c \
@@ -86,6 +87,7 @@ libzip_la_SOURCES=\
        zip_name_locate.c \
        zip_new.c \
        zip_open.c \
+       zip_progress.c \
        zip_rename.c \
        zip_replace.c \
        zip_set_archive_comment.c \
@@ -99,12 +101,13 @@ libzip_la_SOURCES=\
        zip_source_call.c \
        zip_source_close.c \
        zip_source_commit_write.c \
+       zip_source_compress.c \
        zip_source_crc.c \
-       zip_source_deflate.c \
        zip_source_error.c \
        zip_source_filep.c \
        zip_source_free.c \
        zip_source_function.c \
+       zip_source_get_compression_flags.c \
        zip_source_is_deleted.c \
        zip_source_layered.c \
        zip_source_open.c \
index 4c9e3a0..625c84e 100644 (file)
@@ -72,6 +72,9 @@ typedef char bool;
 #endif
 
 #ifdef _WIN32
+#if defined(HAVE__CHMOD)
+#define chmod          _chmod
+#endif
 #if defined(HAVE__CLOSE)
 #define close          _close
 #endif
@@ -107,6 +110,12 @@ typedef char bool;
 #if !defined(HAVE_STRTOULL) && defined(HAVE__STRTOUI64)
 #define strtoull       _strtoui64
 #endif
+#if defined(HAVE__UMASK)
+#define umask  _umask
+#endif
+#if defined(HAVE__UNLINK)
+#define unlink _unlink
+#endif
 #endif
 
 #ifndef HAVE_FSEEKO
index 2ccd3a4..cdfc0e2 100644 (file)
 #include <errno.h>
 #include <fcntl.h>
 #ifdef _WIN32
+#include <process.h>
 #include <io.h>
+#else
+#include <unistd.h>
 #endif
 #include <stdio.h>
 #include <stdlib.h>
index abdaf07..d6053aa 100644 (file)
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -102,37 +102,38 @@ extern "C" {
 
 /* libzip error codes */
 
-#define ZIP_ER_OK             0  /* N No error */
-#define ZIP_ER_MULTIDISK      1  /* N Multi-disk zip archives not supported */
-#define ZIP_ER_RENAME         2  /* S Renaming temporary file failed */
-#define ZIP_ER_CLOSE          3  /* S Closing zip archive failed */
-#define ZIP_ER_SEEK           4  /* S Seek error */
-#define ZIP_ER_READ           5  /* S Read error */
-#define ZIP_ER_WRITE          6  /* S Write error */
-#define ZIP_ER_CRC            7  /* N CRC error */
-#define ZIP_ER_ZIPCLOSED      8  /* N Containing zip archive was closed */
-#define ZIP_ER_NOENT          9  /* N No such file */
-#define ZIP_ER_EXISTS        10  /* N File already exists */
-#define ZIP_ER_OPEN          11  /* S Can't open file */
-#define ZIP_ER_TMPOPEN       12  /* S Failure to create temporary file */
-#define ZIP_ER_ZLIB          13  /* Z Zlib error */
-#define ZIP_ER_MEMORY        14  /* N Malloc failure */
-#define ZIP_ER_CHANGED       15  /* N Entry has been changed */
-#define ZIP_ER_COMPNOTSUPP   16  /* N Compression method not supported */
-#define ZIP_ER_EOF           17  /* N Premature end of file */
-#define ZIP_ER_INVAL         18  /* N Invalid argument */
-#define ZIP_ER_NOZIP         19  /* N Not a zip archive */
-#define ZIP_ER_INTERNAL      20  /* N Internal error */
-#define ZIP_ER_INCONS        21  /* N Zip archive inconsistent */
-#define ZIP_ER_REMOVE        22  /* S Can't remove file */
-#define ZIP_ER_DELETED       23  /* N Entry has been deleted */
-#define ZIP_ER_ENCRNOTSUPP   24  /* N Encryption method not supported */
-#define ZIP_ER_RDONLY        25  /* N Read-only archive */
-#define ZIP_ER_NOPASSWD      26  /* N No password provided */
-#define ZIP_ER_WRONGPASSWD   27  /* N Wrong password provided */
-#define ZIP_ER_OPNOTSUPP     28  /* N Operation not supported */
-#define ZIP_ER_INUSE         29  /* N Resource still in use */
-#define ZIP_ER_TELL          30  /* S Tell error */
+#define ZIP_ER_OK                0  /* N No error */
+#define ZIP_ER_MULTIDISK         1  /* N Multi-disk zip archives not supported */
+#define ZIP_ER_RENAME            2  /* S Renaming temporary file failed */
+#define ZIP_ER_CLOSE             3  /* S Closing zip archive failed */
+#define ZIP_ER_SEEK              4  /* S Seek error */
+#define ZIP_ER_READ              5  /* S Read error */
+#define ZIP_ER_WRITE             6  /* S Write error */
+#define ZIP_ER_CRC               7  /* N CRC error */
+#define ZIP_ER_ZIPCLOSED         8  /* N Containing zip archive was closed */
+#define ZIP_ER_NOENT             9  /* N No such file */
+#define ZIP_ER_EXISTS           10  /* N File already exists */
+#define ZIP_ER_OPEN             11  /* S Can't open file */
+#define ZIP_ER_TMPOPEN          12  /* S Failure to create temporary file */
+#define ZIP_ER_ZLIB             13  /* Z Zlib error */
+#define ZIP_ER_MEMORY           14  /* N Malloc failure */
+#define ZIP_ER_CHANGED          15  /* N Entry has been changed */
+#define ZIP_ER_COMPNOTSUPP      16  /* N Compression method not supported */
+#define ZIP_ER_EOF              17  /* N Premature end of file */
+#define ZIP_ER_INVAL            18  /* N Invalid argument */
+#define ZIP_ER_NOZIP            19  /* N Not a zip archive */
+#define ZIP_ER_INTERNAL         20  /* N Internal error */
+#define ZIP_ER_INCONS           21  /* N Zip archive inconsistent */
+#define ZIP_ER_REMOVE           22  /* S Can't remove file */
+#define ZIP_ER_DELETED          23  /* N Entry has been deleted */
+#define ZIP_ER_ENCRNOTSUPP      24  /* N Encryption method not supported */
+#define ZIP_ER_RDONLY           25  /* N Read-only archive */
+#define ZIP_ER_NOPASSWD         26  /* N No password provided */
+#define ZIP_ER_WRONGPASSWD      27  /* N Wrong password provided */
+#define ZIP_ER_OPNOTSUPP        28  /* N Operation not supported */
+#define ZIP_ER_INUSE            29  /* N Resource still in use */
+#define ZIP_ER_TELL             30  /* S Tell error */
+#define ZIP_ER_COMPRESSED_DATA 31  /* N Compressed data invalid */    
 
 /* type of system error value */
 
@@ -226,11 +227,12 @@ enum zip_source_cmd {
     ZIP_SOURCE_SEEK_WRITE,      /* set position for writing */
     ZIP_SOURCE_TELL_WRITE,      /* get write position */
     ZIP_SOURCE_SUPPORTS,        /* check whether source supports command */
-    ZIP_SOURCE_REMOVE           /* remove file */
+    ZIP_SOURCE_REMOVE,          /* remove file */
+    ZIP_SOURCE_GET_COMPRESSION_FLAGS   /* get compression flags, internal only */
 };
 typedef enum zip_source_cmd zip_source_cmd_t;
 
-#define ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd)    (1<<(cmd))
+#define ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd)    (((zip_uint64_t)1)<<(cmd))
 
 #define ZIP_SOURCE_SUPPORTS_READABLE   (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_OPEN) \
                                          | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_READ) \
@@ -307,10 +309,12 @@ typedef struct zip_stat zip_stat_t;
 typedef zip_uint32_t zip_flags_t;
 
 typedef zip_int64_t (*zip_source_callback)(void *, void *, zip_uint64_t, zip_source_cmd_t);
-typedef void (*zip_progress_callback_t)(double);
-
+typedef void (*zip_progress_callback)(zip_t *, double, void *);
 
 #ifndef ZIP_DISABLE_DEPRECATED
+typedef void (*zip_progress_callback_t)(double);
+ZIP_EXTERN void zip_register_progress_callback(zip_t *, zip_progress_callback_t);
+
 ZIP_EXTERN zip_int64_t zip_add(zip_t *, const char *, zip_source_t *); /* use zip_file_add */
 ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *, const char *); /* use zip_dir_add */
 ZIP_EXTERN const char *zip_get_file_comment(zip_t *, zip_uint64_t, int *, int); /* use zip_file_get_comment */
@@ -376,7 +380,7 @@ ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *, zip_flags_t);
 ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *, const char *, zip_flags_t);
 ZIP_EXTERN zip_t *zip_open(const char *, int, int *);
 ZIP_EXTERN zip_t *zip_open_from_source(zip_source_t *, int, zip_error_t *);
-ZIP_EXTERN void zip_register_progress_callback(zip_t *, zip_progress_callback_t);
+ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *, double, zip_progress_callback, void (*)(void *), void *);
 ZIP_EXTERN int zip_set_archive_comment(zip_t *, const char *, zip_uint16_t);
 ZIP_EXTERN int zip_set_archive_flag(zip_t *, zip_flags_t, int);
 ZIP_EXTERN int zip_set_default_password(zip_t *, const char *);
diff --git a/lib/zip_algorithm_bzip2.c b/lib/zip_algorithm_bzip2.c
new file mode 100644 (file)
index 0000000..fd74503
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+  zip_algorithm_bzip2.c -- bzip2 (de)compression routines
+  Copyright (C) 2017 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+#if defined(HAVE_LIBBZ2)
+
+#include <bzlib.h>
+#include <limits.h>
+#include <stdlib.h>
+
+struct ctx {
+    zip_error_t *error;
+    bool compress;
+    int compression_flags;
+    bool end_of_input;
+    bz_stream zstr;
+};
+
+
+static void *
+allocate(bool compress, int compression_flags, zip_error_t *error) {
+    struct ctx *ctx;
+
+    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
+       return NULL;
+    }
+
+    ctx->error = error;
+    ctx->compress = compress;
+    ctx->compression_flags = compression_flags;
+    if (ctx->compression_flags < 1 || ctx->compression_flags > 9) {
+       ctx->compression_flags = 9;
+    }
+    ctx->end_of_input = false;
+
+    ctx->zstr.bzalloc = NULL;
+    ctx->zstr.bzfree = NULL;
+    ctx->zstr.opaque = NULL;
+
+    return ctx;
+}
+
+
+static void *
+compress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
+    return allocate(true, compression_flags, error);
+}
+
+
+static void *
+decompress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
+    return allocate(false, compression_flags, error);
+}
+
+
+static void
+deallocate(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    free(ctx);
+}
+
+
+static int
+compression_flags(void *ud) {
+    return 0;
+}
+
+
+static int
+map_error(int ret) {
+    switch (ret) {
+    case BZ_FINISH_OK:
+    case BZ_FLUSH_OK:
+    case BZ_OK:
+    case BZ_RUN_OK:
+    case BZ_STREAM_END:
+       return ZIP_ER_OK;
+
+    case BZ_DATA_ERROR:
+    case BZ_DATA_ERROR_MAGIC:
+    case BZ_UNEXPECTED_EOF:
+       return ZIP_ER_COMPRESSED_DATA;
+
+    case BZ_MEM_ERROR:
+       return ZIP_ER_MEMORY;
+
+    case BZ_PARAM_ERROR:
+       return ZIP_ER_INVAL;
+
+    case BZ_CONFIG_ERROR: /* actually, bzip2 miscompiled */
+    case BZ_IO_ERROR:
+    case BZ_OUTBUFF_FULL:
+    case BZ_SEQUENCE_ERROR:
+       return ZIP_ER_INTERNAL;
+
+    default:
+       return ZIP_ER_INTERNAL;
+    }
+
+}
+
+static bool
+start(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+    int ret;
+
+    ctx->zstr.avail_in = 0;
+    ctx->zstr.next_in = NULL;
+    ctx->zstr.avail_out = 0;
+    ctx->zstr.next_out = NULL;
+
+    if (ctx->compress) {
+       ret = BZ2_bzCompressInit(&ctx->zstr, ctx->compression_flags, 0, 30);
+
+    }
+    else {
+       ret = BZ2_bzDecompressInit(&ctx->zstr, 0, 0);
+    }
+
+    if (ret != BZ_OK) {
+       zip_error_set(ctx->error, map_error(ret), 0);
+       return false;
+    }
+
+    return true;
+}
+
+
+static bool
+end(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+    int err;
+
+    if (ctx->compress) {
+       err = BZ2_bzCompressEnd(&ctx->zstr);
+    }
+    else {
+       err = BZ2_bzDecompressEnd(&ctx->zstr);
+    }
+
+    if (err != BZ_OK) {
+       zip_error_set(ctx->error, map_error(err), 0);
+       return false;
+    }
+
+    return true;
+}
+
+
+static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
+       zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
+       return false;
+    }
+
+    ctx->zstr.avail_in = (unsigned int)length;
+    ctx->zstr.next_in = (char *)data;
+
+    return true;
+}
+
+
+static void end_of_input(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    ctx->end_of_input = true;
+}
+
+
+static zip_compression_status_t
+process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    int ret;
+
+    if (ctx->zstr.avail_in == 0 && !ctx->end_of_input) {
+       *length = 0;
+       return ZIP_COMPRESSION_NEED_DATA;
+    }
+
+    ctx->zstr.avail_out = (unsigned int)ZIP_MIN(UINT_MAX, *length);
+    ctx->zstr.next_out = (char *)data;
+
+    if (ctx->compress) {
+       ret = BZ2_bzCompress(&ctx->zstr, ctx->end_of_input ? BZ_FINISH : BZ_RUN);
+    }
+    else {
+       ret = BZ2_bzDecompress(&ctx->zstr);
+    }
+
+    *length = *length - ctx->zstr.avail_out;
+
+    switch (ret) {
+    case BZ_FINISH_OK: /* compression */
+       return ZIP_COMPRESSION_OK;
+
+    case BZ_OK:        /* decompression */
+    case BZ_RUN_OK: /* compression */
+       if (ctx->zstr.avail_in == 0) {
+           return ZIP_COMPRESSION_NEED_DATA;
+       }
+       return ZIP_COMPRESSION_OK;
+
+    case BZ_STREAM_END:
+       return ZIP_COMPRESSION_END;
+
+    default:
+       zip_error_set(ctx->error, map_error(ret), 0);
+       return ZIP_COMPRESSION_ERROR;
+    }
+}
+
+
+zip_compression_algorithm_t zip_algorithm_bzip2_compress = {
+    compress_allocate,
+    deallocate,
+    compression_flags,
+    start,
+    end,
+    input,
+    end_of_input,
+    process
+};
+
+
+zip_compression_algorithm_t zip_algorithm_bzip2_decompress = {
+    decompress_allocate,
+    deallocate,
+    compression_flags,
+    start,
+    end,
+    input,
+    end_of_input,
+    process
+};
+
+#else
+
+static int dummy;
+
+#endif /* HAVE_LIBBZ2 */
diff --git a/lib/zip_algorithm_deflate.c b/lib/zip_algorithm_deflate.c
new file mode 100644 (file)
index 0000000..55cd928
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+  zip_algorithm_deflate.c -- deflate (de)compression routines
+  Copyright (C) 2017 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+struct ctx {
+    zip_error_t *error;
+    bool compress;
+    int compression_flags;
+    bool end_of_input;
+    z_stream zstr;
+};
+
+
+static void *
+allocate(bool compress, int compression_flags, zip_error_t *error) {
+    struct ctx *ctx;
+
+    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
+       return NULL;
+    }
+
+    ctx->error = error;
+    ctx->compress = compress;
+    ctx->compression_flags = compression_flags;
+    if (ctx->compression_flags < 1 || ctx->compression_flags > 9) {
+       ctx->compression_flags = Z_BEST_COMPRESSION;
+    }
+    ctx->end_of_input = false;
+
+    ctx->zstr.zalloc = Z_NULL;
+    ctx->zstr.zfree = Z_NULL;
+    ctx->zstr.opaque = NULL;
+
+    return ctx;
+}
+
+
+static void *
+compress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
+    return allocate(true, compression_flags, error);
+}
+
+
+static void *
+decompress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
+    return allocate(false, compression_flags, error);
+}
+
+
+static void
+deallocate(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    free(ctx);
+}
+
+
+static int
+compression_flags(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    if (!ctx->compress) {
+       return 0;
+    }
+
+    if (ctx->compression_flags < 3) {
+       return 2;
+    }
+    else if (ctx->compression_flags > 7) {
+       return 1;
+    }
+    return 0;
+}
+
+
+static bool
+start(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+    int ret;
+
+    ctx->zstr.avail_in = 0;
+    ctx->zstr.next_in = NULL;
+    ctx->zstr.avail_out = 0;
+    ctx->zstr.next_out = NULL;
+
+    if (ctx->compress) {
+       /* negative value to tell zlib not to write a header */
+       ret = deflateInit2(&ctx->zstr, ctx->compression_flags, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+    }
+    else {
+       ret = inflateInit2(&ctx->zstr, -MAX_WBITS);
+    }
+
+    if (ret != Z_OK) {
+       zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
+       return false;
+    }
+
+
+    return true;
+}
+
+
+static bool
+end(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+    int err;
+
+    if (ctx->compress) {
+       err = deflateEnd(&ctx->zstr);
+    }
+    else {
+       err = inflateEnd(&ctx->zstr);
+    }
+
+    if (err != Z_OK) {
+       zip_error_set(ctx->error, ZIP_ER_ZLIB, err);
+       return false;
+    }
+
+    return true;
+}
+
+
+static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
+       zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
+       return false;
+    }
+
+    ctx->zstr.avail_in = (uInt)length;
+    ctx->zstr.next_in = (Bytef *)data;
+
+    return true;
+}
+
+
+static void end_of_input(void *ud) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    ctx->end_of_input = true;
+}
+
+
+static zip_compression_status_t
+process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
+    struct ctx *ctx = (struct ctx *)ud;
+
+    int ret;
+
+    ctx->zstr.avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);
+    ctx->zstr.next_out = (Bytef *)data;
+
+    if (ctx->compress) {
+       ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0);
+    }
+    else {
+       ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);
+    }
+
+    *length = *length - ctx->zstr.avail_out;
+
+    switch (ret) {
+    case Z_OK:
+       return ZIP_COMPRESSION_OK;
+
+    case Z_STREAM_END:
+       return ZIP_COMPRESSION_END;
+
+    case Z_BUF_ERROR:
+       if (ctx->zstr.avail_in == 0) {
+           return ZIP_COMPRESSION_NEED_DATA;
+       }
+
+       /* fallthrough */
+
+    default:
+       zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
+       return ZIP_COMPRESSION_ERROR;
+    }
+}
+
+
+zip_compression_algorithm_t zip_algorithm_deflate_compress = {
+    compress_allocate,
+    deallocate,
+    compression_flags,
+    start,
+    end,
+    input,
+    end_of_input,
+    process
+};
+
+
+zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
+    decompress_allocate,
+    deallocate,
+    compression_flags,
+    start,
+    end,
+    input,
+    end_of_input,
+    process
+};
index 88fa444..3a2ff0a 100644 (file)
 #endif
 
 
-/* max deflate size increase: size + ceil(size/16k)*5+6 */
-#define MAX_DEFLATE_SIZE_32    4293656963u
-
 static int add_data(zip_t *, zip_source_t *, zip_dirent_t *);
 static int copy_data(zip_t *, zip_uint64_t);
-static int copy_source(zip_t *, zip_source_t *);
+static int copy_source(zip_t *, zip_source_t *, zip_int64_t);
 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
 
-
 ZIP_EXTERN int
 zip_close(zip_t *za)
 {
@@ -124,16 +120,15 @@ zip_close(zip_t *za)
        free(filelist);
        return -1;
     }
-    
+
+    _zip_progress_start(za->progress);
     error = 0;
     for (j=0; j<survivors; j++) {
        int new_data;
        zip_entry_t *entry;
        zip_dirent_t *de;
 
-       if (za->progress_callback) {
-           za->progress_callback((double)j/survivors);
-       }
+        _zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j+1) / (double)survivors);
 
        i = filelist[j].idx;
        entry = za->entry+i;
@@ -226,9 +221,7 @@ zip_close(zip_t *za)
        return -1;
     }
 
-    if (za->progress_callback) {
-       za->progress_callback(1);
-    }
+    _zip_progress_end(za->progress);
 
     zip_discard(za);
     
@@ -239,14 +232,15 @@ zip_close(zip_t *za)
 static int
 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
 {
-    zip_int64_t offstart, offdata, offend;
+    zip_int64_t offstart, offdata, offend, data_length;
     struct zip_stat st;
     zip_source_t *src_final, *src_tmp;
     int ret;
     int is_zip64;
     zip_flags_t flags;
+    zip_int8_t compression_flags;
     bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
-    
+
     if (zip_source_stat(src, &st) < 0) {
        _zip_error_set_from_source(&za->error, src);
        return -1;
@@ -275,30 +269,58 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
 
     flags = ZIP_EF_LOCAL;
 
-    if ((st.valid & ZIP_STAT_SIZE) == 0)
+    if ((st.valid & ZIP_STAT_SIZE) == 0) {
        flags |= ZIP_FL_FORCE_ZIP64;
+       data_length = -1;
+    }
     else {
        de->uncomp_size = st.size;
+       /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */
+       data_length = (zip_int64_t)st.size;
        
        if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
-           if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32)
-                 || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method))))
+           zip_uint64_t max_size;
+
+           switch (ZIP_CM_ACTUAL(de->comp_method)) {
+           case ZIP_CM_BZIP2:
+               /* computed by looking at increase of 10 random files of size 1MB when
+                * compressed with bzip2, rounded up: 1.006 */
+               max_size = 4269351188u;
+               break;
+
+           case ZIP_CM_DEFLATE:
+               /* max deflate size increase: size + ceil(size/16k)*5+6 */
+               max_size = 4293656963u;
+               break;
+
+           case ZIP_CM_STORE:
+               max_size = 0xffffffffu;
+               break;
+
+           default:
+               max_size = 0;
+           }
+
+           if (st.size > max_size) {
                flags |= ZIP_FL_FORCE_ZIP64;
+           }
        }
        else
            de->comp_size = st.comp_size;
     }
 
     if ((offstart = zip_source_tell_write(za->src)) < 0) {
+       _zip_error_set_from_source(&za->error, za->src);
         return -1;
     }
 
     /* as long as we don't support non-seekable output, clear data descriptor bit */
     de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
-    if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0)
+    if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) {
        return -1;
+    }
 
-    needs_recompress = !((st.comp_method == de->comp_method) || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method == ZIP_CM_DEFLATE));
+    needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
     needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
     needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
     needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
@@ -329,15 +351,7 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
     }
     
     if (needs_decompress) {
-       zip_compression_implementation comp_impl;
-       
-       if ((comp_impl = _zip_get_compression_implementation(st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
-           zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
-           zip_source_free(src_final);
-           return -1;
-       }
-       if ((src_tmp = comp_impl(za, src_final, st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
-           /* error set by comp_impl */
+       if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {
            zip_source_free(src_final);
            return -1;
        }
@@ -357,14 +371,7 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
     }
 
     if (needs_compress) {
-       zip_compression_implementation comp_impl;
-
-       if ((comp_impl = _zip_get_compression_implementation(de->comp_method, ZIP_CODEC_ENCODE)) == NULL) {
-           zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
-           zip_source_free(src_final);
-           return -1;
-       }
-       if ((src_tmp = comp_impl(za, src_final, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) {
+       if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {
            zip_source_free(src_final);
            return -1;
        }
@@ -401,12 +408,19 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
 
 
     if ((offdata = zip_source_tell_write(za->src)) < 0) {
+       _zip_error_set_from_source(&za->error, za->src);
         return -1;
     }
 
-    ret = copy_source(za, src_final);
+    ret = copy_source(za, src_final, data_length);
        
     if (zip_source_stat(src_final, &st) < 0) {
+       _zip_error_set_from_source(&za->error, src_final);
+       ret = -1;
+    }
+
+    if ((compression_flags = zip_source_get_compression_flags(src_final)) < 0) {
+       _zip_error_set_from_source(&za->error, src_final);
        ret = -1;
     }
 
@@ -417,6 +431,7 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
     }
 
     if ((offend = zip_source_tell_write(za->src)) < 0) {
+       _zip_error_set_from_source(&za->error, za->src);
         return -1;
     }
 
@@ -440,7 +455,9 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
     de->crc = st.crc;
     de->uncomp_size = st.size;
     de->comp_size = (zip_uint64_t)(offend - offdata);
-
+    de->bitflags = (zip_uint16_t)((de->bitflags & (zip_uint16_t)~6) | ((zip_uint8_t)compression_flags << 1));
+    _zip_dirent_set_version_needed(de, (flags & ZIP_FL_FORCE_ZIP64) != 0);
+    
     if ((ret=_zip_dirent_write(za, de, flags)) < 0)
        return -1;
  
@@ -449,7 +466,6 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
        return -1;
     }
-
    
     if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {
        _zip_error_set_from_source(&za->error, za->src);
@@ -465,6 +481,7 @@ copy_data(zip_t *za, zip_uint64_t len)
 {
     zip_uint8_t buf[BUFSIZE];
     size_t n;
+    double total = (double)len;
 
     while (len > 0) {
        n = len > sizeof(buf) ? sizeof(buf) : len;
@@ -477,6 +494,8 @@ copy_data(zip_t *za, zip_uint64_t len)
        }
        
        len -= n;
+
+        _zip_progress_update(za->progress, (total - (double)len) / total);
     }
 
     return 0;
@@ -484,10 +503,10 @@ copy_data(zip_t *za, zip_uint64_t len)
 
 
 static int
-copy_source(zip_t *za, zip_source_t *src)
+copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length)
 {
     zip_uint8_t buf[BUFSIZE];
-    zip_int64_t n;
+    zip_int64_t n, current;
     int ret;
 
     if (zip_source_open(src) < 0) {
@@ -496,11 +515,16 @@ copy_source(zip_t *za, zip_source_t *src)
     }
 
     ret = 0;
+    current = 0;
     while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
        if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
            ret = -1;
            break;
        }
+       if (n == sizeof(buf) && za->progress && data_length > 0) {
+           current += n;
+           _zip_progress_update(za->progress, (double)current/(double)data_length);
+       }
     }
     
     if (n < 0) {
@@ -513,7 +537,6 @@ copy_source(zip_t *za, zip_source_t *src)
     return ret;
 }
 
-
 static int
 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors)
 {
index df38afd..e5a7cc9 100644 (file)
@@ -281,8 +281,8 @@ _zip_dirent_init(zip_dirent_t *de)
     de->cloned = 0;
 
     de->crc_valid = true;
-    de->version_madeby = 20 | (ZIP_OPSYS_DEFAULT << 8);
-    de->version_needed = 20; /* 2.0 */
+    de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8);
+    de->version_needed = 10; /* 1.0 */
     de->bitflags = 0;
     de->comp_method = ZIP_CM_DEFAULT;
     de->last_mod = 0;
@@ -296,6 +296,7 @@ _zip_dirent_init(zip_dirent_t *de)
     de->int_attrib = 0;
     de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;
     de->offset = 0;
+    de->compression_level = 0;
     de->encryption_method = ZIP_EM_NONE;
     de->password = NULL;
 }
@@ -578,9 +579,6 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo
     }
 
     if (!_zip_dirent_process_winzip_aes(zde, error)) {
-       if (!from_buffer) {
-           _zip_buffer_free(buffer);
-       }
        return -1;
     }
 
@@ -797,10 +795,10 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags)
     }
 
     if (de->encryption_method == ZIP_EM_NONE) {
-       de->bitflags &= ~ZIP_GPBF_ENCRYPTED;
+       de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED;
     }
     else {
-       de->bitflags |= ZIP_GPBF_ENCRYPTED;
+       de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED;
     }
 
     is_really_zip64 = _zip_dirent_needs_zip64(de, flags);
@@ -862,7 +860,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags)
 
        _zip_buffer_put_16(ef_buffer, 2);
        _zip_buffer_put(ef_buffer, "AE", 2);
-       _zip_buffer_put_8(ef_buffer, (de->encryption_method & 0xff));
+       _zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff));
        _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method);
 
         if (!_zip_buffer_ok(ef_buffer)) {
@@ -890,7 +888,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags)
         _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby));
     }
     _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed));
-    _zip_buffer_put_16(buffer, de->bitflags&0xfff9); /* clear compression method specific flags */
+    _zip_buffer_put_16(buffer, de->bitflags);
     if (is_winzip_aes) {
        _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);
     }
@@ -1103,3 +1101,39 @@ _zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate)
 
     return;
 }
+
+
+void
+_zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64) {
+    zip_uint16_t length;
+
+    if (de->comp_method == ZIP_CM_LZMA) {
+       de->version_needed = 63;
+       return;
+    }
+
+    if (de->comp_method == ZIP_CM_BZIP2) {
+       de->version_needed = 46;
+       return;
+    }
+
+    if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {
+       de->version_needed = 45;
+       return;
+    }
+    
+    if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {
+       de->version_needed = 20;
+       return;
+    }
+
+    /* directory */
+    if ((length = _zip_string_length(de->filename)) > 0) {
+       if (de->filename->raw[length-1] == '/') {
+           de->version_needed = 20;
+           return;
+       }
+    }
+    
+    de->version_needed = 10;
+}
index ef891e3..93bdf3a 100644 (file)
@@ -71,6 +71,8 @@ zip_discard(zip_t *za)
     }
     free(za->open_source);
 
+    _zip_progress_free(za->progress);
+
     zip_error_fini(&za->error);
     
     free(za);
index 9c9adb5..6560bba 100644 (file)
@@ -37,6 +37,7 @@ const char * const _zip_err_str[] = {
     "Operation not supported",
     "Resource still in use",
     "Tell error",
+    "Compressed data invalid",    
 };
 
 const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
@@ -77,4 +78,5 @@ const int _zip_err_type[] = {
     N,
     N,
     S,
+    N,    
 };
index a058f81..8b0a66d 100644 (file)
@@ -47,7 +47,7 @@ zip_fdopen(int fd_orig, int _flags, int *zep)
     zip_source_t *src;
     struct zip_error error;
 
-    if (_flags < 0 || (_flags & ZIP_TRUNCATE)) {
+    if (_flags < 0 || (_flags & ~(ZIP_CHECKCONS|ZIP_RDONLY))) {
        _zip_set_open_error(zep, NULL, ZIP_ER_INVAL);
         return  NULL;
     }
index 23f9708..fc854a8 100644 (file)
 #include <string.h>
 #include "zipint.h"
 
+/* parameter for the string hash function */
+#define HASH_MULTIPLIER 33
+#define HASH_START 5381
+
+/* hash table's fill ratio is kept between these by doubling/halfing its size as necessary */
+#define HASH_MAX_FILL .75
+#define HASH_MIN_FILL .01
+
+/* but hash table size is kept between these */
+#define HASH_MIN_SIZE 256
+#define HASH_MAX_SIZE 0x80000000ul
+
 struct zip_hash_entry {
     const zip_uint8_t *name;
     zip_int64_t orig_index;
     zip_int64_t current_index;
     struct zip_hash_entry *next;
+    zip_uint32_t hash_value;
 };
 typedef struct zip_hash_entry zip_hash_entry_t;
 
 struct zip_hash {
-    zip_uint16_t table_size;
+    zip_uint32_t table_size;
+    zip_uint64_t nentries;
     zip_hash_entry_t **table;
 };
 
-zip_hash_t *
-_zip_hash_new(zip_uint16_t table_size, zip_error_t *error)
+
+/* free list of entries */
+static void
+free_list(zip_hash_entry_t *entry)
 {
-    zip_hash_t *hash;
+    while (entry != NULL) {
+       zip_hash_entry_t *next = entry->next;
+       free(entry);
+       entry = next;
+    }
+}
+
+
+/* compute hash of string, full 32 bit value */
+static zip_uint32_t
+hash_string(const zip_uint8_t *name)
+{
+    zip_uint64_t value = HASH_START;
+
+    if (name == NULL) {
+       return 0;
+    }
 
-    if (table_size == 0) {
-       zip_error_set(error, ZIP_ER_INTERNAL, 0);
-       return NULL;
+    while (*name != 0) {
+       value = (zip_uint64_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % 0x100000000ul);
+       name++;
     }
 
-    if ((hash=(zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) {
-       zip_error_set(error, ZIP_ER_MEMORY, 0);
-       return NULL;
+    return (zip_uint32_t)value;
+}
+
+
+/* resize hash table; new_size must be a power of 2, can be larger or smaller than current size */
+static bool
+hash_resize(zip_hash_t *hash, zip_uint32_t new_size, zip_error_t *error)
+{
+    zip_hash_entry_t **new_table;
+
+    if (new_size == hash->table_size) {
+       return true;
     }
-    hash->table_size = table_size;
-    if ((hash->table=(zip_hash_entry_t**)calloc(table_size, sizeof(zip_hash_entry_t *))) == NULL) {
-       free(hash);
+
+    if ((new_table = (zip_hash_entry_t**)calloc(new_size, sizeof(zip_hash_entry_t *))) == NULL) {
        zip_error_set(error, ZIP_ER_MEMORY, 0);
-       return NULL;
+       return false;
     }
 
-    return hash;
+    if (hash->nentries > 0) {
+       zip_uint32_t i;
+
+       for (i = 0; i < hash->table_size; i++) {
+           zip_hash_entry_t *entry = hash->table[i];
+           while (entry) {
+               zip_hash_entry_t *next = entry->next;
+
+               zip_uint32_t new_index = entry->hash_value % new_size;
+
+               entry->next = new_table[new_index];
+               new_table[new_index] = entry;
+
+               entry = next;
+           }
+       }
+    }
+
+    free(hash->table);
+    hash->table = new_table;
+    hash->table_size = new_size;
+
+    return true;
 }
 
-static void
-_free_list(zip_hash_entry_t *entry)
+
+static zip_uint32_t
+size_for_capacity(zip_uint64_t capacity) {
+    double needed_size = capacity / HASH_MAX_FILL;
+    zip_uint32_t v;
+
+    if (needed_size > ZIP_UINT32_MAX) {
+       v = ZIP_UINT32_MAX;
+    }
+    else {
+       v = (zip_uint32_t)needed_size;
+    }
+
+    if (v > HASH_MAX_SIZE) {
+       return HASH_MAX_SIZE;
+    }
+
+    /* From Bit Twiddling Hacks by Sean Eron Anderson <seander@cs.stanford.edu>
+     (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2). */
+
+    v--;
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v++;
+
+    return v;
+}
+
+
+zip_hash_t *
+_zip_hash_new(zip_error_t *error)
 {
-    zip_hash_entry_t *next;
-    do {
-       next = entry->next;
-       free(entry);
-       entry = next;
-    } while (entry != NULL);
+    zip_hash_t *hash;
+
+    if ((hash = (zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) {
+        zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    hash->table_size = 0;
+    hash->nentries = 0;
+    hash->table = NULL;
+    
+    return hash;
 }
 
+
 void
 _zip_hash_free(zip_hash_t *hash)
 {
-    zip_uint16_t i;
+    zip_uint32_t i;
 
     if (hash == NULL) {
        return;
     }
 
-    for (i=0; i<hash->table_size; i++) {
-       if (hash->table[i] != NULL) {
-           _free_list(hash->table[i]);
+    if (hash->table != NULL) {
+       for (i=0; i<hash->table_size; i++) {
+           if (hash->table[i] != NULL) {
+               free_list(hash->table[i]);
+           }
        }
+       free(hash->table);
     }
-    free(hash->table);
     free(hash);
 }
 
-static zip_uint16_t
-_hash_string(const zip_uint8_t *name, zip_uint16_t size)
-{
-#define HASH_MULTIPLIER 33
-    zip_uint16_t value = 5381;
-
-    if (name == NULL)
-       return 0;
-
-    while (*name != 0) {
-       value = (zip_uint16_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % size);
-       name++;
-    }
-
-    return value;
-}
 
 /* insert into hash, return error on existence or memory issues */
 bool
 _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error)
 {
-    zip_uint16_t hash_value;
+    zip_uint32_t hash_value, table_index;
     zip_hash_entry_t *entry;
 
     if (hash == NULL || name == NULL || index > ZIP_INT64_MAX) {
@@ -130,43 +217,59 @@ _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip
        return false;
     }
 
-    hash_value = _hash_string(name, hash->table_size);
-    for (entry = hash->table[hash_value]; entry != NULL; entry = entry->next) {
-       if (strcmp((const char *)name, (const char *)entry->name) == 0) {
-           if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) {
-               zip_error_set(error, ZIP_ER_EXISTS, 0);
-               return false;
-           }
-           else {
-               break;
-           }
+    if (hash->table_size == 0) {
+       if (!hash_resize(hash, HASH_MIN_SIZE, error)) {
+           return false;
        }
     }
 
+    hash_value = hash_string(name);
+    table_index = hash_value % hash->table_size;
+
+    for (entry = hash->table[table_index]; entry != NULL; entry = entry->next) {
+        if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) {
+            if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) {
+                zip_error_set(error, ZIP_ER_EXISTS, 0);
+                return false;
+            }
+            else {
+                break;
+            }
+        }
+    }
+
     if (entry == NULL) {
-       if ((entry=(zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) {
-           zip_error_set(error, ZIP_ER_MEMORY, 0);
-           return false;
+        if ((entry = (zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) {
+            zip_error_set(error, ZIP_ER_MEMORY, 0);
+            return false;
+        }
+        entry->name = name;
+        entry->next = hash->table[table_index];
+        hash->table[table_index] = entry;
+        entry->hash_value = hash_value;
+        entry->orig_index = -1;
+        hash->nentries++;
+       if (hash->nentries > hash->table_size * HASH_MAX_FILL && hash->table_size < HASH_MAX_SIZE) {
+           if (!hash_resize(hash, hash->table_size * 2, error)) {
+               return false;
+           }
        }
-       entry->name = name;
-       entry->next = hash->table[hash_value];
-       hash->table[hash_value] = entry;
-       entry->orig_index = -1;
     }
 
     if (flags & ZIP_FL_UNCHANGED) {
-       entry->orig_index = (zip_int64_t)index;
+        entry->orig_index = (zip_int64_t)index;
     }
     entry->current_index = (zip_int64_t)index;
 
     return true;
 }
 
+
 /* remove entry from hash, error if not found */
 bool
 _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error)
 {
-    zip_uint16_t hash_value;
+    zip_uint32_t hash_value, index;
     zip_hash_entry_t *entry, *previous;
 
     if (hash == NULL || name == NULL) {
@@ -174,94 +277,144 @@ _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error)
        return false;
     }
 
-    hash_value = _hash_string(name, hash->table_size);
-    previous = NULL;
-    entry = hash->table[hash_value];
-    while (entry) {
-       if (strcmp((const char *)name, (const char *)entry->name) == 0) {
-           if (entry->orig_index == -1) {
-               if (previous) {
-                   previous->next = entry->next;
+    if (hash->nentries > 0) {
+       hash_value = hash_string(name);
+       index = hash_value % hash->table_size;
+       previous = NULL;
+       entry = hash->table[index];
+       while (entry) {
+           if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) {
+               if (entry->orig_index == -1) {
+                   if (previous) {
+                       previous->next = entry->next;
+                   }
+                   else {
+                       hash->table[index] = entry->next;
+                   }
+                   free(entry);
+                   hash->nentries--;
+                   if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) {
+                       if (!hash_resize(hash, hash->table_size / 2, error)) {
+                           return false;
+                       }
+                   }
                }
                else {
-                   hash->table[hash_value] = entry->next;
+                   entry->current_index = -1;
                }
-               free(entry);
-           }
-           else {
-               entry->current_index = -1;
+               return true;
            }
-           return true;
+           previous = entry;
+           entry = entry->next;
        }
-       previous = entry;
-       entry = entry->next;
-    };
+    }
 
     zip_error_set(error, ZIP_ER_NOENT, 0);
     return false;
 }
 
+
 /* find value for entry in hash, -1 if not found */
 zip_int64_t
 _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error)
 {
-    zip_uint16_t hash_value;
+    zip_uint32_t hash_value, index;
     zip_hash_entry_t *entry;
 
     if (hash == NULL || name == NULL) {
-       zip_error_set(error, ZIP_ER_INVAL, 0);
-       return -1;
+        zip_error_set(error, ZIP_ER_INVAL, 0);
+        return -1;
     }
 
-    hash_value = _hash_string(name, hash->table_size);
-    for (entry = hash->table[hash_value]; entry != NULL; entry = entry->next) {
-       if (strcmp((const char *)name, (const char *)entry->name) == 0) {
-           if (flags & ZIP_FL_UNCHANGED) {
-               if (entry->orig_index != -1) {
-                   return entry->orig_index;
+    if (hash->nentries > 0) {
+       hash_value = hash_string(name);
+       index = hash_value % hash->table_size;
+       for (entry = hash->table[index]; entry != NULL; entry = entry->next) {
+           if (strcmp((const char *)name, (const char *)entry->name) == 0) {
+               if (flags & ZIP_FL_UNCHANGED) {
+                   if (entry->orig_index != -1) {
+                       return entry->orig_index;
+                   }
                }
-           }
-           else {
-               if (entry->current_index != -1) {
-                   return entry->current_index;
+               else {
+                   if (entry->current_index != -1) {
+                       return entry->current_index;
+                   }
                }
+               break;
            }
-           break;
        }
     }
 
     zip_error_set(error, ZIP_ER_NOENT, 0);
-    return -1;    
+    return -1;
 }
 
-void
-_zip_hash_revert(zip_hash_t *hash)
+
+bool
+_zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error)
 {
-    zip_uint16_t i;
+    zip_uint32_t new_size;
+
+    if (capacity == 0) {
+       return true;
+    }
+
+    new_size = size_for_capacity(capacity);
+
+    if (new_size <= hash->table_size) {
+       return true;
+    }
+
+    if (!hash_resize(hash, new_size, error)) {
+        return false;
+    }
+
+    return true;
+}
+
+
+bool
+_zip_hash_revert(zip_hash_t *hash, zip_error_t *error)
+{
+    zip_uint32_t i;
     zip_hash_entry_t *entry, *previous;
     
     for (i = 0; i < hash->table_size; i++) {
-       previous = NULL;
-       entry = hash->table[i];
-       while (entry) {
-           if (entry->orig_index == -1) {
-               zip_hash_entry_t *p;
-               if (previous) {
-                   previous->next = entry->next;
-               }
-               else {
-                   hash->table[i] = entry->next;
-               }
-               p = entry;
-               entry = entry->next;
-               /* previous does not change */
-               free(p);
-           }
-           else {
-               entry->current_index = entry->orig_index;
-               previous = entry;
-               entry = entry->next;
-           }
+        previous = NULL;
+        entry = hash->table[i];
+        while (entry) {
+            if (entry->orig_index == -1) {
+                zip_hash_entry_t *p;
+                if (previous) {
+                    previous->next = entry->next;
+                }
+                else {
+                    hash->table[i] = entry->next;
+                }
+                p = entry;
+                entry = entry->next;
+                /* previous does not change */
+                free(p);
+                hash->nentries--;
+            }
+            else {
+                entry->current_index = entry->orig_index;
+                previous = entry;
+                entry = entry->next;
+            }
+        }
+    }
+
+    if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) {
+       zip_uint32_t new_size = hash->table_size / 2;
+       while (hash->nentries < new_size * HASH_MIN_FILL && new_size > HASH_MIN_SIZE) {
+           new_size /= 2;
+       }
+       if (!hash_resize(hash, new_size, error)) {
+           return false;
        }
     }
+
+    return true;
 }
index c05c2a3..96ece2d 100644 (file)
@@ -52,7 +52,7 @@ _zip_new(zip_error_t *error)
        return NULL;
     }
 
-    if ((za->names = _zip_hash_new(ZIP_HASH_TABLE_SIZE, error)) == NULL) {
+    if ((za->names = _zip_hash_new(error)) == NULL) {
        free(za);
        return NULL;
     }
@@ -68,7 +68,7 @@ _zip_new(zip_error_t *error)
     za->entry = NULL;
     za->nopen_source = za->nopen_source_alloc = 0;
     za->open_source = NULL;
-    za->progress_callback = NULL;
+    za->progress = NULL;
     
     return za;
 }
index f62f95f..9d3a4cb 100644 (file)
@@ -157,12 +157,6 @@ zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error)
     }
 }
 
-ZIP_EXTERN void
-zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback)
-{
-    za->progress_callback = progress_callback;
-}
-
 
 zip_t *
 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
@@ -212,6 +206,8 @@ _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
 
     free(cdir);
 
+    _zip_hash_reserve_capacity(za->names, za->nentry, &za->error);
+    
     for (idx = 0; idx < za->nentry; idx++) {
        const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
        if (name == NULL) {
@@ -407,7 +403,6 @@ _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_err
 
             if (offset < 0) {
                 _zip_error_set_from_source(error, za->src);
-                _zip_buffer_free(cd_buffer);
                 _zip_cdir_free(cd);
                 return NULL;
             }
@@ -809,10 +804,16 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse
     }
     if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
        zip_error_set(error, ZIP_ER_INCONS, 0);
+        if (free_buffer) {
+            _zip_buffer_free(buffer);
+        }
        return NULL;
     }
     if (num_disks != 0 || eocd_disk != 0) {
        zip_error_set(error, ZIP_ER_MULTIDISK, 0);
+        if (free_buffer) {
+            _zip_buffer_free(buffer);
+        }
        return NULL;
     }
 
@@ -846,7 +847,12 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse
         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
         return NULL;
     }
-    if ((flags & ZIP_CHECKCONS) && offset+size != eocd_offset) {
+    if (offset+size > buf_offset + eocd_offset) {
+       /* cdir spans past EOCD record */
+       zip_error_set(error, ZIP_ER_INCONS, 0);
+       return NULL;
+    }
+    if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
        zip_error_set(error, ZIP_ER_INCONS, 0);
        return NULL;
     }
diff --git a/lib/zip_progress.c b/lib/zip_progress.c
new file mode 100644 (file)
index 0000000..b1b6e58
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ zip_progress.c -- progress reporting
+ Copyright (C) 2017 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <stdlib.h>
+
+
+#define _ZIP_COMPILING_DEPRECATED
+#include "zipint.h"
+
+struct zip_progress {
+    zip_t *za;
+    zip_progress_callback callback;
+    void (*ud_free)(void *);
+
+    void *ud;
+
+    double precision;
+
+    /* state */
+    double last_update;  /* last value callback function was called with */
+
+    double start;        /* start of sub-progress section */
+    double end;          /* end of sub-progress section */
+};
+
+
+void
+_zip_progress_end(zip_progress_t *progress) {
+    _zip_progress_update(progress, 1.0);
+}
+
+
+void
+_zip_progress_free(zip_progress_t *progress) {
+    if (progress == NULL) {
+        return;
+    }
+
+    if (progress->ud_free) {
+        progress->ud_free(progress->ud);
+    }
+
+    free(progress);
+}
+
+
+zip_progress_t *
+_zip_progress_new(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
+    zip_progress_t *progress = (zip_progress_t *)malloc(sizeof(*progress));
+
+    if (progress == NULL) {
+        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    progress->za = za;
+    progress->callback = callback;
+    progress->ud_free = ud_free;
+    progress->ud = ud;
+    progress->precision = precision;
+
+    return progress;
+}
+
+
+void
+_zip_progress_start(zip_progress_t *progress) {
+    if (progress == NULL) {
+        return;
+    }
+
+    progress->last_update = 0.0;
+    progress->callback(progress->za, 0.0, progress->ud);
+}
+
+
+void
+_zip_progress_subrange(zip_progress_t *progress, double start, double end) {
+    if (progress == NULL) {
+        return;
+    }
+
+    progress->start = start;
+    progress->end = end;
+
+    _zip_progress_update(progress, 0.0);
+}
+
+void
+_zip_progress_update(zip_progress_t *progress, double sub_current) {
+    double current;
+
+    if (progress == NULL) {
+        return;
+    }
+
+    current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start;
+
+    if (current - progress->last_update > progress->precision) {
+        progress->callback(progress->za, current, progress->ud);
+        progress->last_update = current;
+    }
+}
+
+
+ZIP_EXTERN int
+zip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
+    zip_progress_t *progress = NULL;
+
+    if (callback != NULL) {
+        if ((progress = _zip_progress_new(za, precision, callback, ud_free, ud)) == NULL) {
+            return -1;
+        }
+    }
+
+    _zip_progress_free(za->progress);
+    za->progress = progress;
+
+    return 0;
+}
+
+
+struct legacy_ud {
+    zip_progress_callback_t callback;
+};
+
+
+static void
+_zip_legacy_progress_callback(zip_t *za, double progress, void *vud) {
+    struct legacy_ud *ud = (struct legacy_ud *)vud;
+
+    ud->callback(progress);
+}
+
+ZIP_EXTERN void
+zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback)
+{
+    struct legacy_ud *ud;
+    
+    if (progress_callback == NULL) {
+        zip_register_progress_callback_with_state(za, 0, NULL, NULL, NULL);
+    }
+
+    if ((ud = (struct legacy_ud *)malloc(sizeof(*ud))) == NULL) {
+        return;
+    }
+
+    ud->callback = progress_callback;
+
+    if (zip_register_progress_callback_with_state(za, 0.001, _zip_legacy_progress_callback, free, ud) < 0) {
+        free(ud);
+    }
+}
index 7a932ef..26706f0 100644 (file)
@@ -34,6 +34,7 @@
 #include "zipint.h"
 
 #include <fcntl.h>
+#include <unistd.h>
 
 bool
 zip_random(zip_uint8_t *buffer, zip_uint16_t length)
index 7bb0bf9..a35290d 100644 (file)
@@ -41,7 +41,7 @@ zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_ui
     zip_entry_t *e;
     zip_int32_t old_method;
 
-    if (idx >= za->nentry) {
+    if (idx >= za->nentry || flags > 9) {
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
        return -1;
     }
@@ -51,7 +51,7 @@ zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_ui
        return -1;
     }
 
-    if (method != ZIP_CM_DEFAULT && method != ZIP_CM_STORE && method != ZIP_CM_DEFLATE) {
+    if (!zip_compression_method_supported(method, true)) {
        zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
        return -1;
     }
@@ -60,11 +60,15 @@ zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_ui
     
     old_method = (e->orig == NULL ? ZIP_CM_DEFAULT : e->orig->comp_method);
     
-    /* TODO: revisit this when flags are supported, since they may require a recompression */
+    /* TODO: do we want to recompress if level is set? Only if it's
+     * different than what bit flags tell us, but those are not
+     * defined for all compression methods, or not directly mappable
+     * to levels */
     
     if (method == old_method) {
        if (e->changes) {
            e->changes->changed &= ~ZIP_DIRENT_COMP_METHOD;
+           e->changes->compression_level = 0;
            if (e->changes->changed == 0) {
                _zip_dirent_free(e->changes);
                e->changes = NULL;
@@ -80,6 +84,7 @@ zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_ui
         }
 
         e->changes->comp_method = method;
+       e->changes->compression_level = (zip_uint16_t)flags;
         e->changes->changed |= ZIP_DIRENT_COMP_METHOD;
     }
     
diff --git a/lib/zip_source_compress.c b/lib/zip_source_compress.c
new file mode 100644 (file)
index 0000000..37e0318
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+  zip_source_compress.c -- (de)compression routines
+  Copyright (C) 2017 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "zipint.h"
+
+struct context {
+    zip_error_t error;
+
+    bool end_of_input;
+    bool end_of_stream;
+    bool can_store;
+    bool is_stored;
+    bool compress;
+    zip_int32_t method;
+    
+    zip_uint64_t size;
+    zip_int64_t first_read;
+    zip_uint8_t buffer[BUFSIZE];
+    
+    zip_compression_algorithm_t *algorithm;
+    void *ud;
+};
+
+
+struct implementation {
+    zip_uint16_t method;
+    zip_compression_algorithm_t *compress;
+    zip_compression_algorithm_t *decompress;
+};
+
+static struct implementation implementations[] = {
+    { ZIP_CM_DEFLATE, &zip_algorithm_deflate_compress, &zip_algorithm_deflate_decompress },
+#if defined(HAVE_LIBBZ2)
+    { ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress },
+#endif
+};
+
+static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]);
+
+static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags);
+static zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
+static void context_free(struct context *ctx);
+static struct context *context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm);
+static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t);
+
+static zip_compression_algorithm_t *
+get_algorithm(zip_int32_t method, bool compress) {
+    size_t i;
+    zip_uint16_t real_method = ZIP_CM_ACTUAL(method);
+
+    for (i = 0; i < implementations_size; i++) {
+       if (implementations[i].method == real_method) {
+           if (compress) {
+               return implementations[i].compress;
+           }
+           else {
+               return implementations[i].decompress;
+           }
+       }
+    }
+
+    return NULL;
+}
+
+bool
+zip_compression_method_supported(zip_int32_t method, bool compress) {
+    if (method == ZIP_CM_STORE) {
+       return true;
+    }
+    return get_algorithm(method, compress) != NULL;
+}
+
+zip_source_t *
+zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, int compression_flags) {
+    return compression_source_new(za, src, method, true, compression_flags);
+}
+
+zip_source_t *
+zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method) {
+    return compression_source_new(za, src, method, false, 0);
+}
+
+
+static zip_source_t *
+compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags)
+{
+    struct context *ctx;
+    zip_source_t *s2;
+    zip_compression_algorithm_t *algorithm = NULL;
+    
+    if (src == NULL) {
+       zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+       return NULL;
+    }
+
+    if ((algorithm = get_algorithm(method, compress)) == NULL) {
+       zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+       return NULL;
+    }
+
+    if ((ctx = context_new(method, compress, compression_flags, algorithm)) == NULL) {
+       zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+       return NULL;
+    }
+    
+    if ((s2 = zip_source_layered(za, src, compress_callback, ctx)) == NULL) {
+       context_free(ctx);
+       return NULL;
+    }
+
+    return s2;
+}
+
+
+static struct context *
+context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm) {
+    struct context *ctx;
+    
+    if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) {
+       return NULL;
+    }
+    zip_error_init(&ctx->error);
+    ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false;
+    ctx->algorithm = algorithm;
+    ctx->method = method;
+    ctx->compress = compress;
+    
+    if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) {
+       zip_error_fini(&ctx->error);
+       free(ctx);
+       return NULL;
+    }
+    
+    return ctx;
+}
+
+
+static void
+context_free(struct context *ctx) {
+    if (ctx == NULL) {
+       return;
+    }
+
+    ctx->algorithm->deallocate(ctx->ud);
+    zip_error_fini(&ctx->error);
+
+    free(ctx);
+}
+
+
+static zip_int64_t
+compress_read(zip_source_t *src, struct context *ctx, void *data, zip_uint64_t len)
+{
+    zip_compression_status_t ret;
+    bool end;
+    zip_int64_t n;
+    zip_uint64_t out_offset;
+    zip_uint64_t out_len;
+
+    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) {
+       return -1;
+    }
+    
+    if (len == 0 || ctx->end_of_stream) {
+       return 0;
+    }
+       
+    out_offset = 0;
+
+    end = false;
+    while (!end && out_offset < len) {
+       out_len = len - out_offset;
+       ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len);
+
+       if (ret != ZIP_COMPRESSION_ERROR) {
+           out_offset += out_len;
+       }
+
+       switch (ret) {
+        case ZIP_COMPRESSION_END:
+           ctx->end_of_stream = true;
+
+           if (!ctx->end_of_input) {
+               /* TODO: garbage after stream, or compression ended before all data read */
+           }
+
+           if (ctx->first_read < 0) {
+               /* we got end of processed stream before reading any input data */
+               zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
+               end = true;
+               break;
+           }
+            if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) {
+                ctx->is_stored = true;
+                ctx->size = (zip_uint64_t)ctx->first_read;
+                memcpy(data, ctx->buffer, ctx->size);
+                return (zip_int64_t)ctx->size;
+            }
+           end = true;
+           break;
+           
+       case ZIP_COMPRESSION_OK:
+           break;
+
+       case ZIP_COMPRESSION_NEED_DATA:
+           if (ctx->end_of_input) {
+               /* TODO: error: stream not ended, but no more input */
+               end = true;
+               break;
+           }
+
+           if ((n = zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
+               _zip_error_set_from_source(&ctx->error, src);
+               end = true;
+               break;
+           }
+           else if (n == 0) {
+               ctx->end_of_input = true;
+               ctx->algorithm->end_of_input(ctx->ud);
+               if (ctx->first_read < 0) {
+                   ctx->first_read = 0;
+               }
+           }
+           else {
+               if (ctx->first_read >= 0) {
+                   /* we overwrote a previously filled ctx->buffer */
+                   ctx->can_store = false;
+               }
+               else {
+                   ctx->first_read = n;
+               }
+
+               ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n);
+           }
+           break;
+           
+       case ZIP_COMPRESSION_ERROR:
+           /* error set by algorithm */
+           if (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) {
+               zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
+           }
+           end = true;
+           break;
+       }
+    }
+
+    if (out_offset > 0) {
+       ctx->can_store = false;
+       ctx->size += out_offset;
+       return (zip_int64_t)out_offset;
+    }
+
+    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
+}
+
+
+static zip_int64_t
+compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
+{
+    struct context *ctx;
+
+    ctx = (struct context *)ud;
+
+    switch (cmd) {
+    case ZIP_SOURCE_OPEN:
+       ctx->size = 0;
+       ctx->end_of_input = false;
+       ctx->end_of_stream = false;
+       ctx->is_stored = false;
+       ctx->first_read = -1;
+       
+       if (!ctx->algorithm->start(ctx->ud)) {
+           return -1;
+       }
+
+       return 0;
+
+    case ZIP_SOURCE_READ:
+       return compress_read(src, ctx, data, len);
+
+    case ZIP_SOURCE_CLOSE:
+       if (!ctx->algorithm->end(ctx->ud)) {
+           return -1;
+       }
+       return 0;
+
+    case ZIP_SOURCE_STAT:
+       {
+           zip_stat_t *st;
+
+           st = (zip_stat_t *)data;
+
+           if (ctx->compress) {
+               st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method);
+               if (ctx->end_of_stream) {
+                   st->comp_size = ctx->size;
+                   st->valid |= ZIP_STAT_COMP_SIZE;
+               }
+               else {
+                   st->valid &= ~ZIP_STAT_COMP_SIZE;
+               }
+           }
+           else {
+               st->comp_method = ZIP_CM_STORE;
+               if (ctx->end_of_stream) {
+                   st->size = ctx->size;
+                   st->valid |= ZIP_STAT_SIZE;
+               }
+               else {
+                   st->valid &= ~ZIP_STAT_SIZE;
+               }
+           }
+           st->valid |= ZIP_STAT_COMP_METHOD;
+       }
+       return 0;
+
+    case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
+       return ctx->is_stored ? 0 : ctx->algorithm->compression_flags(ctx->ud);
+
+    case ZIP_SOURCE_ERROR:
+        return zip_error_to_data(&ctx->error, data, len);
+
+    case ZIP_SOURCE_FREE:
+       context_free(ctx);
+       return 0;
+
+    case ZIP_SOURCE_SUPPORTS:
+        return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
+            
+    default:
+        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
+       return -1;
+    }
+}
index 01f526c..ef861bd 100644 (file)
@@ -171,7 +171,7 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
                 return -1;
             }
 
-            return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1);
+            return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
         }
 
         case ZIP_SOURCE_SEEK:
diff --git a/lib/zip_source_deflate.c b/lib/zip_source_deflate.c
deleted file mode 100644 (file)
index 2574ad0..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
-  zip_source_deflate.c -- deflate (de)compressoin routines
-  Copyright (C) 2009-2015 Dieter Baron and Thomas Klausner
-
-  This file is part of libzip, a library to manipulate ZIP archives.
-  The authors can be contacted at <libzip@nih.at>
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-  1. Redistributions of source code must retain the above copyright
-     notice, this list of conditions and the following disclaimer.
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-  3. The names of the authors may not be used to endorse or promote
-     products derived from this software without specific prior
-     written permission.
-  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
-  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include "zipint.h"
-
-struct deflate {
-    zip_error_t error;
-    
-    bool eof;
-    bool can_store;
-    bool is_stored;
-    int mem_level;
-    zip_uint64_t size;
-    zip_uint8_t buffer[BUFSIZE];
-    z_stream zstr;
-};
-
-static zip_int64_t compress_read(zip_source_t *, struct deflate *, void *, zip_uint64_t);
-static zip_int64_t decompress_read(zip_source_t *, struct deflate *, void *, zip_uint64_t);
-static zip_int64_t deflate_compress(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
-static zip_int64_t deflate_decompress(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
-static void deflate_free(struct deflate *);
-
-
-zip_source_t *
-zip_source_deflate(zip_t *za, zip_source_t *src, zip_int32_t cm, int flags)
-{
-    struct deflate *ctx;
-    zip_source_t *s2;
-
-    if (src == NULL || (cm != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(cm))) {
-       zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-       return NULL;
-    }
-
-    if ((ctx=(struct deflate *)malloc(sizeof(*ctx))) == NULL) {
-       zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
-       return NULL;
-    }
-
-    zip_error_init(&ctx->error);
-    ctx->eof = false;
-    ctx->is_stored = false;
-    ctx->can_store = ZIP_CM_IS_DEFAULT(cm);
-    if (flags & ZIP_CODEC_ENCODE) {
-       ctx->mem_level = MAX_MEM_LEVEL;
-    }
-
-    if ((s2=zip_source_layered(za, src,
-                              ((flags & ZIP_CODEC_ENCODE)
-                               ? deflate_compress : deflate_decompress),
-                              ctx)) == NULL) {
-       deflate_free(ctx);
-       return NULL;
-    }
-
-    return s2;
-}
-
-
-static zip_int64_t
-compress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len)
-{
-    int end, ret;
-    zip_int64_t n;
-    zip_uint64_t out_offset;
-    uInt out_len;
-
-    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK)
-       return -1;
-    
-    if (len == 0 || ctx->is_stored) {
-       return 0;
-    }
-       
-    out_offset = 0;
-    out_len = (uInt)ZIP_MIN(UINT_MAX, len);
-    ctx->zstr.next_out = (Bytef *)data;
-    ctx->zstr.avail_out = out_len;
-
-    end = 0;
-    while (!end) {
-       ret = deflate(&ctx->zstr, ctx->eof ? Z_FINISH : 0);
-
-       switch (ret) {
-        case Z_STREAM_END:
-            if (ctx->can_store && ctx->zstr.total_in <= ctx->zstr.total_out) {
-                ctx->is_stored = true;
-                ctx->size = ctx->zstr.total_in;
-                memcpy(data, ctx->buffer, ctx->size);
-                return (zip_int64_t)ctx->size;
-            }
-            /* fallthrough */
-       case Z_OK:
-           /* all ok */
-
-           if (ctx->zstr.avail_out == 0) {
-               out_offset += out_len;
-               if (out_offset < len) {
-                   out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset);
-                   ctx->zstr.next_out = (Bytef *)data+out_offset;
-                   ctx->zstr.avail_out = out_len;
-               }
-               else {
-                    ctx->can_store = false;
-                   end = 1;
-               }
-           }
-           else if (ctx->eof && ctx->zstr.avail_in == 0)
-               end = 1;
-           break;
-
-       case Z_BUF_ERROR:
-           if (ctx->zstr.avail_in == 0) {
-               if (ctx->eof) {
-                   end = 1;
-                   break;
-               }
-
-               if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
-                    _zip_error_set_from_source(&ctx->error, src);
-                   end = 1;
-                   break;
-               }
-               else if (n == 0) {
-                   ctx->eof = true;
-                   /* TODO: check against stat of src? */
-                   ctx->size = ctx->zstr.total_in;
-               }
-               else {
-                    if (ctx->zstr.total_in > 0) {
-                        /* we overwrote a previously filled ctx->buffer */
-                        ctx->can_store = false;
-                    }
-                   ctx->zstr.next_in = (Bytef *)ctx->buffer;
-                   ctx->zstr.avail_in = (uInt)n;
-               }
-               continue;
-           }
-           /* fallthrough */
-       case Z_NEED_DICT:
-       case Z_DATA_ERROR:
-       case Z_STREAM_ERROR:
-       case Z_MEM_ERROR:
-            zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
-
-           end = 1;
-           break;
-       }
-    }
-
-    if (ctx->zstr.avail_out < len) {
-       ctx->can_store = false;
-       return (zip_int64_t)(len - ctx->zstr.avail_out);
-    }
-
-    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
-}
-
-
-static zip_int64_t
-decompress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len)
-{
-    int end, ret;
-    zip_int64_t n;
-    zip_uint64_t out_offset;
-    uInt out_len;
-
-    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK)
-       return -1;
-    
-    if (len == 0)
-       return 0;
-
-    out_offset = 0;
-    out_len = (uInt)ZIP_MIN(UINT_MAX, len);
-    ctx->zstr.next_out = (Bytef *)data;
-    ctx->zstr.avail_out = out_len;
-
-    end = 0;
-    while (!end) {
-       ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);
-
-       switch (ret) {
-       case Z_OK:
-           if (ctx->zstr.avail_out == 0) {
-               out_offset += out_len;
-               if (out_offset < len) {
-                   out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset);
-                   ctx->zstr.next_out = (Bytef *)data+out_offset;
-                   ctx->zstr.avail_out = out_len;
-               }
-               else {
-                   end = 1;
-               }
-           }
-           break;
-           
-       case Z_STREAM_END:
-           ctx->eof = 1;
-           end = 1;
-           break;
-
-       case Z_BUF_ERROR:
-           if (ctx->zstr.avail_in == 0) {
-               if (ctx->eof) {
-                   end = 1;
-                   break;
-               }
-
-               if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
-                    _zip_error_set_from_source(&ctx->error, src);
-                   end = 1;
-                   break;
-               }
-               else if (n == 0) {
-                   ctx->eof = 1;
-               }
-               else {
-                   ctx->zstr.next_in = (Bytef *)ctx->buffer;
-                   ctx->zstr.avail_in = (uInt)n;
-               }
-               continue;
-           }
-           /* fallthrough */
-       case Z_NEED_DICT:
-       case Z_DATA_ERROR:
-       case Z_STREAM_ERROR:
-       case Z_MEM_ERROR:
-            zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
-           end = 1;
-           break;
-       }
-    }
-
-    if (ctx->zstr.avail_out < len)
-       return (zip_int64_t)(len - ctx->zstr.avail_out);
-
-    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
-}
-
-
-static zip_int64_t
-deflate_compress(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
-{
-    struct deflate *ctx;
-    int ret;
-
-    ctx = (struct deflate *)ud;
-
-    switch (cmd) {
-    case ZIP_SOURCE_OPEN:
-       ctx->zstr.zalloc = Z_NULL;
-       ctx->zstr.zfree = Z_NULL;
-       ctx->zstr.opaque = NULL;
-       ctx->zstr.avail_in = 0;
-       ctx->zstr.next_in = NULL;
-       ctx->zstr.avail_out = 0;
-       ctx->zstr.next_out = NULL;
-
-       /* negative value to tell zlib not to write a header */
-       if ((ret=deflateInit2(&ctx->zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
-            zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
-           return -1;
-       }
-
-       return 0;
-
-    case ZIP_SOURCE_READ:
-       return compress_read(src, ctx, data, len);
-
-    case ZIP_SOURCE_CLOSE:
-       deflateEnd(&ctx->zstr);
-       return 0;
-
-    case ZIP_SOURCE_STAT:
-       {
-           zip_stat_t *st;
-
-           st = (zip_stat_t *)data;
-
-           st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_DEFLATE;
-           st->valid |= ZIP_STAT_COMP_METHOD;
-           if (ctx->eof) {
-               st->comp_size = ctx->size;
-               st->valid |= ZIP_STAT_COMP_SIZE;
-           }
-           else
-               st->valid &= ~ZIP_STAT_COMP_SIZE;
-       }
-       return 0;
-
-    case ZIP_SOURCE_ERROR:
-        return zip_error_to_data(&ctx->error, data, len);
-
-    case ZIP_SOURCE_FREE:
-       deflate_free(ctx);
-       return 0;
-
-    case ZIP_SOURCE_SUPPORTS:
-        return ZIP_SOURCE_SUPPORTS_READABLE;
-            
-    default:
-        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
-       return -1;
-    }
-}
-
-
-static zip_int64_t
-deflate_decompress(zip_source_t *src, void *ud, void *data,
-                  zip_uint64_t len, zip_source_cmd_t cmd)
-{
-    struct deflate *ctx;
-    zip_int64_t n;
-    int ret;
-
-    ctx = (struct deflate *)ud;
-
-    switch (cmd) {
-        case ZIP_SOURCE_OPEN:
-            if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
-                _zip_error_set_from_source(&ctx->error, src);
-                return -1;
-            }
-
-            ctx->zstr.zalloc = Z_NULL;
-            ctx->zstr.zfree = Z_NULL;
-            ctx->zstr.opaque = NULL;
-            ctx->zstr.next_in = (Bytef *)ctx->buffer;
-            ctx->zstr.avail_in = (uInt)n;
-
-            /* negative value to tell zlib that there is no header */
-            if ((ret=inflateInit2(&ctx->zstr, -MAX_WBITS)) != Z_OK) {
-                zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
-                return -1;
-            }
-            return 0;
-
-        case ZIP_SOURCE_READ:
-            return decompress_read(src, ctx, data, len);
-
-        case ZIP_SOURCE_CLOSE:
-            inflateEnd(&ctx->zstr);
-            return 0;
-
-        case ZIP_SOURCE_STAT:
-        {
-            zip_stat_t *st;
-            
-            st = (zip_stat_t *)data;
-            
-            st->comp_method = ZIP_CM_STORE;
-            if (st->comp_size > 0 && st->size > 0)
-                st->comp_size = st->size;
-            
-            return 0;
-        }
-
-        case ZIP_SOURCE_ERROR:
-            return zip_error_to_data(&ctx->error, data, len);
-
-        case ZIP_SOURCE_FREE:
-            free(ctx);
-            return 0;
-            
-        case ZIP_SOURCE_SUPPORTS:
-            return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
-
-        default:
-            zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
-            return -1;
-    }
-}
-
-
-static void
-deflate_free(struct deflate *ctx)
-{
-    free(ctx);
-}
index a8a271a..0cb0ed0 100644 (file)
@@ -115,6 +115,8 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int
 {
     struct read_file *ctx;
     zip_source_t *zs;
+    struct stat sb;
+    bool stat_valid;
 
     if (file == NULL && fname == NULL) {
        zip_error_set(error, ZIP_ER_INVAL, 0);
@@ -170,42 +172,46 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int
     ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
 
     if (ctx->fname) {
-       struct stat sb;
-       if (stat(ctx->fname, &sb) < 0) {
-           zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
+       stat_valid = stat(ctx->fname, &sb) >= 0;
+
+       if (!stat_valid) {
            if (ctx->start == 0 && ctx->end == 0) {
                ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
            }
        }
-       else {
-           if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
-               ctx->st.mtime = sb.st_mtime;
-               ctx->st.valid |= ZIP_STAT_MTIME;
-           }
-           if (S_ISREG(sb.st_mode)) {
-               ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
-
-               if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) {
-                   zip_error_set(error, ZIP_ER_INVAL, 0);
-                   free(ctx->fname);
-                   free(ctx);
-                   return NULL;
-               }
+    }
+    else {
+       stat_valid = fstat(fileno(ctx->f), &sb) >= 0;
+    }
 
-               if (ctx->end == 0) {
-                   ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start;
-                   ctx->st.valid |= ZIP_STAT_SIZE;
+    if (!stat_valid) {
+       zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
+    }
+    else {
+       if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
+           ctx->st.mtime = sb.st_mtime;
+           ctx->st.valid |= ZIP_STAT_MTIME;
+       }
+       if (S_ISREG(sb.st_mode)) {
+           ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
+
+           if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) {
+               zip_error_set(error, ZIP_ER_INVAL, 0);
+               free(ctx->fname);
+               free(ctx);
+               return NULL;
+           }
 
-                   if (start == 0) {
-                       ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
-                   }
+           if (ctx->end == 0) {
+               ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start;
+               ctx->st.valid |= ZIP_STAT_SIZE;
+               
+               if (ctx->fname && start == 0) {
+                   ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
                }
            }
        }
     }
-    else if (fseeko(ctx->f, 0, SEEK_CUR) == 0) {
-        ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
-    }
 
     if ((zs=zip_source_function_create(read_file, ctx, error)) == NULL) {
        free(ctx->fname);
similarity index 70%
rename from lib/zip_get_compression_implementation.c
rename to lib/zip_source_get_compression_flags.c
index 5f8d0c7..b5bae82 100644 (file)
@@ -1,6 +1,6 @@
 /*
-  zip_get_compression_implementation.c -- get compression implementation
-  Copyright (C) 2009-2016 Dieter Baron and Thomas Klausner
+  zip_source_get_compression_flags.c -- get compression flags for entry
+  Copyright (C) 2017 Dieter Baron and Thomas Klausner
 
   This file is part of libzip, a library to manipulate ZIP archives.
   The authors can be contacted at <libzip@nih.at>
 
 #include "zipint.h"
 
+#define ZIP_COMPRESSION_BITFLAG_MAX    3
 
-zip_compression_implementation
-_zip_get_compression_implementation(zip_int32_t cm, int operation)
+zip_int8_t
+zip_source_get_compression_flags(zip_source_t *src)
 {
-    if (cm == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(cm))
-       return zip_source_deflate;
-    return NULL;
+    while (src) {
+       if ((src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_COMPRESSION_FLAGS))) {
+           zip_int64_t ret = _zip_source_call(src, NULL, 0, ZIP_SOURCE_GET_COMPRESSION_FLAGS);
+           if (ret < 0) {
+               return -1;
+           }
+           if (ret > ZIP_COMPRESSION_BITFLAG_MAX) {
+               zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);
+               return -1;
+           }
+           return (zip_int8_t)ret;
+       }
+       src = src->src;
+    }
+
+    return 0;
 }
index 85493b6..e343a70 100644 (file)
@@ -90,7 +90,7 @@ _win32_open_a(_zip_source_win32_read_file_t *ctx)
 static HANDLE
 _win32_create_temp_a(_zip_source_win32_read_file_t *ctx, void **temp, zip_uint32_t value, PSECURITY_ATTRIBUTES sa)
 {
-    int len;
+    size_t len;
 
     len = strlen((const char *)ctx->fname) + 10;
     if (*temp == NULL) {
index 551aba5..d8b8f86 100644 (file)
@@ -90,7 +90,7 @@ _win32_open_w(_zip_source_win32_read_file_t *ctx)
 static HANDLE
 _win32_create_temp_w(_zip_source_win32_read_file_t *ctx, void **temp, zip_uint32_t value, PSECURITY_ATTRIBUTES sa)
 {
-    int len;
+    size_t len;
 
     len = wcslen((const wchar_t *)ctx->fname) + 10;
     if (*temp == NULL) {
index f02d048..ec0c8b4 100644 (file)
@@ -17,7 +17,7 @@
   3. The names of the authors may not be used to endorse or promote
      products derived from this software without specific prior
      written permission.
+
   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 #include "zipint.h"
 
 struct window {
-    zip_uint64_t start;
-    zip_uint64_t end;
-    zip_uint64_t offset;
+    zip_uint64_t start;                        /* where in file we start reading */
+    zip_uint64_t end;                  /* where in file we stop reading */
+
+    /* if not NULL, read file data for this file */
+    zip_t *source_archive;
+    zip_uint64_t source_index;
+
+    zip_uint64_t offset;               /* offset in src for next read */
+
     zip_stat_t stat;
+    zip_int8_t compression_flags;
     zip_error_t error;
     zip_int64_t supports;
     bool needs_seek;
@@ -53,39 +60,42 @@ static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip
 zip_source_t *
 zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t len)
 {
-    return _zip_source_window_new(src, start, len, NULL, &za->error);
+    return _zip_source_window_new(src, start, len, NULL, 0, NULL, 0, &za->error);
 }
 
 
 zip_source_t *
-_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_error_t *error)
+_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error)
 {
     struct window *ctx;
-    
-    if (src == NULL || start + length < start) {
+
+    if (src == NULL || start + length < start || (source_archive == NULL && source_index != 0)) {
         zip_error_set(error, ZIP_ER_INVAL, 0);
         return NULL;
     }
-    
+
     if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) {
         zip_error_set(error, ZIP_ER_MEMORY, 0);
         return NULL;
     }
-    
+
     ctx->start = start;
     ctx->end = start + length;
     zip_stat_init(&ctx->stat);
+    ctx->compression_flags = compression_flags;
+    ctx->source_archive = source_archive;
+    ctx->source_index = source_index;
     zip_error_init(&ctx->error);
-    ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
+    ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
     ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
-    
+
     if (st) {
         if (_zip_stat_merge(&ctx->stat, st, error) < 0) {
             free(ctx);
             return NULL;
         }
     }
-    
+
     return zip_source_layered_create(src, window_read, ctx, error);
 }
 
@@ -123,15 +133,31 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
     switch (cmd) {
         case ZIP_SOURCE_CLOSE:
             return 0;
-            
+
         case ZIP_SOURCE_ERROR:
             return zip_error_to_data(&ctx->error, data, len);
-            
+
         case ZIP_SOURCE_FREE:
             free(ctx);
             return 0;
 
         case ZIP_SOURCE_OPEN:
+           if (ctx->source_archive) {
+               zip_int64_t offset;
+
+               if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) {
+                   return -1;
+               }
+               if (ctx->end + offset < ctx->end) {
+                   /* zip archive data claims end of data past zip64 limits */
+                   zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
+                   return -1;
+               }
+               ctx->start += offset;
+               ctx->end += offset;
+               ctx->source_archive = NULL;
+           }
+
             if (!ctx->needs_seek) {
                 for (n=0; n<ctx->start; n+=(zip_uint64_t)ret) {
                     i = (ctx->start-n > sizeof(b) ? sizeof(b) : ctx->start-n);
@@ -144,7 +170,7 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
                         return -1;
                     }
                 }
-               
+
             }
            ctx->offset = ctx->start;
             return 0;
@@ -152,17 +178,17 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
         case ZIP_SOURCE_READ:
             if (len > ctx->end - ctx->offset)
                 len = ctx->end - ctx->offset;
-            
+
             if (len == 0)
                 return 0;
-            
+
             if (ctx->needs_seek) {
                 if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {
                     _zip_error_set_from_source(&ctx->error, src);
                     return -1;
                 }
             }
-            
+
             if ((ret=zip_source_read(src, data, len)) < 0) {
                 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
                 return -1;
@@ -177,7 +203,7 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
                 }
             }
             return ret;
-            
+
         case ZIP_SOURCE_SEEK:
         {
             zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
@@ -185,7 +211,7 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
             if (new_offset < 0) {
                 return -1;
             }
-            
+
             ctx->offset = (zip_uint64_t)new_offset + ctx->start;
             return 0;
         }
@@ -193,21 +219,24 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
        case ZIP_SOURCE_STAT:
         {
             zip_stat_t *st;
-            
+
            st = (zip_stat_t *)data;
-            
+
             if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {
                 return -1;
             }
             return 0;
         }
-            
+
+        case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
+           return ctx->compression_flags;
+
         case ZIP_SOURCE_SUPPORTS:
             return ctx->supports;
-            
+
         case ZIP_SOURCE_TELL:
             return (zip_int64_t)(ctx->offset - ctx->start);
-            
+
        default:
             zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
             return -1;
@@ -219,7 +248,7 @@ void
 _zip_deregister_source(zip_t *za, zip_source_t *src)
 {
     unsigned int i;
-    
+
     for (i=0; i<za->nopen_source; i++) {
         if (za->open_source[i] == src) {
             za->open_source[i] = za->open_source[za->nopen_source-1];
@@ -234,7 +263,7 @@ int
 _zip_register_source(zip_t *za, zip_source_t *src)
 {
     zip_source_t **open_source;
-    
+
     if (za->nopen_source+1 >= za->nopen_source_alloc) {
         unsigned int n;
         n = za->nopen_source_alloc + 10;
@@ -246,8 +275,8 @@ _zip_register_source(zip_t *za, zip_source_t *src)
         za->nopen_source_alloc = n;
         za->open_source = open_source;
     }
-    
+
     za->open_source[za->nopen_source++] = src;
-    
+
     return 0;
 }
index 9256255..47eae79 100644 (file)
 zip_source_t *
 _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_uint64_t len, const char *password)
 {
-    zip_compression_implementation comp_impl;
-    zip_encryption_implementation enc_impl;
     zip_source_t *src, *s2;
-    zip_uint64_t offset;
     struct zip_stat st;
+    bool partial_data, needs_crc, needs_decrypt, needs_decompress;
 
     if (za == NULL)
        return NULL;
@@ -74,13 +72,22 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
     }
 
     /* overflow or past end of file */
-    if ((start > 0 || len > 0) && (start+len < start || start+len > st.size)) {
+    if ((start > 0 || len > 0) && (start + len < start || start + len > st.size)) {
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
        return NULL;
     }
 
-    enc_impl = NULL;
-    if (((flags & ZIP_FL_ENCRYPTED) == 0) && (st.encryption_method != ZIP_EM_NONE)) {
+    if (len == 0) {
+       len = st.size - start;
+    }
+
+    partial_data = len < st.size;
+    needs_decrypt = ((flags & ZIP_FL_ENCRYPTED) == 0) && (st.encryption_method != ZIP_EM_NONE);
+    needs_decompress = ((flags & ZIP_FL_COMPRESSED) == 0) && (st.comp_method != ZIP_CM_STORE);
+    /* when reading the whole file, check for CRC errors */
+    needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE) && !partial_data;
+    
+    if (needs_decrypt) {
         if (password == NULL) {
             password = za->default_password;
         }
@@ -88,48 +95,36 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
            zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
            return NULL;
        }
-       if ((enc_impl=_zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
-           zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
-           return NULL;
-       }
     }
 
-    comp_impl = NULL;
-    if ((flags & ZIP_FL_COMPRESSED) == 0) {
-       if (st.comp_method != ZIP_CM_STORE) {
-           if ((comp_impl=_zip_get_compression_implementation(st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
-               zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
-               return NULL;
-           }
-       }
-    }
-
-    if ((offset=_zip_file_get_offset(srcza, srcidx, &za->error)) == 0)
-       return NULL;
-
     if (st.comp_size == 0) {
        return zip_source_buffer(za, NULL, 0, 0);
     }
 
-    if (start+len > 0 && enc_impl == NULL && comp_impl == NULL) {
+    if (partial_data && !needs_decrypt && !needs_decompress) {
        struct zip_stat st2;
        
-       st2.size = len ? len : st.size-start;
-       st2.comp_size = st2.size;
+       st2.size = len;
+       st2.comp_size = len;
        st2.comp_method = ZIP_CM_STORE;
        st2.mtime = st.mtime;
        st2.valid = ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_MTIME;
        
-       if ((src = _zip_source_window_new(srcza->src, offset+start, st2.size, &st2, &za->error)) == NULL) {
+       if ((src = _zip_source_window_new(srcza->src, start, len, &st2, 0, srcza, srcidx, &za->error)) == NULL) {
            return NULL;
        }
     }
     else {
-       if ((src = _zip_source_window_new(srcza->src, offset, st.comp_size, &st, &za->error)) == NULL) {
+       zip_dirent_t *de;
+       
+       if ((de = _zip_get_dirent(srcza, srcidx, flags, &za->error)) == NULL) {
+           return NULL;
+       }
+       if ((src = _zip_source_window_new(srcza->src, 0, st.comp_size, &st, (de->bitflags >> 1) & 3, srcza, srcidx, &za->error)) == NULL) {
            return NULL;
        }
     }
-       
+    
     if (_zip_source_set_source_archive(src, srcza) < 0) {
        zip_source_free(src);
        return NULL;
@@ -137,7 +132,14 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
 
     /* creating a layered source calls zip_keep() on the lower layer, so we free it */
        
-    if (enc_impl) {
+    if (needs_decrypt) {
+       zip_encryption_implementation enc_impl;
+       
+       if ((enc_impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
+           zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
+           return NULL;
+       }
+
        s2 = enc_impl(za, src, st.encryption_method, 0, password);
        zip_source_free(src);
        if (s2 == NULL) {
@@ -145,16 +147,15 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
        }
        src = s2;
     }
-    if (comp_impl) {
-       s2 = comp_impl(za, src, st.comp_method, 0);
+    if (needs_decompress) {
+       s2 = zip_source_decompress(za, src, st.comp_method);
        zip_source_free(src);
        if (s2 == NULL) {
            return NULL;
        }
        src = s2;
     }
-    if (((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE) && (len == 0 || len == st.comp_size)) {
-       /* when reading the whole file, check for CRC errors */
+    if (needs_crc) {
        s2 = zip_source_crc(za, src, 1);
        zip_source_free(src);
        if (s2 == NULL) {
@@ -163,8 +164,8 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
        src = s2;
     }
 
-    if (start+len > 0 && (comp_impl || enc_impl)) {
-       s2 = zip_source_window(za, src, start, len ? len : st.size-start);
+    if (partial_data && (needs_decrypt || needs_decompress)) {
+       s2 = zip_source_window(za, src, start, len);
        zip_source_free(src);
        if (s2 == NULL) {
            return NULL;
index 2221d6c..39754b2 100644 (file)
@@ -43,7 +43,9 @@ zip_unchange_all(zip_t *za)
     int ret;
     zip_uint64_t i;
 
-    _zip_hash_revert(za->names);
+    if (!_zip_hash_revert(za->names, &za->error)) {
+        return -1;
+    }
     
     ret = 0;
     for (i=0; i<za->nentry; i++)
index 2c5c6b9..0c2ab42 100644 (file)
@@ -70,6 +70,7 @@
 #define ZIP_CM_WINZIP_AES         99  /* Winzip AES encrypted */
 
 #define ZIP_CM_IS_DEFAULT(x)   ((x) == ZIP_CM_DEFAULT || (x) == ZIP_CM_REPLACED_DEFAULT)
+#define ZIP_CM_ACTUAL(x)       ((zip_uint16_t)(ZIP_CM_IS_DEFAULT(x) ? ZIP_CM_DEFLATE : (x)))
 
 #define ZIP_EF_UTF_8_COMMENT   0x6375
 #define ZIP_EF_UTF_8_NAME      0x7075
 #define ZIP_CODEC_DECODE       0 /* decompress/decrypt (encode flag not set) */
 #define ZIP_CODEC_ENCODE       1 /* compress/encrypt */
 
-
-typedef zip_source_t *(*zip_compression_implementation)(zip_t *, zip_source_t *, zip_int32_t, int);
 typedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
 
-zip_compression_implementation _zip_get_compression_implementation(zip_int32_t method, int operation);
 zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t method, int operation);
 
+enum zip_compression_status {
+    ZIP_COMPRESSION_OK,
+    ZIP_COMPRESSION_END,
+    ZIP_COMPRESSION_ERROR,
+    ZIP_COMPRESSION_NEED_DATA
+};
+typedef enum zip_compression_status zip_compression_status_t;
+
+struct zip_compression_algorithm {
+    /* called once to create new context */
+    void *(*allocate)(zip_uint16_t method, int compression_flags, zip_error_t *error);
+    /* called once to free context */
+    void (*deallocate)(void *ctx);
+
+    /* get compression specific general purpose bitflags */
+    int (*compression_flags)(void *ctx);
 
+    /* start processing */
+    bool (*start)(void *ctx);
+    /* stop processing */
+    bool (*end)(void *ctx);
+
+    /* provide new input data, remains valid until next call to input or end */
+    bool (*input)(void *ctx, zip_uint8_t *data, zip_uint64_t length);
+
+    /* all input data has been provided */
+    void (*end_of_input)(void *ctx);
+
+    /* process input data, writing to data, which has room for length bytes, update length to number of bytes written */
+    zip_compression_status_t (*process)(void *ctx, zip_uint8_t *data, zip_uint64_t *length);
+};
+typedef struct zip_compression_algorithm zip_compression_algorithm_t;
+
+extern zip_compression_algorithm_t zip_algorithm_bzip2_compress;
+extern zip_compression_algorithm_t zip_algorithm_bzip2_decompress;
+extern zip_compression_algorithm_t zip_algorithm_deflate_compress;
+extern zip_compression_algorithm_t zip_algorithm_deflate_decompress;
+
+bool zip_compression_method_supported(zip_int32_t method, bool compress);
 
 /* This API is not final yet, but we need it internally, so it's private for now. */
 
@@ -113,8 +149,9 @@ const zip_uint8_t *zip_get_extra_field_by_id(zip_t *, int, int, zip_uint16_t, in
    Thus we will keep it private for now. */
 
 typedef zip_int64_t (*zip_source_layered_callback)(zip_source_t *, void *, void *, zip_uint64_t, enum zip_source_cmd);
+zip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t cm, int compression_flags);
 zip_source_t *zip_source_crc(zip_t *, zip_source_t *, int);
-zip_source_t *zip_source_deflate(zip_t *, zip_source_t *, zip_int32_t, int);
+zip_source_t *zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t cm);
 zip_source_t *zip_source_layered(zip_t *, zip_source_t *, zip_source_layered_callback, void *);
 zip_source_t *zip_source_layered_create(zip_source_t *src, zip_source_layered_callback cb, void *ud, zip_error_t *error);
 zip_source_t *zip_source_pkware(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
@@ -131,10 +168,10 @@ enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL };
 
 /* directory entry: general purpose bit flags */
 
-#define ZIP_GPBF_ENCRYPTED             0x0001  /* is encrypted */
-#define ZIP_GPBF_DATA_DESCRIPTOR       0x0008  /* crc/size after file data */
-#define ZIP_GPBF_STRONG_ENCRYPTION     0x0040  /* uses strong encryption */
-#define ZIP_GPBF_ENCODING_UTF_8                0x0800  /* file name encoding is UTF-8 */
+#define ZIP_GPBF_ENCRYPTED             0x0001u /* is encrypted */
+#define ZIP_GPBF_DATA_DESCRIPTOR       0x0008u /* crc/size after file data */
+#define ZIP_GPBF_STRONG_ENCRYPTION     0x0040u /* uses strong encryption */
+#define ZIP_GPBF_ENCODING_UTF_8                0x0800u /* file name encoding is UTF-8 */
 
 
 /* extra fields */
@@ -159,11 +196,8 @@ enum zip_encoding_type {
 
 typedef enum zip_encoding_type zip_encoding_type_t;
 
-#ifndef ZIP_HASH_TABLE_SIZE
-#define ZIP_HASH_TABLE_SIZE 8192
-#endif
-
 struct zip_hash;
+struct zip_progress;
 
 typedef struct zip_cdir zip_cdir_t;
 typedef struct zip_dirent zip_dirent_t;
@@ -172,6 +206,7 @@ typedef struct zip_extra_field zip_extra_field_t;
 typedef struct zip_string zip_string_t;
 typedef struct zip_buffer zip_buffer_t;
 typedef struct zip_hash zip_hash_t;
+typedef struct zip_progress zip_progress_t;
 
 /* zip archive, part of API */
 
@@ -199,7 +234,7 @@ struct zip {
 
     zip_hash_t *names;                 /* hash table for name lookup */
 
-    zip_progress_callback_t progress_callback; /* progress callback for zip_close() */
+    zip_progress_t *progress;            /* progress callback for zip_close() */
 };
 
 /* file in zip archive, part of API */
@@ -246,6 +281,7 @@ struct zip_dirent {
     zip_uint32_t ext_attrib;           /* (c)  external file attributes */
     zip_uint64_t offset;               /* (c)  offset of local header */
 
+    zip_uint16_t compression_level;    /*      level of compression to use (never valid in orig) */
     zip_uint16_t encryption_method;    /*      encryption method, computed from other fields */
     char *password;                     /*      file specific encryption password */
 };
@@ -407,6 +443,7 @@ void _zip_dirent_init(zip_dirent_t *);
 bool _zip_dirent_needs_zip64(const zip_dirent_t *, zip_flags_t);
 zip_dirent_t *_zip_dirent_new(void);
 zip_int64_t _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error);
+void _zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64);
 zip_int32_t _zip_dirent_size(zip_source_t *src, zip_uint16_t, zip_error_t *);
 int _zip_dirent_write(zip_t *za, zip_dirent_t *dirent, zip_flags_t flags);
 
@@ -447,11 +484,19 @@ bool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index
 bool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *key, zip_error_t *error);
 void _zip_hash_free(zip_hash_t *hash);
 zip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error);
-zip_hash_t *_zip_hash_new(zip_uint16_t hash_size, zip_error_t *error);
-void _zip_hash_revert(zip_hash_t *hash);
+zip_hash_t *_zip_hash_new(zip_error_t *error);
+bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error);
+bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error);
 
 zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);
 
+void _zip_progress_end(zip_progress_t *progress);
+void _zip_progress_free(zip_progress_t *progress);
+zip_progress_t *_zip_progress_new(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud);
+void _zip_progress_start(zip_progress_t *progress);
+void _zip_progress_subrange(zip_progress_t *progress, double start, double end);
+void _zip_progress_update(zip_progress_t *progress, double value);
+
 bool zip_random(zip_uint8_t *buffer, zip_uint16_t length);
 
 int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
@@ -466,11 +511,12 @@ void _zip_set_open_error(int *zep, const zip_error_t *err, int ze);
 zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command);
 bool _zip_source_eof(zip_source_t *);
 zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error);
-void _zip_source_invalidate(zip_source_t *src);
+zip_int8_t zip_source_get_compression_flags(zip_source_t *);
 bool _zip_source_had_error(zip_source_t *);
+void _zip_source_invalidate(zip_source_t *src);
 zip_source_t *_zip_source_new(zip_error_t *error);
 int _zip_source_set_source_archive(zip_source_t *, zip_t *);
-zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_error_t *error);
+zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error);
 zip_source_t *_zip_source_zip_new(zip_t *, zip_t *, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_uint64_t, const char *);
 
 int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error);
index 4ce79ab..3f28518 100644 (file)
@@ -29,7 +29,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd July 21, 2012
+.Dd April 25, 2017
 .Dt ZIP_NAME_LOCATE 3
 .Os
 .Sh NAME
@@ -60,8 +60,14 @@ the following values, or 0 for none of them.
 .It Dv ZIP_FL_NOCASE
 Ignore case distinctions.
 (Will only work well if the file names are ASCII.)
+With this flag,
+.Fn zip_name_locate
+will be slow for archives with many files.
 .It Dv ZIP_FL_NODIR
 Ignore directory part of file name in archive.
+With this flag,
+.Fn zip_name_locate
+will be slow for archives with many files.
 .It Dv ZIP_FL_ENC_RAW
 Compare against the unmodified names as it is in the ZIP archive.
 .It Dv ZIP_FL_ENC_GUESS
index 7924aeb..65e02eb 100644 (file)
@@ -1,5 +1,5 @@
 .\" zip_set_file_compression.mdoc -- set compression method and its flags
-.\" Copyright (C) 2012-2016 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner
 .\"
 .\" This file is part of libzip, a library to manipulate ZIP files.
 .\" The authors can be contacted at <libzip@nih.at>
@@ -29,7 +29,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd May 1, 2012
+.Dd April 6, 2017
 .Dt ZIP_SET_FILE_COMPRESSION 3
 .Os
 .Sh NAME
@@ -63,21 +63,26 @@ default compression; currently the same as
 .Dv ZIP_CM_DEFLATE .
 .It Dv ZIP_CM_STORE
 Store the file uncompressed.
+.It Dv ZIP_CM_BZIP2
+Compress the file using the
+.Xr bzip2 1
+algorithm.
 .It Dv ZIP_CM_DEFLATE
 Deflate the file with the
 .Xr zlib 3
 algorithm and default options
 .El
 .Pp
+.Em NOTE :
+Only the deflate and store methods can be assumed to be universally
+supported.
+.Pp
 The
 .Ar comp_flags
-argument is currently ignored.
-.\" For the comp_flags argument, the lower 4 bits define the compression
-.\" level.
-.\" 0 is fastest compression, 15 is highest compression
-.\" .Dv ZIP_COMP_FL_DEFAULT
-.\" can be used to specify that the default shall be used.
-.\" Further compression method specific flags will be added over time.
+argument defines the compression level, 1 being fastest compression
+and 9 highest.
+Allowed values are 1-9, other values are undefined.
+Further compression method specific flags might be added over time.
 .Pp
 The current compression method for a file in a zip archive can be
 determined using
index 40a8cc5..4408655 100644 (file)
@@ -29,7 +29,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd January 19, 2016
+.Dd April 25, 2017
 .Dt ZIPMERGE 1
 .Os
 .Sh NAME
@@ -53,10 +53,12 @@ Supported options:
 .Bl -tag -width MMM
 .It Fl D
 Ignore directory components in file name comparisons.
+This option is slow for archives with many files.
 .It Fl h
 Display a short help message and exit.
 .It Fl I
 Ignore case in file name comparisons
+This option is slow for archives with many files.
 .It Fl i
 Ask before overwriting files.
 See also
index 0a36cfd..3cd1a47 100644 (file)
@@ -7,27 +7,17 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/../src)
 ENDIF(NOT HAVE_GETOPT)
 
-SET(STANDALONE_TEST_PROGRAMS
+SET(TEST_PROGRAMS
   add_from_filep
   fopen_unchanged
   fseek
 )
 
-SET(HELPER_TEST_PROGRAMS
-#  tryopen
-)
-
 SET(GETOPT_USERS
   fread
   tryopen
 )
 
-SET(DISABLED_TESTS
-       encryption-nonrandom-aes128.test
-       encryption-nonrandom-aes192.test
-       encryption-nonrandom-aes256.test
-)
-
 SET(EXTRA_TESTS
        add_dir.test
        add_from_buffer.test
@@ -38,15 +28,21 @@ SET(EXTRA_TESTS
        add_from_stdin.test
        add_from_zip_closed.test
        add_from_zip_deflated.test
+       add_from_zip_deflated2.test
        add_from_zip_partial_deflated.test
        add_from_zip_partial_stored.test
        add_from_zip_stored.test
        add_stored.test
        add_stored_in_memory.test
+       cm-default.test
        count_entries.test
+       decrypt-correct-password-aes128.test
+       decrypt-correct-password-aes192.test
        decrypt-correct-password-aes256.test
        decrypt-correct-password-pkware.test
        decrypt-no-password-aes256.test
+       decrypt-wrong-password-aes128.test
+       decrypt-wrong-password-aes192.test
        decrypt-wrong-password-aes256.test
        decrypt-wrong-password-pkware.test
        delete_add_same.test
@@ -56,6 +52,10 @@ SET(EXTRA_TESTS
        delete_multiple_partial.test
        delete_renamed_rename.test
        encrypt.test
+# TODO: the tests need nonrandomopen.so, which is not hooked into the CMake build
+#      encryption-nonrandom-aes128.test
+#      encryption-nonrandom-aes192.test
+#      encryption-nonrandom-aes256.test
        encryption-remove.test
        extra_add.test
        extra_add_multiple.test
@@ -70,6 +70,7 @@ SET(EXTRA_TESTS
        extra_set.test
        extra_set_modify_c.test
        extra_set_modify_l.test
+       fdopen_ok.test
        file_comment_encmismatch.test
        fopen_unchanged.test
        fread.test
@@ -77,13 +78,21 @@ SET(EXTRA_TESTS
        fseek_fail.test
        fseek_ok.test
        get_comment.test
+       junk_at_end.test
+       junk_at_start.test
        name_locate.test
        open_cons_extrabytes.test
        open_empty.test
        open_empty_2.test
        open_extrabytes.test
+       open_file_count.test
+       open_filename_duplicate.test
+       open_filename_duplicate_consistency.test
+       open_filename_duplicate_empty.test
+       open_filename_duplicate_empty_consistency.test
        open_filename_empty.test
        open_incons.test
+       open_many_fail.test
        open_many_ok.test
        open_multidisk.test
        open_new_but_exists.test
@@ -107,8 +116,11 @@ SET(EXTRA_TESTS
        set_comment_localonly.test
        set_comment_removeglobal.test
        set_comment_revert.test
+       set_compression_bzip2_to_deflate.test
+       set_compression_deflate_to_bzip2.test
        set_compression_deflate_to_deflate.test
        set_compression_deflate_to_store.test
+       set_compression_store_to_bzip2.test
        set_compression_store_to_deflate.test
        set_compression_store_to_store.test
        set_compression_unknown.test
@@ -124,31 +136,52 @@ SET(EXTRA_TESTS
        stat_index_utf8_unmarked_strict.test
        stat_index_zip64.test
        utf-8-standardization.test
+       zip-in-archive-comment.test
        zip64_creation.test
        zip64_stored_creation.test
 )
 
 SET(ENV{srcdir} ${CMAKE_CURRENT_SOURCE_DIR})
-FOREACH(PROGRAM ${STANDALONE_TEST_PROGRAMS})
+FOREACH(PROGRAM ${TEST_PROGRAMS})
   ADD_EXECUTABLE(${PROGRAM} ${PROGRAM}.c)
   TARGET_LINK_LIBRARIES(${PROGRAM} zip)
-  ADD_TEST(${PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/runtest ${CMAKE_CURRENT_SOURCE_DIR}/${PROGRAM})
 ENDFOREACH(PROGRAM ${STANDALONE_TEST_PROGRAMS})
 
-FOREACH(PROGRAM ${HELPER_TEST_PROGRAMS})
-  ADD_EXECUTABLE(${PROGRAM} ${PROGRAM}.c)
-  TARGET_LINK_LIBRARIES(${PROGRAM} zip)
-ENDFOREACH(PROGRAM ${HELPER_TEST_PROGRAMS})
-
 FOREACH(PROGRAM ${GETOPT_USERS})
   ADD_EXECUTABLE(${PROGRAM} ${PROGRAM}.c ${SRC_EXTRA_FILES})
   TARGET_LINK_LIBRARIES(${PROGRAM} zip)
 ENDFOREACH(PROGRAM ${GETOPT_USERS})
 
-ADD_TEST(fread ${CMAKE_CURRENT_SOURCE_DIR}/runtest ${CMAKE_CURRENT_SOURCE_DIR}/fread)
+# for appveyor builds
+#SET(CMAKE_MSVCIDE_RUN_PATH C:/projects/libzip/vstudio/zlib/installed/bin;C:/projects/libzip/vstudio/zlib/installed/lib;C:/projects/libzip/build/lib/Release)
+
+ADD_CUSTOM_TARGET(
+  testinput
+  # ALL
+  VERBATIM
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 0 > manyfiles.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 1 > manyfiles-133000.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 2 > manyfiles-65536.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 3 > manyfiles-zip64-modulo.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 4 > manyfiles-zip64.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 5 > manyfiles-fewer.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip cat 6 > manyfiles-more.zip
+  COMMAND ziptool ${CMAKE_CURRENT_SOURCE_DIR}/bigzero-zip.zip cat 0 > bigzero.zip
+  DEPENDS ziptool ${CMAKE_CURRENT_SOURCE_DIR}/manyfiles-zip.zip ${CMAKE_CURRENT_SOURCE_DIR}/bigzero-zip.zip
+)
+SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+  bigzero.zip
+  manyfiles-133000.zip
+  manyfiles-65536.zip
+  manyfiles-fewer.zip
+  manyfiles-more.zip
+  manyfiles-zip64-modulo.zip
+  manyfiles-zip64.zip
+  manyfiles.zip
+)
 
 FOREACH(CASE ${EXTRA_TESTS})
-  ADD_TEST(${CASE} ${CMAKE_CURRENT_SOURCE_DIR}/runtest ${CMAKE_CURRENT_SOURCE_DIR}/${CASE})
+  ADD_TEST(${CASE} perl ${CMAKE_BINARY_DIR}/regress/runtest ${CMAKE_CURRENT_SOURCE_DIR}/${CASE})
 ENDFOREACH(CASE ${EXTRA_TESTS})
 
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib
index 19babed..5da3881 100644 (file)
@@ -118,6 +118,7 @@ EXTRA_DIST= \
        test-utf8.zip \
        test-utf8-unmarked.zip \
        testbuffer.zip \
+       testbzip2.zip \
        testdir.zip \
        testchanged.zip \
        testchangedlocal.zip \
@@ -183,6 +184,9 @@ TESTS= \
        delete_multiple_partial.test \
        delete_renamed_rename.test \
        encrypt.test \
+       encryption-nonrandom-aes128.test \
+       encryption-nonrandom-aes192.test \
+       encryption-nonrandom-aes256.test \
        encryption-remove.test \
        extra_add.test \
        extra_add_multiple.test \
@@ -197,6 +201,7 @@ TESTS= \
        extra_set.test \
        extra_set_modify_c.test \
        extra_set_modify_l.test \
+       fdopen_ok.test \
        file_comment_encmismatch.test \
        fopen_unchanged.test \
        fread.test \
@@ -242,8 +247,11 @@ TESTS= \
        set_comment_localonly.test \
        set_comment_removeglobal.test \
        set_comment_revert.test \
+       set_compression_bzip2_to_deflate.test \
+       set_compression_deflate_to_bzip2.test \
        set_compression_deflate_to_deflate.test \
        set_compression_deflate_to_store.test \
+       set_compression_store_to_bzip2.test \
        set_compression_store_to_deflate.test \
        set_compression_store_to_store.test \
        set_compression_unknown.test \
@@ -263,11 +271,6 @@ TESTS= \
        zip64_creation.test \
        zip64_stored_creation.test
 
-DISABLED_TESTS= \
-       encryption-nonrandom-aes128.test \
-       encryption-nonrandom-aes192.test \
-       encryption-nonrandom-aes256.test
-
 #XFAIL_TESTS=
 
 
@@ -312,7 +315,7 @@ manyfiles-zip64.zip: manyfiles-zip.zip
        ${top_builddir}/src/ziptool ${srcdir}/manyfiles-zip.zip cat 4 > ${builddir}/$@
 
 runtest: runtest.in
-       sed -e 's!@[s]rcdir@!${srcdir}!g' -e 's!@[a]bs_srcdir@!${abs_srcdir}!g' ${srcdir}/runtest.in > runtest
+       sed -e 's!@[s]rcdir@!${srcdir}!g' -e 's!@[a]bs_srcdir@!${abs_srcdir}!g' -e 's!@[t]op_builddir@!${top_builddir}!g' ${srcdir}/runtest.in > runtest
        chmod +x runtest
 
 cleanup:
index 6021fd6..5ab48bc 100644 (file)
@@ -8,10 +8,11 @@ use File::Copy;
 use File::Path qw(mkpath remove_tree);
 use Getopt::Long qw(:config posix_default bundling no_ignore_case);
 use IPC::Open3;
+use Storable qw(dclone);
 use Symbol 'gensym';
 use UNIVERSAL;
 
-use Data::Dumper qw(Dumper);
+#use Data::Dumper qw(Dumper);
 
 #  NiHTest -- package to run regression tests
 #  Copyright (C) 2002-2016 Dieter Baron and Thomas Klausner
@@ -77,6 +78,9 @@ use Data::Dumper qw(Dumper);
 #      mkdir MODE NAME
 #          create directory NAME with permissions MODE.
 #
+#      pipefile FILE
+#          pipe FILE to program's stdin.
+#
 #      pipein COMMAND ARGS ...
 #          pipe output of running COMMAND to program's stdin.
 #
@@ -133,15 +137,17 @@ my %EXIT_CODES = (
        ERROR => 99
     );
 
+# MARK: - Public API
+
 sub new {
        my $class = UNIVERSAL::isa ($_[0], __PACKAGE__) ? shift : __PACKAGE__;
        my $self = bless {}, $class;
-       
+
        my ($opts) = @_;
 
        $self->{default_program} = $opts->{default_program};
        $self->{zipcmp} = $opts->{zipcmp} // 'zipcmp';
-       $self->{zipcmp_flags} = $opts->{zipcmp_flags};
+       $self->{zipcmp_flags} = $opts->{zipcmp_flags} // '-p';
 
        $self->{directives} = {
                args => { type => 'string...', once => 1, required => 1 },
@@ -151,6 +157,7 @@ sub new {
                'file-del' => { type => 'string string' },
                'file-new' => { type => 'string string' },
                mkdir => { type => 'string string' },
+               pipefile => { type => 'string', once => 1 },
                pipein => { type => 'string', once => 1 },
                preload => { type => 'string', once => 1 },
                program => { type => 'string', once => 1 },
@@ -162,22 +169,16 @@ sub new {
                touch => { type => 'int string' },
                ulimit => { type => 'char string' }
        };
-       
+
        $self->{compare_by_type} = {};
        $self->{copy_by_type} = {};
        $self->{hooks} = {};
 
-       $self->add_comparator('zip/zip', \&comparator_zip);
-       
-       $self->{srcdir} = $opts->{srcdir} // $ENV{srcdir};
-       
-       if (!defined($self->{srcdir}) || $self->{srcdir} eq '') {
-               $self->{srcdir} = `sed -n 's/^srcdir = \(.*\)/\1/p' Makefile`;
-               chomp($self->{srcdir});
-       }
-       
+       $self->get_variable('srcdir', $opts);
+       $self->get_variable('top_builddir', $opts);
+
        $self->{in_sandbox} = 0;
-       
+
        $self->{verbose} = $ENV{VERBOSE};
        $self->{keep_broken} = $ENV{KEEP_BROKEN};
        $self->{no_cleanup} = $ENV{NO_CLEANUP};
@@ -189,7 +190,7 @@ sub new {
 
 sub add_comparator {
        my ($self, $ext, $sub) = @_;
-       
+
        return $self->add_file_proc('compare_by_type', $ext, $sub);
 }
 
@@ -203,15 +204,15 @@ sub add_copier {
 
 sub add_directive {
        my ($self, $name, $def) = @_;
-       
+
        if (exists($self->{directives}->{$name})) {
                $self->die("directive $name already defined");
        }
-       
+
        # TODO: validate $def
-       
+
        $self->{directives}->{$name} = $def;
-       
+
        return 1;
 }
 
@@ -228,7 +229,7 @@ sub add_file_proc {
 
 sub add_hook {
        my ($self, $hook, $sub) = @_;
-       
+
        $self->{hooks}->{$hook} = [] unless (defined($self->{hooks}->{$hook}));
        push @{$self->{hooks}->{$hook}}, $sub;
 
@@ -236,6 +237,25 @@ sub add_hook {
 }
 
 
+sub add_variant {
+       my ($self, $name, $hooks) = @_;
+
+       if (!defined($self->{variants})) {
+               $self->{variants} = [];
+               $self->add_directive('variants' => { type => 'string...', once => 1 });
+       }
+       for my $variant (@{$self->{variants}}) {
+               if ($variant->{name} eq $name) {
+                       $self->die("variant $name already defined");
+               }
+       }
+
+       push @{$self->{variants}}, { name => $name, hooks => $hooks };
+
+       return 1;
+}
+
+
 sub end {
        my ($self, @results) = @_;
 
@@ -261,6 +281,37 @@ sub run {
 
 
 sub runtest {
+       my ($self) = @_;
+
+       if (defined($self->{variants})) {
+               my @results = ();
+               $self->{original_test} = $self->{test};
+
+               my %variants;
+
+               if (defined($self->{test}->{variants})) {
+                       %variants = map { $_ => 1; } @{$self->{test}->{variants}};
+               }
+
+               for my $variant (@{$self->{variants}}) {
+                       next if (defined($self->{test}->{variants}) && !exists($variants{$variant->{name}}));
+
+                       $self->{variant_hooks} = $variant->{hooks};
+                       $self->{test} = dclone($self->{original_test});
+                       $self->{variant} = $variant->{name};
+                       $self->mangle_test_for_variant();
+                       push @results, $self->runtest_one($variant->{name});
+               }
+
+               return @results;
+       }
+       else {
+               return $self->runtest_one();
+       }
+}
+
+
+sub runtest_one {
        my ($self, $tag) = @_;
 
        $ENV{TZ} = "UTC";
@@ -268,7 +319,7 @@ sub runtest {
        $ENV{POSIXLY_CORRECT} = 1;
        $self->sandbox_create($tag);
        $self->sandbox_enter();
-       
+
        my $ok = 1;
        $ok &= $self->copy_files();
        $ok &= $self->run_hook('post_copy_files');
@@ -289,7 +340,6 @@ sub runtest {
                 $preload_env_var = 'DYLD_INSERT_LIBRARIES';
         }
        if (defined($self->{test}->{'preload'})) {
-                print "preloading: $preload_env_var = $self->{test}->{preload}\n";
                $ENV{$preload_env_var} = cwd() . "/../.libs/$self->{test}->{'preload'}";
        }
 
@@ -318,7 +368,7 @@ sub runtest {
        $self->run_hook('post_run_program');
 
        my @failed = ();
-       
+
        if ($self->{exit_status} != ($self->{test}->{return} // 0)) {
                push @failed, 'exit status';
                if ($self->{verbose}) {
@@ -326,7 +376,7 @@ sub runtest {
                        print "-" . ($self->{test}->{return} // 0) . "\n+$self->{exit_status}\n";
                }
        }
-       
+
        if (!$self->compare_arrays($self->{expected_stdout}, $self->{stdout}, 'output')) {
                push @failed, 'output';
        }
@@ -336,11 +386,11 @@ sub runtest {
        if (!$self->compare_files()) {
                push @failed, 'files';
        }
-       
+
        $self->{failed} = \@failed;
-       
+
        $self->run_hook('checks');
-       
+
        my $result = scalar(@{$self->{failed}}) == 0 ? 'PASS' : 'FAIL';
 
        $self->sandbox_leave();
@@ -361,7 +411,7 @@ sub setup {
        @ARGV = @argv;
        my $ok = GetOptions(
                'help|h' => \my $help,
-               'keep-broken' => \$self->{keep_broken},
+               'keep-broken|k' => \$self->{keep_broken},
                'no-cleanup' => \$self->{no_cleanup},
                # 'run-gdb' => \$self->{run_gdb},
                'setup-only' => \$self->{setup_only},
@@ -380,43 +430,68 @@ sub setup {
        $testcase .= '.test' unless ($testcase =~ m/\.test$/);
 
        my $testcase_file = $self->find_file($testcase);
-       
+
        $self->die("cannot find test case $testcase") unless ($testcase_file);
-       
+
        $testcase =~ s,^(?:.*/)?([^/]*)\.test$,$1,;
        $self->{testname} = $testcase;
 
        $self->die("error in test case definition") unless $self->parse_case($testcase_file);
-       
+
        $self->check_features_requirement() if ($self->{test}->{features});
 
        $self->end_test('SKIP') if ($self->{test}->{preload} && $^O eq 'darwin');
 }
 
 
-#
-# internal methods
-#
+# MARK: - Internal Methods
 
 sub add_file {
        my ($self, $file) = @_;
-       
+
        if (defined($self->{files}->{$file->{destination}})) {
                $self->warn("duplicate specification for input file $file->{destination}");
                return undef;
        }
-        
+
        $self->{files}->{$file->{destination}} = $file;
-       
+
        return 1;
 }
 
 
 sub check_features_requirement() {
        my ($self) = @_;
-       
-       ### TODO: implement
-       
+
+       my %features;
+
+       my $fh;
+       unless (open($fh, '<', "$self->{top_builddir}/config.h")) {
+               $self->die("cannot open config.h in top builddir $self->{top_builddir}");
+       }
+       while (my $line = <$fh>) {
+               if ($line =~ m/^#define HAVE_([A-Z0-9_a-z]*)/) {
+                       $features{$1} = 1;
+               }
+       }
+       close($fh);
+
+       my @missing = ();
+       for my $feature (@{$self->{test}->{features}}) {
+               if (!$features{$feature}) {
+                       push @missing, $feature;
+               }
+       }
+
+       if (scalar @missing > 0) {
+               my $reason = "missing features";
+               if (scalar(@missing) == 1) {
+                       $reason = "missing feature";
+               }
+               $self->print_test_result('SKIP', "$reason: " . (join ' ', @missing));
+               $self->end_test('SKIP');
+       }
+
        return 1;
 }
 
@@ -424,21 +499,21 @@ sub check_features_requirement() {
 sub comparator_zip {
        my ($self, $got, $expected) = @_;
 
-       my @args = ($self->{zipcmp}, $self->{verbose} ? '-pv' : '-pq');
+       my @args = ($self->{zipcmp}, $self->{verbose} ? '-v' : '-q');
        push @args, $self->{zipcmp_flags} if ($self->{zipcmp_flags});
        push @args, ($expected, $got);
-        
+
        my $ret = system(@args);
-       
+
        return $ret == 0;
 }
 
 
 sub compare_arrays() {
        my ($self, $a, $b, $tag) = @_;
-       
+
        my $ok = 1;
-       
+
        if (scalar(@$a) != scalar(@$b)) {
                $ok = 0;
        }
@@ -450,14 +525,14 @@ sub compare_arrays() {
                        }
                }
        }
-       
+
        if (!$ok && $self->{verbose}) {
                print "Unexpected $tag:\n";
                print "--- expected\n+++ got\n";
 
                diff_arrays($a, $b);
        }
-       
+
        return $ok;
 }
 
@@ -482,7 +557,7 @@ sub file_cmp($$) {
 
 sub compare_file($$$) {
        my ($self, $got, $expected) = @_;
-       
+
        my $real_expected = $self->find_file($expected);
        unless ($real_expected) {
                $self->warn("cannot find expected result file $expected");
@@ -505,22 +580,48 @@ sub compare_file($$$) {
        return $ok;
 }
 
+sub list_files {
+       my ($root) = @_;
+        my $ls;
+
+       my @files = ();
+       my @dirs = ($root);
+
+       while (scalar(@dirs) > 0) {
+               my $dir = shift @dirs;
+               
+               opendir($ls, $dir);
+               unless ($ls) {
+                       # TODO: handle error
+               }
+               while (my $entry = readdir($ls)) {
+                       my $file = "$dir/$entry";
+                       if ($dir eq '.') {
+                               $file = $entry;
+                       }
+                       
+                       if (-f $file) {
+                               push @files, "$file";
+                       }
+                       if (-d $file && $entry ne '.' && $entry ne '..') {
+                               push @dirs, "$file";
+                       }
+               }
+               closedir($ls);
+       }
+
+       return @files;
+}
 
 sub compare_files() {
        my ($self) = @_;
-       
+
        my $ok = 1;
-       
-       opendir(my $ls, '.');
-       unless ($ls) {
-               # TODO: handle error
-       }
-       my @files_got = grep { -f } readdir($ls);
-       closedir($ls);
 
-       @files_got = sort @files_got;
+
+       my @files_got = sort(list_files("."));
        my @files_should = ();
-       
+
         for my $file (sort keys %{$self->{files}}) {
                push @files_should, $file if ($self->{files}->{$file}->{result} || $self->{files}->{$file}->{ignore});
        }
@@ -531,25 +632,25 @@ sub compare_files() {
        unless ($self->run_hook('post_list_files')) {
                return 0;
        }
-       
+
        $ok = $self->compare_arrays($self->{files_should}, $self->{files_got}, 'files');
-       
+
        for my $file (@{$self->{files_got}}) {
                my $file_def = $self->{files}->{$file};
                next unless ($file_def && $file_def->{result});
-               
+
                $ok &= $self->compare_file($file, $file_def->{result});
        }
-       
+
        return $ok;
 }
 
 
 sub copy_files {
        my ($self) = @_;
-       
+
        my $ok = 1;
-       
+
        for my $filename (sort keys %{$self->{files}}) {
                my $file = $self->{files}->{$filename};
                next unless ($file->{source});
@@ -592,25 +693,25 @@ sub copy_files {
                        }
                }
        }
-       
+
        $self->die("failed to copy input files") unless ($ok);
 }
 
 
 sub die() {
        my ($self, $msg) = @_;
-       
+
        print STDERR "$0: $msg\n" if ($msg);
-       
+
        $self->end_test('ERROR');
 }
 
 
 sub end_test {
        my ($self, $status) = @_;
-       
+
        my $exit_code = $EXIT_CODES{$status} // $EXIT_CODES{ERROR};
-       
+
        $self->exit($exit_code);
 }
 
@@ -619,21 +720,21 @@ sub end_test {
 sub exit() {
        my ($self, $status) = @_;
        ### TODO: cleanup
-       
+
        exit($status);
 }
 
 
 sub find_file() {
        my ($self, $fname) = @_;
-       
+
        for my $dir (('', "$self->{srcdir}/")) {
                my $f = "$dir$fname";
                $f = "../$f" if ($self->{in_sandbox} && $dir !~ m,^/,);
-               
+
                return $f if (-f $f);
        }
-       
+
        return undef;
 }
 
@@ -653,6 +754,40 @@ sub get_extension {
 }
 
 
+sub get_variable {
+       my ($self, $name, $opts) = @_;
+
+       $self->{$name} = $opts->{$name} // $ENV{$name};
+       if (!defined($self->{$name}) || $self->{$name} eq '') {
+               my $fh;
+               unless (open($fh, '<', 'Makefile')) {
+                       $self->die("cannot open Makefile: $!");
+               }
+               while (my $line = <$fh>) {
+                       chomp $line;
+                       if ($line =~ m/^$name = (.*)/) {
+                               $self->{$name} = $1;
+                               last;
+                       }
+               }
+               close ($fh);
+       }
+       if (!defined($self->{$name} || $self->{$name} eq '')) {
+               $self->die("cannot get variable $name");
+       }
+}
+
+
+sub mangle_test_for_variant {
+       my ($self) = @_;
+
+       $self->{test}->{stdout} = $self->strip_tags($self->{variant}, $self->{test}->{stdout});
+       $self->{test}->{stderr} = $self->strip_tags($self->{variant}, $self->{test}->{stderr});
+       $self->run_hook('mangle_test');
+
+       return 1;
+}
+
 sub parse_args {
        my ($self, $type, $str) = @_;
 
@@ -705,16 +840,16 @@ sub parse_args {
                        $self->warn_file_line("expected $expected arguments, got " . (scalar(@strs)));
                        return undef;
                }
-               
+
                my $args = [];
-               
+
                my $n = scalar(@types);
                for (my $i=0; $i<scalar(@strs); $i++) {
                        my $val = $self->parse_args(($i >= $n ? $types[$n-1] : $types[$i]), $strs[$i]);
                        return undef unless (defined($val));
                        push @$args, $val;
                }
-               
+
                return $args;
        }
        else {
@@ -745,42 +880,42 @@ sub parse_args {
 
 sub parse_case() {
        my ($self, $fname) = @_;
-       
+
        my $ok = 1;
-       
+
        open TST, "< $fname" or $self->die("cannot open test case $fname: $!");
-       
+
        $self->{testcase_fname} = $fname;
-       
+
        my %test = ();
-       
+
        while (my $line = <TST>) {
                chomp $line;
-               
+
                next if ($line =~ m/^\#/);
-               
+
                unless ($line =~ m/(\S*)(?:\s(.*))?/) {
                        $self->warn_file_line("cannot parse line $line");
                        $ok = 0;
                        next;
                }
                my ($cmd, $argstring) = ($1, $2//"");
-               
+
                my $def = $self->{directives}->{$cmd};
-               
+
                unless ($def) {
                        $self->warn_file_line("unknown directive $cmd in test file");
                        $ok = 0;
                        next;
                }
-               
+
                my $args = $self->parse_args($def->{type}, $argstring);
-            
+
                unless (defined($args)) {
                        $ok = 0;
                        next;
                }
-               
+
                if ($def->{once}) {
                        if (defined($test{$cmd})) {
                                $self->warn_file_line("directive $cmd appeared twice in test file");
@@ -794,16 +929,39 @@ sub parse_case() {
        }
 
        close TST;
-       
+
        return undef unless ($ok);
-       
+
        for my $cmd (sort keys %test) {
                if ($self->{directives}->{$cmd}->{required} && !defined($test{$cmd})) {
                        $self->warn_file("required directive $cmd missing in test file");
                        $ok = 0;
                }
        }
-       
+
+       if ($test{pipefile} && $test{pipein}) {
+               $self->warn_file("both pipefile and pipein set, choose one");
+               $ok = 0;
+       }
+
+       if (defined($self->{variants})) {
+               if (defined($test{variants})) {
+                       for my $name (@{$test{variants}}) {
+                               my $found = 0;
+                               for my $variant (@{$self->{variants}}) {
+                                       if ($name eq $variant->{name}) {
+                                               $found = 1;
+                                               last;
+                                       }
+                               }
+                               if ($found == 0) {
+                                       $self->warn_file("unknown variant $name");
+                                       $ok = 0;
+                               }
+                       }
+               }
+       }
+
        return undef unless ($ok);
 
        if (defined($test{'stderr-replace'}) && defined($test{stderr})) {
@@ -817,7 +975,7 @@ sub parse_case() {
        $self->{test} = \%test;
 
        $self->run_hook('mangle_program');
-       
+
        if (!$self->parse_postprocess_files()) {
                return 0;
        }
@@ -828,23 +986,23 @@ sub parse_case() {
 
 sub parse_postprocess_files {
        my ($self) = @_;
-       
+
        $self->{files} = {};
-       
+
        my $ok = 1;
-       
+
        for my $file (@{$self->{test}->{file}}) {
                $ok = 0 unless ($self->add_file({ source => $file->[1], destination => $file->[0], result => $file->[2] }));
        }
-       
+
        for my $file (@{$self->{test}->{'file-del'}}) {
                $ok = 0 unless ($self->add_file({ source => $file->[1], destination => $file->[0], result => undef }));
        }
-       
+
        for my $file (@{$self->{test}->{'file-new'}}) {
                $ok = 0 unless ($self->add_file({ source => undef, destination => $file->[0], result => $file->[1] }));
        }
-       
+
        return $ok;
 }
 
@@ -881,6 +1039,14 @@ sub run_file_proc {
 
        my $ext = ($self->get_extension($got)) . '/' . ($self->get_extension($expected));
 
+       if ($self->{variant}) {
+               if (defined($self->{$proc}->{"$self->{variant}/$ext"})) {
+                       for my $sub (@{$self->{$proc}->{"$self->{variant}/$ext"}}) {
+                               my $ret = $sub->($self, $got, $expected);
+                               return $ret if (defined($ret));
+                       }
+               }
+       }
        if (defined($self->{$proc}->{$ext})) {
                for my $sub (@{$self->{$proc}->{$ext}}) {
                        my $ret = $sub->($self, $got, $expected);
@@ -894,18 +1060,25 @@ sub run_file_proc {
 
 sub run_hook {
        my ($self, $hook) = @_;
-       
+
        my $ok = 1;
-       
+
+       my @hooks = ();
+
+       if (defined($self->{variant_hooks}) && defined($self->{variant_hooks}->{$hook})) {
+               push @hooks, $self->{variant_hooks}->{$hook};
+       }
        if (defined($self->{hooks}->{$hook})) {
-               for my $sub (@{$self->{hooks}->{$hook}}) {
-                       unless ($sub->($self, $hook)) {
-                               $self->warn("hook $hook failed");
-                               $ok = 0;
-                       }
+               push @hooks, @{$self->{hooks}->{$hook}};
+       }
+
+       for my $sub (@hooks) {
+               unless ($sub->($self, $hook, $self->{variant})) {
+                       $self->warn("hook $hook failed");
+                       $ok = 0;
                }
        }
-       
+
        return $ok;
 }
 sub args_decode {
@@ -947,13 +1120,20 @@ sub run_program {
        my @cmd = ('../' . $self->{test}->{program}, map ({ args_decode($_, $self->{srcdir}); } @{$self->{test}->{args}}));
 
        ### TODO: catch errors?
-       
-       my $pid = open3($stdin, $stdout, $stderr, @cmd);
-       
+
+       my $pid;
+        if ($self->{test}->{pipefile}) {
+                open(SPLAT, '<', $self->{test}->{pipefile});
+               my $is_marked = eof SPLAT; # mark used
+               $pid = open3("<&SPLAT", $stdout, $stderr, @cmd);
+       }
+       else {
+               $pid = open3($stdin, $stdout, $stderr, @cmd);
+       }
        $self->{stdout} = [];
        $self->{stderr} = [];
-        
-        if ($self->{test}->{pipein}) {
+
+       if ($self->{test}->{pipein}) {
                 my $fh;
                 open($fh, "$self->{test}->{pipein} |");
                 if (!defined($fh)) {
@@ -965,7 +1145,7 @@ sub run_program {
                 close($fh);
                 close($stdin);
         }
-       
+
        while (my $line = <$stdout>) {
                if ($^O eq 'MSWin32') {
                        $line =~ s/[\r\n]+$//;
@@ -991,9 +1171,9 @@ sub run_program {
                }
                push @{$self->{stderr}}, $line;
        }
-       
+
        waitpid($pid, 0);
-       
+
        $self->{exit_status} = $? >> 8;
 }
 
@@ -1033,38 +1213,38 @@ sub pipein_win32() {
 
 sub sandbox_create {
        my ($self, $tag) = @_;
-       
+
        $tag = ($tag ? "-$tag" : "");
        $self->{sandbox_dir} = "sandbox-$self->{testname}$tag.d$$";
-       
+
        $self->die("sandbox $self->{sandbox_dir} already exists") if (-e $self->{sandbox_dir});
-       
+
        mkdir($self->{sandbox_dir}) or $self->die("cannot create sandbox $self->{sandbox_dir}: $!");
-       
+
        return 1;
 }
 
 
 sub sandbox_enter {
        my ($self) = @_;
-       
+
        $self->die("internal error: cannot enter sandbox before creating it") unless (defined($self->{sandbox_dir}));
 
        return if ($self->{in_sandbox});
 
-       chdir($self->{sandbox_dir}) or $self->die("cant cd into sandbox $self->{sandbox_dir}: $!");
-       
+       chdir($self->{sandbox_dir}) or $self->die("cannot cd into sandbox $self->{sandbox_dir}: $!");
+
        $self->{in_sandbox} = 1;
 }
 
 
 sub sandbox_leave {
        my ($self) = @_;
-       
+
        return if (!$self->{in_sandbox});
-       
+
        chdir('..') or $self->die("cannot leave sandbox: $!");
-       
+
        $self->{in_sandbox} = 0;
 }
 
@@ -1079,15 +1259,35 @@ sub sandbox_remove {
 }
 
 
+sub strip_tags {
+       my ($self, $tag, $lines) = @_;
+
+       my @stripped = ();
+
+       for my $line (@$lines) {
+               if ($line =~ m/^<([a-zA-Z0-9_]*)> (.*)/) {
+                       if ($1 eq $tag) {
+                               push @stripped, $2;
+                       }
+               }
+               else {
+                       push @stripped, $line;
+               }
+       }
+
+       return \@stripped;
+}
+
+
 sub touch_files {
        my ($self) = @_;
-       
+
        my $ok = 1;
-       
+
        if (defined($self->{test}->{touch})) {
                for my $args (@{$self->{test}->{touch}}) {
                        my ($mtime, $fname) = @$args;
-                       
+
                        if (!-f $fname) {
                                my $fh;
                                unless (open($fh, "> $fname") and close($fh)) {
@@ -1102,28 +1302,28 @@ sub touch_files {
                        }
                }
        }
-       
+
        return $ok;
 }
 
 
 sub warn {
        my ($self, $msg) = @_;
-       
+
        print STDERR "$0: $msg\n";
 }
 
 
 sub warn_file {
        my ($self, $msg) = @_;
-       
+
        $self->warn("$self->{testcase_fname}: $msg");
 }
 
 
 sub warn_file_line {
        my ($self, $msg) = @_;
-       
+
        $self->warn("$self->{testcase_fname}:$.: $msg");
 }
 
@@ -1197,7 +1397,7 @@ sub find_best_offsets {
        if (!defined($best_a)) {
                return (scalar(@$a) - $i, scalar(@$b) - $j);
        }
-       
+
        return ($best_a, $best_b);
 }
 
index 6951028..359a943 100644 (file)
Binary files a/regress/bigstored.zh and b/regress/bigstored.zh differ
index e545722..c588fc9 100644 (file)
Binary files a/regress/encrypt-aes128-noentropy.zip and b/regress/encrypt-aes128-noentropy.zip differ
index 2600691..59605a0 100644 (file)
Binary files a/regress/encrypt-aes192-noentropy.zip and b/regress/encrypt-aes192-noentropy.zip differ
index 0a3627a..742ada6 100644 (file)
Binary files a/regress/encrypt-aes256-noentropy.zip and b/regress/encrypt-aes256-noentropy.zip differ
index 3238aa6..0a2f770 100644 (file)
Binary files a/regress/encrypt-none.zip and b/regress/encrypt-none.zip differ
diff --git a/regress/fdopen_ok.test b/regress/fdopen_ok.test
new file mode 100644 (file)
index 0000000..192419c
--- /dev/null
@@ -0,0 +1,15 @@
+# zip_fdopen: stdin opens fine
+program ../src/ziptool
+args /dev/stdin stat 0
+pipefile test.zip
+return 0
+file test.zip test.zip test.zip
+stdout name: 'test'
+stdout index: '0'
+stdout size: '5'
+stdout compressed size: '5'
+stdout mtime: 'Mon Oct 06 2003 15:46:42'
+stdout crc: '3bb935c6'
+stdout compression method: '0'
+stdout encryption method: '0'
+stdout 
\ No newline at end of file
index d833bbf..4f74222 100644 (file)
@@ -52,7 +52,6 @@ static int (*real_open)(const char *path, int mode, ...) = NULL;
 static void
 init(void)
 {
-    char *foo;
     real_open = dlsym(RTLD_NEXT, "open");
     if (!real_open)
        abort();
index c845388..221648a 100644 (file)
@@ -38,6 +38,23 @@ BEGIN { push @INC, '@abs_srcdir@'; }
 
 use NiHTest;
 
-my $test = NiHTest::new({ default_program => '../src/ziptool', srcdir => '@srcdir@', zipcmp => '../../src/zipcmp', zipcmp_flags => '-p' });
+my $test = NiHTest::new({ default_program => '../src/ziptool', srcdir => '@srcdir@', top_builddir => '@top_builddir@', zipcmp => '../../src/zipcmp', zipcmp_flags => '-p' });
+
+sub mangle_test {
+       my ($test, $variant) = @_;
+
+       if (defined($test->{test}->{preload})) {
+               if (!defined($test->{test}->{features})) {
+                       $test->{test}->{features} = [];
+               }
+               push @{$test->{test}->{features}}, 'SHARED';
+       }
+
+       return 1;
+}
+
+
+$test->add_comparator('zip/zip', \&NiHTest::comparator_zip);
+$test->add_hook('post_parse', \&mangle_test);
 
 $test->run(@ARGV);
diff --git a/regress/set_compression_bzip2_to_deflate.test b/regress/set_compression_bzip2_to_deflate.test
new file mode 100644 (file)
index 0000000..bdfacb5
--- /dev/null
@@ -0,0 +1,5 @@
+# change method from bzip2 to deflated
+features LIBBZ2
+return 0
+args test.zip  set_file_compression 0 deflate 0
+file test.zip testbzip2.zip testdeflated.zip
diff --git a/regress/set_compression_deflate_to_bzip2.test b/regress/set_compression_deflate_to_bzip2.test
new file mode 100644 (file)
index 0000000..197b435
--- /dev/null
@@ -0,0 +1,5 @@
+# change method from deflated to bzip2
+features LIBBZ2
+return 0
+args test.zip  set_file_compression 0 bzip2 0
+file test.zip testdeflated.zip testbzip2.zip
diff --git a/regress/set_compression_store_to_bzip2.test b/regress/set_compression_store_to_bzip2.test
new file mode 100644 (file)
index 0000000..28bddd7
--- /dev/null
@@ -0,0 +1,5 @@
+# change method from stored to bzip2
+features LIBBZ2
+return 0
+args test.zip  set_file_compression 0 bzip2 0
+file test.zip teststored.zip testbzip2.zip
diff --git a/regress/testbzip2.zip b/regress/testbzip2.zip
new file mode 100644 (file)
index 0000000..7c9a9e7
Binary files /dev/null and b/regress/testbzip2.zip differ
index b41eea8..8a2b9a6 100644 (file)
@@ -44,8 +44,8 @@
 #include "getopt.h"
 #endif
 
-#include "zip.h"
 #include "compat.h"
+#include "zip.h"
 
 const char *usage = "usage: %s [-cent] file\n\n"
     "\t-c\tcheck consistency\n"
index 375489e..2507a76 100644 (file)
Binary files a/regress/utf-8-standardization-output.zip and b/regress/utf-8-standardization-output.zip differ
index 6e259a4..35d4808 100644 (file)
@@ -1,4 +1,4 @@
 # replace file contents and make UTF-8 name
 return 0
-args testfile replace_file_contents 0 "Some new content for the file." set_file_mtime 0 1406885162
-file testfile utf-8-standardization-input.zip utf-8-standardization-output.zip
+args testfile.zzip replace_file_contents 0 "Some new content for the file." set_file_mtime 0 1406885162
+file testfile.zzip utf-8-standardization-input.zip utf-8-standardization-output.zip
index aac1eea..48c4ed4 100644 (file)
@@ -54,8 +54,8 @@
 #include "getopt.h"
 #endif
 
-#include "zip.h"
 #include "compat.h"
+#include "zip.h"
 
 struct archive {
     const char *name;
@@ -314,6 +314,7 @@ list_directory(const char *name, struct archive *a)
     FTS *fts;
     FTSENT *ent;
     zip_uint64_t nalloc;
+    size_t prefix_length;
 
     char * const names[2] = { (char *)name, NULL };
 
@@ -322,7 +323,7 @@ list_directory(const char *name, struct archive *a)
        fprintf(stderr, "%s: can't open directory '%s': %s\n", prg, name, strerror(errno));
        return -1;
     }
-    size_t prefix_length = strlen(name)+1;
+    prefix_length = strlen(name)+1;
 
     nalloc = 0;
 
index d3f1aaf..1d3be4c 100644 (file)
@@ -48,8 +48,8 @@
 #include "getopt.h"
 #endif
 
-#include "zip.h"
 #include "compat.h"
+#include "zip.h"
 
 char *prg;
 
index 2994cb2..1a8e5c3 100644 (file)
@@ -50,8 +50,8 @@
 #endif
 extern int optopt;
 
-#include "zip.h"
 #include "compat.h"
+#include "zip.h"
 
 zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
 
@@ -402,13 +402,13 @@ name_locate(int argc, char *argv[]) {
 }
 
 static void
-progress_callback(double percentage) {
+progress_callback(zip_t *za, double percentage, void *ud) {
     printf("%.1lf%% done\n", percentage*100);
 }
 
 static int
 print_progress(int argc, char *argv[]) {
-    zip_register_progress_callback(za, progress_callback);
+    zip_register_progress_callback_with_state(za, 0.001, progress_callback, NULL, NULL);
     return 0;
 }
 
@@ -649,6 +649,10 @@ get_compression_method(const char *arg)
         return ZIP_CM_STORE;
     else if (strcmp(arg, "deflate") == 0)
         return ZIP_CM_DEFLATE;
+#if defined(HAVE_LIBBZ2)
+    else if (strcmp(arg, "bzip2") == 0)
+        return ZIP_CM_BZIP2;
+#endif
     else if (strcmp(arg, "unknown") == 0)
         return 100;
     return 0; /* TODO: error handling */
@@ -695,7 +699,13 @@ read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t
     int err;
 
     if (offset == 0 && length == 0) {
-       if ((zaa = zip_open(archive, flags, &err)) == NULL) {
+       if (strcmp(archive, "/dev/stdin") == 0) {
+           zaa = zip_fdopen(STDIN_FILENO, flags & ~ZIP_CREATE, &err);
+       }
+       else {
+           zaa = zip_open(archive, flags, &err);
+       }
+       if (zaa == NULL) {
            zip_error_set(error, err, errno);
            return NULL;
        }
@@ -722,6 +732,11 @@ read_hole(const char *archive, int flags, zip_error_t *error)
     zip_source_t *src = NULL;
     zip_t *zs = NULL;
 
+    if (strcmp(archive, "/dev/stdin") == 0) {
+       zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
+       return NULL;
+    }
+
     if ((src = source_hole_create(archive, flags, error)) == NULL
         || (zs = zip_open_from_source(src, flags, error)) == NULL) {
         zip_source_free(src);
@@ -738,6 +753,11 @@ read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t
     zip_source_t *src;
     zip_t *zb;
 
+    if (strcmp(archive, "/dev/stdin") == 0) {
+       zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
+       return NULL;
+    }
+
     if (stat(archive, &st) < 0) {
        if (errno == ENOENT) {
            src = zip_source_buffer_create(NULL, 0, 0, error);
@@ -1023,6 +1043,9 @@ usage(const char *progname, const char *reason)
            "\tu\tZIP_FL_UNCHANGED\n");
     fprintf(out, "\nSupported compression methods are:\n"
            "\tdefault\n"
+#if defined(HAVE_LIBBZ2)
+           "\tbzip2\n"
+#endif
            "\tdeflate\n"
            "\tstore\n");
     fprintf(out, "\nSupported compression methods are:\n"
index 8baf094..9b7d8bd 100644 (file)
@@ -29,6 +29,18 @@ if "%1"=="clean" (
        if errorlevel 1 goto exit_failure
        if exist ..\regress\manyfiles.zip del ..\regress\manyfiles.zip
        if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-133000.zip del ..\regress\manyfiles-133000.zip
+       if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-65536.zip del ..\regress\manyfiles-65536.zip
+       if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-zip64-modulo.zip del ..\regress\manyfiles-zip64-modulo.zip
+       if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-zip64.zip del ..\regress\manyfiles-zip64.zip
+       if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-fewer.zip del ..\regress\manyfiles-fewer.zip
+       if errorlevel 1 goto exit_failure
+       if exist ..\regress\manyfiles-more.zip del ..\regress\manyfiles-more.zip
+       if errorlevel 1 goto exit_failure
        echo Done
        exit /b 0
 ) else if "%1"=="build" (
@@ -76,31 +88,6 @@ if errorlevel 1 popd & goto exit_failure
 popd
 
 rem ---------------------------------------------------------------------------
-rem regress/CMakeLists.txt thinks the Perl script to run a test is called
-rem runtest, but on Windows we have to explicitly start the Perl interpreter
-rem because cmd.exe doesn't do "shebang".
-rem Fix this up before configuring libzip.
-rem ---------------------------------------------------------------------------
-if "%LIBZIP_RUN_TESTS%"=="true" (
-       echo Fixing up runtest script for Windows
-       pushd ..\regress
-       rem Get the full path to the Perl interpreter, with backslashes replaced by
-       rem forward slashes.
-       for /f "usebackq tokens=*" %%a in (`where perl.exe`) do set PERL_PATH=%%a
-       set PERL_PATH=!PERL_PATH:\=/!
-       echo Path to Perl interpreter is !PERL_PATH!
-
-       rem Fix up the CMakeLists.txt file.
-       perl -p -e "s|\$\{CMAKE_CURRENT_SOURCE_DIR\}/runtest|!PERL_PATH! \$\{CMAKE_CURRENT_BINARY_DIR\}/runtest|;" CMakeLists.txt > CMakeLists.fixed.txt
-       if errorlevel 1 popd & goto exit_failure
-       rename CMakeLists.txt CMakeLists.orig.txt
-       if errorlevel 1 popd & goto exit_failure
-       rename CMakeLists.fixed.txt CMakeLists.txt
-       if errorlevel 1 popd & goto exit_failure
-       popd
-)
-
-rem ---------------------------------------------------------------------------
 rem Prepare the build directory and run CMake to configure the project.
 rem ---------------------------------------------------------------------------
 pushd ..
@@ -113,7 +100,7 @@ cd build
 if errorlevel 1 popd & goto exit_failure
 cmake .. -G %CMAKE_GENERATOR% -T %CMAKE_TOOLSET% -DCMAKE_PREFIX_PATH="%ZLIB_INSTALL_PATH%"
 if errorlevel 1 popd & goto exit_failure
-call :revert_cmakelists
+goto :EOF
 
 rem ---------------------------------------------------------------------------
 rem Build libzip.
@@ -149,11 +136,25 @@ if "%LIBZIP_RUN_TESTS%"=="true" (
        if errorlevel 1 popd & goto exit_failure
        copy Release\*.exe .
        if errorlevel 1 popd & goto exit_failure
+       copy ..\src\Release\*.exe .
+       if errorlevel 1 popd & goto exit_failure
        echo Extracting test files
        if not exist ..\..\regress\bigzero.zip ziptool ..\..\regress\bigzero-zip.zip cat 0 > ..\..\regress\bigzero.zip
        if errorlevel 1 popd & goto exit_failure
        if not exist ..\..\regress\manyfiles.zip ziptool ..\..\regress\manyfiles-zip.zip cat 0 > ..\..\regress\manyfiles.zip
        if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-133000.zip ziptool ..\..\regress\manyfiles-zip.zip cat 1 > ..\..\regress\manyfiles-133000.zip
+       if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-65536.zip ziptool ..\..\regress\manyfiles-zip.zip cat 2 > ..\..\regress\manyfiles-65536.zip
+       if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-zip64-modulo.zip ziptool ..\..\regress\manyfiles-zip.zip cat 3 > ..\..\regress\manyfiles-zip64-modulo.zip
+       if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-zip64.zip ziptool ..\..\regress\manyfiles-zip.zip cat 4 > ..\..\regress\manyfiles-zip64.zip
+       if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-fewer.zip ziptool ..\..\regress\manyfiles-zip.zip cat 5 > ..\..\regress\manyfiles-fewer.zip
+       if errorlevel 1 popd & goto exit_failure
+       if not exist ..\..\regress\manyfiles-more.zip ziptool ..\..\regress\manyfiles-zip.zip cat 6 > ..\..\regress\manyfiles-more.zip
+       if errorlevel 1 popd & goto exit_failure
        echo Generating runtest script
        for /f %%p in ("..\..\regress") do set ABS_SRCDIR=%%~fp
        set ABS_SRCDIR=!ABS_SRCDIR:\=\\!
@@ -161,8 +162,8 @@ if "%LIBZIP_RUN_TESTS%"=="true" (
        if errorlevel 1 popd & goto exit_failure
        echo Running tests
        ctest
-       if errorlevel 1 popd & goto exit_failure
        popd
+       if errorlevel 1 goto exit_failure
 )
 
 goto :EOF
@@ -180,14 +181,6 @@ if errorlevel 1 (
 )
 goto :EOF
 
-:revert_cmakelists
-if exist ..\regress\CMakeLists.orig.txt (
-       del ..\regress\CMakeLists.txt
-       rename ..\regress\CMakeLists.orig.txt CMakeLists.txt
-)
-goto :EOF
-
 :exit_failure
-call :revert_cmakelists
 echo Build failed.
 exit /b 1
index cf2c0db..3ea9d5a 100644 (file)
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.2.0"
+#define PACKAGE_VERSION "1.3.0"
 
 /* The size of `int', as computed by sizeof. */
 #define SIZEOF_INT 4
 /* #undef TM_IN_SYS_TIME */
 
 /* Version number of package */
-#define VERSION "1.2.0"
+#define VERSION "1.3.0"
 
 /* Enable large inode numbers on Mac OS X 10.5.  */
 #ifndef _DARWIN_USE_64_BIT_INODE
index 597e8fe..e407e7f 100644 (file)
                4B01D6C815B2F46B002D5007 /* zip_fread.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721315B1B25E00236D3C /* zip_fread.c */; };
                4B01D6C915B2F46B002D5007 /* zip_get_archive_comment.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721415B1B25E00236D3C /* zip_get_archive_comment.c */; };
                4B01D6CA15B2F46B002D5007 /* zip_get_archive_flag.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721515B1B25E00236D3C /* zip_get_archive_flag.c */; };
-               4B01D6CB15B2F46B002D5007 /* zip_get_compression_implementation.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721615B1B25E00236D3C /* zip_get_compression_implementation.c */; };
                4B01D6CC15B2F46B002D5007 /* zip_get_encryption_implementation.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721715B1B25E00236D3C /* zip_get_encryption_implementation.c */; };
                4B01D6CD15B2F46B002D5007 /* zip_get_file_comment.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721815B1B25E00236D3C /* zip_get_file_comment.c */; };
                4B01D6CE15B2F46B002D5007 /* zip_get_name.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721915B1B25E00236D3C /* zip_get_name.c */; };
                4B01D6DD15B2F46B002D5007 /* zip_source_buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722815B1B25E00236D3C /* zip_source_buffer.c */; };
                4B01D6DE15B2F46B002D5007 /* zip_source_close.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722915B1B25E00236D3C /* zip_source_close.c */; };
                4B01D6DF15B2F46B002D5007 /* zip_source_crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722A15B1B25E00236D3C /* zip_source_crc.c */; };
-               4B01D6E015B2F46B002D5007 /* zip_source_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722B15B1B25E00236D3C /* zip_source_deflate.c */; };
                4B01D6E115B2F46B002D5007 /* zip_source_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722C15B1B25E00236D3C /* zip_source_error.c */; };
                4B01D6E215B2F46B002D5007 /* zip_source_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722D15B1B25E00236D3C /* zip_source_file.c */; };
                4B01D6E315B2F46B002D5007 /* zip_source_filep.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722E15B1B25E00236D3C /* zip_source_filep.c */; };
                4B01D73215B2F5EE002D5007 /* zipconf.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDC729E15B1B4E900236D3C /* zipconf.h */; settings = {ATTRIBUTES = (Public, ); }; };
                4B01D73415B2F5F4002D5007 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDC72A015B1B56400236D3C /* config.h */; };
                4B01D73C15B2F6AF002D5007 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
+               4B0454B81E8E3E02002FA1F9 /* zip_source_get_compression_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */; };
+               4B0454B91E8E3E03002FA1F9 /* zip_source_get_compression_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */; };
+               4B0454BA1E8E3E08002FA1F9 /* zip_source_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */; };
+               4B0454BB1E8E3E09002FA1F9 /* zip_source_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */; };
+               4B0454BC1E8E3E24002FA1F9 /* zip_algorithm_bzip2.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */; };
+               4B0454BD1E8E3E24002FA1F9 /* zip_algorithm_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */; };
+               4B0454BE1E8E3E25002FA1F9 /* zip_algorithm_bzip2.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */; };
+               4B0454BF1E8E3E25002FA1F9 /* zip_algorithm_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */; };
                4B3A5F501DF96EA8005A53A1 /* gladman-fcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4B1DF96D83005A53A1 /* gladman-fcrypt.c */; };
                4B3A5F511DF96EA9005A53A1 /* gladman-fcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4B1DF96D83005A53A1 /* gladman-fcrypt.c */; };
                4B3A5F521DF96EB4005A53A1 /* zip_fseek.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4D1DF96D83005A53A1 /* zip_fseek.c */; };
                4BD6CB6619E71CD100710654 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
                4BD6CB6719E71CD100710654 /* libzip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D68B15B2F3F1002D5007 /* libzip.framework */; };
                4BD6CB6F19E71D6900710654 /* hole.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD6CB5E19E71B3B00710654 /* hole.c */; };
+               4BD708791EB1CF73003F351F /* zip_progress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD708781EB1CF73003F351F /* zip_progress.c */; };
+               4BD7087A1EB1CF73003F351F /* zip_progress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD708781EB1CF73003F351F /* zip_progress.c */; };
                4BDC724415B1B25E00236D3C /* zip_add_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC71F115B1B25E00236D3C /* zip_add_dir.c */; };
                4BDC724515B1B25E00236D3C /* zip_add_entry.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC71F215B1B25E00236D3C /* zip_add_entry.c */; };
                4BDC724615B1B25E00236D3C /* zip_add.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC71F315B1B25E00236D3C /* zip_add.c */; };
                4BDC726615B1B25E00236D3C /* zip_fread.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721315B1B25E00236D3C /* zip_fread.c */; };
                4BDC726715B1B25E00236D3C /* zip_get_archive_comment.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721415B1B25E00236D3C /* zip_get_archive_comment.c */; };
                4BDC726815B1B25E00236D3C /* zip_get_archive_flag.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721515B1B25E00236D3C /* zip_get_archive_flag.c */; };
-               4BDC726915B1B25E00236D3C /* zip_get_compression_implementation.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721615B1B25E00236D3C /* zip_get_compression_implementation.c */; };
                4BDC726A15B1B25E00236D3C /* zip_get_encryption_implementation.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721715B1B25E00236D3C /* zip_get_encryption_implementation.c */; };
                4BDC726B15B1B25E00236D3C /* zip_get_file_comment.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721815B1B25E00236D3C /* zip_get_file_comment.c */; };
                4BDC726C15B1B25E00236D3C /* zip_get_name.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC721915B1B25E00236D3C /* zip_get_name.c */; };
                4BDC727B15B1B25E00236D3C /* zip_source_buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722815B1B25E00236D3C /* zip_source_buffer.c */; };
                4BDC727C15B1B25E00236D3C /* zip_source_close.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722915B1B25E00236D3C /* zip_source_close.c */; };
                4BDC727D15B1B25E00236D3C /* zip_source_crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722A15B1B25E00236D3C /* zip_source_crc.c */; };
-               4BDC727E15B1B25E00236D3C /* zip_source_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722B15B1B25E00236D3C /* zip_source_deflate.c */; };
                4BDC727F15B1B25E00236D3C /* zip_source_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722C15B1B25E00236D3C /* zip_source_error.c */; };
                4BDC728015B1B25E00236D3C /* zip_source_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722D15B1B25E00236D3C /* zip_source_file.c */; };
                4BDC728115B1B25E00236D3C /* zip_source_filep.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC722E15B1B25E00236D3C /* zip_source_filep.c */; };
                3D7E35401B33063600022624 /* in-memory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "in-memory.c"; sourceTree = "<group>"; };
                3D7E35421B33063600022624 /* windows-open.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "windows-open.c"; sourceTree = "<group>"; };
                3D7E35471B33076C00022624 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
-               3D9284801C309510001EABA7 /* zip_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_hash.c; sourceTree = "<group>"; };
+               3D9284801C309510001EABA7 /* zip_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_hash.c; sourceTree = "<group>"; usesTabs = 1; };
                4B01D68B15B2F3F1002D5007 /* libzip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libzip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                4B01D6FD15B2F4B1002D5007 /* zipmerge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zipmerge; sourceTree = BUILT_PRODUCTS_DIR; };
                4B01D70815B2F4CF002D5007 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
                4B01D72115B2F572002D5007 /* zipcmp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zipcmp.c; sourceTree = "<group>"; };
                4B01D72215B2F572002D5007 /* zipmerge.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zipmerge.c; sourceTree = "<group>"; };
                4B01D73D15B2FB6B002D5007 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
+               4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_algorithm_bzip2.c; sourceTree = "<group>"; };
+               4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_algorithm_deflate.c; sourceTree = "<group>"; };
+               4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_compress.c; sourceTree = "<group>"; };
+               4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_get_compression_flags.c; sourceTree = "<group>"; };
                4B1ABD1A1A2E5DA700C93867 /* links */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = links; sourceTree = "<group>"; };
                4B1ABD1B1A2E5E4D00C93867 /* handle_links */ = {isa = PBXFileReference; explicitFileType = text.script.perl; fileEncoding = 4; path = handle_links; sourceTree = "<group>"; };
                4B1E46E51A08CB7600A376D2 /* zip_error_code_system.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_error_code_system.mdoc; sourceTree = "<group>"; };
                4B28AA2115BACC3900D0C17D /* ziptorrent.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = ziptorrent.mdoc; sourceTree = "<group>"; };
                4B28AA2215BAD4E200D0C17D /* API-CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "API-CHANGES"; sourceTree = "<group>"; };
                4B28AA2315BAD4E200D0C17D /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS; sourceTree = "<group>"; };
-               4B28AA2415BAD4E200D0C17D /* NEWS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NEWS; sourceTree = "<group>"; };
-               4B28AA2515BAD4E200D0C17D /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+               4B28AA2415BAD4E200D0C17D /* NEWS.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = NEWS.md; sourceTree = "<group>"; };
+               4B28AA2515BAD4E200D0C17D /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
                4B28AA2615BAD4E200D0C17D /* THANKS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = THANKS; sourceTree = "<group>"; };
-               4B28AA2715BAD4E200D0C17D /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
+               4B28AA2715BAD4E200D0C17D /* TODO.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = TODO.md; sourceTree = "<group>"; };
                4B3A5F4A1DF96D83005A53A1 /* gladman-fcrypt */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "gladman-fcrypt"; sourceTree = "<group>"; };
                4B3A5F4B1DF96D83005A53A1 /* gladman-fcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "gladman-fcrypt.c"; sourceTree = "<group>"; };
                4B3A5F4C1DF96D83005A53A1 /* gladman-fcrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gladman-fcrypt.h"; sourceTree = "<group>"; };
                4BD6CB5C19E6A5D900710654 /* source_hole.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = source_hole.c; sourceTree = "<group>"; };
                4BD6CB5E19E71B3B00710654 /* hole.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hole.c; sourceTree = "<group>"; };
                4BD6CB6C19E71CD100710654 /* hole */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hole; sourceTree = BUILT_PRODUCTS_DIR; };
+               4BD708781EB1CF73003F351F /* zip_progress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_progress.c; sourceTree = "<group>"; };
                4BDC71E015B182B200236D3C /* libzip_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = libzip_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                4BDC71F115B1B25E00236D3C /* zip_add_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_add_dir.c; path = ../lib/zip_add_dir.c; sourceTree = "<group>"; };
                4BDC71F215B1B25E00236D3C /* zip_add_entry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_add_entry.c; path = ../lib/zip_add_entry.c; sourceTree = "<group>"; };
                4BDC721315B1B25E00236D3C /* zip_fread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_fread.c; path = ../lib/zip_fread.c; sourceTree = "<group>"; };
                4BDC721415B1B25E00236D3C /* zip_get_archive_comment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_archive_comment.c; path = ../lib/zip_get_archive_comment.c; sourceTree = "<group>"; };
                4BDC721515B1B25E00236D3C /* zip_get_archive_flag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_archive_flag.c; path = ../lib/zip_get_archive_flag.c; sourceTree = "<group>"; };
-               4BDC721615B1B25E00236D3C /* zip_get_compression_implementation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_compression_implementation.c; path = ../lib/zip_get_compression_implementation.c; sourceTree = "<group>"; };
                4BDC721715B1B25E00236D3C /* zip_get_encryption_implementation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_encryption_implementation.c; path = ../lib/zip_get_encryption_implementation.c; sourceTree = "<group>"; };
                4BDC721815B1B25E00236D3C /* zip_get_file_comment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_file_comment.c; path = ../lib/zip_get_file_comment.c; sourceTree = "<group>"; };
                4BDC721915B1B25E00236D3C /* zip_get_name.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_get_name.c; path = ../lib/zip_get_name.c; sourceTree = "<group>"; };
                4BDC721C15B1B25E00236D3C /* zip_memdup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_memdup.c; path = ../lib/zip_memdup.c; sourceTree = "<group>"; };
                4BDC721D15B1B25E00236D3C /* zip_name_locate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_name_locate.c; path = ../lib/zip_name_locate.c; sourceTree = "<group>"; };
                4BDC721E15B1B25E00236D3C /* zip_new.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_new.c; path = ../lib/zip_new.c; sourceTree = "<group>"; };
-               4BDC721F15B1B25E00236D3C /* zip_open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_open.c; path = ../lib/zip_open.c; sourceTree = "<group>"; };
+               4BDC721F15B1B25E00236D3C /* zip_open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_open.c; path = ../lib/zip_open.c; sourceTree = "<group>"; usesTabs = 1; };
                4BDC722015B1B25E00236D3C /* zip_rename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_rename.c; path = ../lib/zip_rename.c; sourceTree = "<group>"; };
                4BDC722115B1B25E00236D3C /* zip_replace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_replace.c; path = ../lib/zip_replace.c; sourceTree = "<group>"; };
                4BDC722215B1B25E00236D3C /* zip_set_archive_comment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_set_archive_comment.c; path = ../lib/zip_set_archive_comment.c; sourceTree = "<group>"; };
                4BDC722815B1B25E00236D3C /* zip_source_buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_buffer.c; path = ../lib/zip_source_buffer.c; sourceTree = "<group>"; };
                4BDC722915B1B25E00236D3C /* zip_source_close.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_close.c; path = ../lib/zip_source_close.c; sourceTree = "<group>"; };
                4BDC722A15B1B25E00236D3C /* zip_source_crc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_crc.c; path = ../lib/zip_source_crc.c; sourceTree = "<group>"; };
-               4BDC722B15B1B25E00236D3C /* zip_source_deflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_deflate.c; path = ../lib/zip_source_deflate.c; sourceTree = "<group>"; };
                4BDC722C15B1B25E00236D3C /* zip_source_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_error.c; path = ../lib/zip_source_error.c; sourceTree = "<group>"; };
                4BDC722D15B1B25E00236D3C /* zip_source_file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_file.c; path = ../lib/zip_source_file.c; sourceTree = "<group>"; };
                4BDC722E15B1B25E00236D3C /* zip_source_filep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip_source_filep.c; path = ../lib/zip_source_filep.c; sourceTree = "<group>"; };
                        children = (
                                4B28AA2215BAD4E200D0C17D /* API-CHANGES */,
                                4B28AA2315BAD4E200D0C17D /* AUTHORS */,
-                               4B28AA2415BAD4E200D0C17D /* NEWS */,
-                               4B28AA2515BAD4E200D0C17D /* README */,
+                               4B28AA2415BAD4E200D0C17D /* NEWS.md */,
+                               4B28AA2515BAD4E200D0C17D /* README.md */,
                                4B28AA2615BAD4E200D0C17D /* THANKS */,
-                               4B28AA2715BAD4E200D0C17D /* TODO */,
+                               4B28AA2715BAD4E200D0C17D /* TODO.md */,
                        );
                        name = info;
                        path = ..;
                                4BDC71F115B1B25E00236D3C /* zip_add_dir.c */,
                                4BDC71F215B1B25E00236D3C /* zip_add_entry.c */,
                                4BDC71F315B1B25E00236D3C /* zip_add.c */,
+                               4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */,
+                               4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */,
                                4BCB434119E9347E0067FAA3 /* zip_buffer.c */,
                                4BDC71F415B1B25E00236D3C /* zip_close.c */,
                                4BDC71F515B1B25E00236D3C /* zip_delete.c */,
                                4B3A5F4E1DF96D83005A53A1 /* zip_ftell.c */,
                                4BDC721415B1B25E00236D3C /* zip_get_archive_comment.c */,
                                4BDC721515B1B25E00236D3C /* zip_get_archive_flag.c */,
-                               4BDC721615B1B25E00236D3C /* zip_get_compression_implementation.c */,
                                4BDC721715B1B25E00236D3C /* zip_get_encryption_implementation.c */,
                                4BDC721815B1B25E00236D3C /* zip_get_file_comment.c */,
                                4BDC721915B1B25E00236D3C /* zip_get_name.c */,
                                4BDC721D15B1B25E00236D3C /* zip_name_locate.c */,
                                4BDC721E15B1B25E00236D3C /* zip_new.c */,
                                4BDC721F15B1B25E00236D3C /* zip_open.c */,
+                               4BD708781EB1CF73003F351F /* zip_progress.c */,
                                736ED9B81E3D688C00C36873 /* zip_random_unix.c */,
                                4BDC722015B1B25E00236D3C /* zip_rename.c */,
                                4BDC722115B1B25E00236D3C /* zip_replace.c */,
                                4BD5053219A0116D007DD28A /* zip_source_call.c */,
                                4BDC722915B1B25E00236D3C /* zip_source_close.c */,
                                4BCF301B199A2F820064207B /* zip_source_commit_write.c */,
+                               4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */,
                                4BDC722A15B1B25E00236D3C /* zip_source_crc.c */,
-                               4BDC722B15B1B25E00236D3C /* zip_source_deflate.c */,
                                4BDC722C15B1B25E00236D3C /* zip_source_error.c */,
                                4BDC722D15B1B25E00236D3C /* zip_source_file.c */,
                                4BDC722E15B1B25E00236D3C /* zip_source_filep.c */,
                                4BDC722F15B1B25E00236D3C /* zip_source_free.c */,
                                4BDC723015B1B25E00236D3C /* zip_source_function.c */,
+                               4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */,
                                4BE402AC19D94AE400298248 /* zip_source_is_deleted.c */,
                                4BDC723115B1B25E00236D3C /* zip_source_layered.c */,
                                4BDC723215B1B25E00236D3C /* zip_source_open.c */,
                                4BCF3039199ABDDA0064207B /* zip_source_tell_write.c in Sources */,
                                4B01D6A615B2F46B002D5007 /* zip_add_dir.c in Sources */,
                                4B972052188EBE85002FAFAD /* zip_file_set_external_attributes.c in Sources */,
+                               4B0454BA1E8E3E08002FA1F9 /* zip_source_compress.c in Sources */,
                                4BCF3024199A2F820064207B /* zip_source_begin_write.c in Sources */,
                                4B01D6A715B2F46B002D5007 /* zip_add_entry.c in Sources */,
                                4B01D6A815B2F46B002D5007 /* zip_add.c in Sources */,
                                4B01D6A915B2F46B002D5007 /* zip_close.c in Sources */,
                                4B01D6AA15B2F46B002D5007 /* zip_delete.c in Sources */,
                                4B01D6AB15B2F46B002D5007 /* zip_dir_add.c in Sources */,
+                               4BD7087A1EB1CF73003F351F /* zip_progress.c in Sources */,
                                4B01D6AC15B2F46B002D5007 /* zip_dirent.c in Sources */,
                                4B01D6AD15B2F46B002D5007 /* zip_discard.c in Sources */,
+                               4B0454B81E8E3E02002FA1F9 /* zip_source_get_compression_flags.c in Sources */,
                                4B01D6AE15B2F46B002D5007 /* zip_entry.c in Sources */,
                                4B01D6AF15B2F46B002D5007 /* zip_err_str.c in Sources */,
                                4B3A5F521DF96EB4005A53A1 /* zip_fseek.c in Sources */,
                                4B01D6BD15B2F46B002D5007 /* zip_file_get_comment.c in Sources */,
                                4B01D6BE15B2F46B002D5007 /* zip_file_get_offset.c in Sources */,
                                4B01D6BF15B2F46B002D5007 /* zip_file_rename.c in Sources */,
+                               4B0454BD1E8E3E24002FA1F9 /* zip_algorithm_deflate.c in Sources */,
                                4B01D6C015B2F46B002D5007 /* zip_file_replace.c in Sources */,
                                4B01D6C115B2F46B002D5007 /* zip_file_set_comment.c in Sources */,
                                4BCF3033199ABD3A0064207B /* zip_source_remove.c in Sources */,
                                736ED9BF1E3D6B7C00C36873 /* zip_file_set_encryption.c in Sources */,
                                4B01D6C915B2F46B002D5007 /* zip_get_archive_comment.c in Sources */,
                                4B01D6CA15B2F46B002D5007 /* zip_get_archive_flag.c in Sources */,
+                               4B0454BC1E8E3E24002FA1F9 /* zip_algorithm_bzip2.c in Sources */,
                                736ED9BC1E3D6B6F00C36873 /* zip_source_winzip_aes_encode.c in Sources */,
-                               4B01D6CB15B2F46B002D5007 /* zip_get_compression_implementation.c in Sources */,
                                4BD5053419A01BB0007DD28A /* zip_source_call.c in Sources */,
                                4BCF3030199A2F820064207B /* zip_source_write.c in Sources */,
                                4B01D6CC15B2F46B002D5007 /* zip_get_encryption_implementation.c in Sources */,
                                4BCB434319E9347E0067FAA3 /* zip_buffer.c in Sources */,
                                4B01D6DE15B2F46B002D5007 /* zip_source_close.c in Sources */,
                                4B01D6DF15B2F46B002D5007 /* zip_source_crc.c in Sources */,
-                               4B01D6E015B2F46B002D5007 /* zip_source_deflate.c in Sources */,
                                4B01D6E115B2F46B002D5007 /* zip_source_error.c in Sources */,
                                4B01D6E215B2F46B002D5007 /* zip_source_file.c in Sources */,
                                4B01D6E315B2F46B002D5007 /* zip_source_filep.c in Sources */,
                                4BCF3038199ABDDA0064207B /* zip_source_tell_write.c in Sources */,
                                4BDC724415B1B25E00236D3C /* zip_add_dir.c in Sources */,
                                4B972051188EBE85002FAFAD /* zip_file_set_external_attributes.c in Sources */,
+                               4B0454BB1E8E3E09002FA1F9 /* zip_source_compress.c in Sources */,
                                4BCF3023199A2F820064207B /* zip_source_begin_write.c in Sources */,
                                4BDC724515B1B25E00236D3C /* zip_add_entry.c in Sources */,
                                4BDC724615B1B25E00236D3C /* zip_add.c in Sources */,
                                736ED9C11E3D6B8300C36873 /* zip_source_winzip_aes_decode.c in Sources */,
                                4BDC724715B1B25E00236D3C /* zip_close.c in Sources */,
                                4BDC724815B1B25E00236D3C /* zip_delete.c in Sources */,
+                               4BD708791EB1CF73003F351F /* zip_progress.c in Sources */,
                                736ED9C21E3D6B8600C36873 /* zip_source_winzip_aes_encode.c in Sources */,
                                4BDC724915B1B25E00236D3C /* zip_dir_add.c in Sources */,
+                               4B0454B91E8E3E03002FA1F9 /* zip_source_get_compression_flags.c in Sources */,
                                4BDC724A15B1B25E00236D3C /* zip_dirent.c in Sources */,
                                4BDC724B15B1B25E00236D3C /* zip_discard.c in Sources */,
                                4BDC724C15B1B25E00236D3C /* zip_entry.c in Sources */,
                                4BDC725B15B1B25E00236D3C /* zip_file_get_comment.c in Sources */,
                                4BDC725C15B1B25E00236D3C /* zip_file_get_offset.c in Sources */,
                                4BDC725D15B1B25E00236D3C /* zip_file_rename.c in Sources */,
+                               4B0454BF1E8E3E25002FA1F9 /* zip_algorithm_deflate.c in Sources */,
                                4BDC725E15B1B25E00236D3C /* zip_file_replace.c in Sources */,
                                4BDC725F15B1B25E00236D3C /* zip_file_set_comment.c in Sources */,
                                4BCF3032199ABD3A0064207B /* zip_source_remove.c in Sources */,
                                4BDC726615B1B25E00236D3C /* zip_fread.c in Sources */,
                                4BDC726715B1B25E00236D3C /* zip_get_archive_comment.c in Sources */,
                                4BDC726815B1B25E00236D3C /* zip_get_archive_flag.c in Sources */,
-                               4BDC726915B1B25E00236D3C /* zip_get_compression_implementation.c in Sources */,
                                736ED9C01E3D6B8000C36873 /* zip_random_unix.c in Sources */,
+                               4B0454BE1E8E3E25002FA1F9 /* zip_algorithm_bzip2.c in Sources */,
                                4BD5053319A0116D007DD28A /* zip_source_call.c in Sources */,
                                4BCF302F199A2F820064207B /* zip_source_write.c in Sources */,
                                4BDC726A15B1B25E00236D3C /* zip_get_encryption_implementation.c in Sources */,
                                4BCB434219E9347E0067FAA3 /* zip_buffer.c in Sources */,
                                4BDC727C15B1B25E00236D3C /* zip_source_close.c in Sources */,
                                4BDC727D15B1B25E00236D3C /* zip_source_crc.c in Sources */,
-                               4BDC727E15B1B25E00236D3C /* zip_source_deflate.c in Sources */,
                                4BDC727F15B1B25E00236D3C /* zip_source_error.c in Sources */,
                                4BDC728015B1B25E00236D3C /* zip_source_file.c in Sources */,
                                4BDC728115B1B25E00236D3C /* zip_source_filep.c in Sources */,