Merge 0.10.1 into head.
Bump head version to 0.10b to diffentiate bugfixed version.
diff --git a/.hgignore b/.hgignore
index d9a7c49..5d80ffb 100644
--- a/.hgignore
+++ b/.hgignore
@@ -22,15 +22,21 @@
 ^regress/add_from_file$
 ^regress/add_from_filep$
 ^regress/add_from_zip$
+^regress/cp437$
+^regress/encoding$
 ^regress/encrypt$
+^regress/fopen_unchanged$
 ^regress/fread$
 ^regress/get_comment$
+^regress/modify$
 ^regress/name_locate$
-^regress/open$
+^regress/rename$
 ^regress/set_comment_all$
 ^regress/set_comment_localonly$
 ^regress/set_comment_removeglobal$
 ^regress/set_comment_revert$
+^regress/set_compression$
+^regress/stat_index$
 ^regress/tryopen$
 ^src/zipcmp$
 ^src/zipmerge$
diff --git a/.hgtags b/.hgtags
index 86c1fde..32284a2 100644
--- a/.hgtags
+++ b/.hgtags
@@ -3,3 +3,4 @@
 305c067cba3a04d11e95c7cd1e0ae55d662620ee rel-0-9-1
 a523a1da577163bb4255d0f670444964bbf9d43e rel-0-9-2
 a3023e707845ef0d87b9cb33cb3c330afbb5a3c3 rel-0-9-3
+70e00fa4feefae33235b72c072c30c90f76b8204 rel-0-10
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50bc082..980eb77 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@
 SET(PACKAGE_NAME ${PACKAGE})
 SET(PACKAGE_VERSION_MAJOR "0")
 SET(PACKAGE_VERSION_MINOR "10")
-SET(PACKAGE_VERSION_PATCH "1")
+SET(PACKAGE_VERSION_PATCH "b")
 SET(VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}")
 SET(PACKAGE_VERSION ${VERSION})
 SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
@@ -45,12 +45,16 @@
 CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H_LIBZIP)
 CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H_LIBZIP)
 CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H_LIBZIP)
+CHECK_TYPE_SIZE(__int8 __INT8_LIBZIP)
 CHECK_TYPE_SIZE(int8_t INT8_T_LIBZIP)
 CHECK_TYPE_SIZE(uint8_t UINT8_T_LIBZIP)
+CHECK_TYPE_SIZE(__int16 __INT16_LIBZIP)
 CHECK_TYPE_SIZE(int16_t INT16_T_LIBZIP)
 CHECK_TYPE_SIZE(uint16_t UINT16_T_LIBZIP)
+CHECK_TYPE_SIZE(__int32 __INT32_LIBZIP)
 CHECK_TYPE_SIZE(int32_t INT32_T_LIBZIP)
 CHECK_TYPE_SIZE(uint32_t UINT32_T_LIBZIP)
+CHECK_TYPE_SIZE(__int64 __INT64_LIBZIP)
 CHECK_TYPE_SIZE(int64_t INT64_T_LIBZIP)
 CHECK_TYPE_SIZE(uint64_t UINT64_T_LIBZIP)
 CHECK_TYPE_SIZE("short" SHORT_LIBZIP)
@@ -66,6 +70,10 @@
   MESSAGE(FATAL_ERROR "-- ZLIB version too old, please install at least v1.1.2")
 ENDIF(NOT HAVE_ZEXPORT)
 
+IF(MSVC)
+ADD_DEFINITIONS("-D_CRT_SECURE_NO_WARNING")
+ENDIF(MSVC)
+
 # Targets
 ADD_SUBDIRECTORY(lib)
 ADD_SUBDIRECTORY(man)
diff --git a/NEWS b/NEWS
index 02081c6..c9923a9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,15 @@
-0.10.1 [2012/03/20]
+0.xx [20xx/xx/xx]
 
+* Add UTF-8 support for file names, file comments, and archive comments
+* Added zip_discard()
+* Added ZIP_TRUNCATE for zip_open()
+* Added zip_set_compression()
+* Added zip_get_file_extra()/zip_set_file_extra()
+* Use gcc4's visibility __attribute__
+* More changes for Windows support
+* Additional test cases
+
+0.10.1 [2012/03/20]
 * Fixed CVE-2012-1162
 * Fixed CVE-2012-1163
 
diff --git a/THANKS b/THANKS
index 601d3cf..3cd6610 100644
--- a/THANKS
+++ b/THANKS
@@ -4,13 +4,16 @@
 Thanks to these people for suggestions, testing, and bug reports:
 
 Alexander Galanin <al@galanin.nnov.ru>
+Alexandr Shadchin <alexandr.shadchin@gmail.com>
 Andrew Brampton <brampton@gmail.com>
+François Simon <AT.GFI.Francois.SIMON@sesam-vitale.fr>
 Heiko Hund <heiko@ist.eigentlich.net>
 Joel Ebrahimi <joel.ebrahimi@gmail.com>
 Jono Spiro <jono.spiro@gmail.com>
 Mikhail Gusarov <dottedmag@dottedmag.net>.
 Oliver Kaiser <under.northern.sky@googlemail.com>
 Patrick Spendrin <ps_ml@gmx.de>
+Paul Sheppard <shepsoft@googlemail.com>
 Pierre Joye <pierre.php@gmail.com>
 Rick Carback <carback1@umbc.edu>
 Roberto Tirabassi <rtirabassi@3di.it>
@@ -18,3 +21,5 @@
 Stephen Bryant <steve@bawue.de>
 Tarmo Pikaro <tapika@yahoo.com>
 Timo Warns <warns@pre-sense.de>
+Tom Callaway <tcallawa@redhat.com>
+Vassili Courzakis <vcoxvco@googlemail.com>
diff --git a/TODO b/TODO
index add2bf5..75ce36d 100644
--- a/TODO
+++ b/TODO
@@ -1,76 +1,97 @@
-! [doc] zip_source_function: mention that stat is called after close
-! [cleanup] get rid of zip_get_{compression,encryption}_implementation
-! [compat] test calls against old API
-+ [portability] use _setmode(_fileno(fp), _O_BINARY); where present
-+ [bug] fix permissions of new file to match old one
-+ [bug] _zip_checkcons return value can overflow
-+ [bug] _zip_u2d_time: handle localtime(3) failure
-+ [bug] missing -Wl,-R in pkg-config file
-+ [cleanup] use zip_*int*_t internally
-+ [cleanup] don't make zip_source_zip go through zip_fread
-+ [bug] set "version of encoding software" to 2.0
-+ [bug?] keep extended local headers when copying?
-- [cleanup] remove now useless check of fseek 
-- [consistency check] check that local headers come before central dir
-- [consistency] check arguments for every entry point into libzip
-- [bug] zip_open: consistency check: check data descriptor
-- [bug] do not compress if storing is smaller
-- [bug] zip_open: check whether file can be created and fail if not
-- [bug] check for limits imposed by format (central dir size, file size, ...)
-- [feature] handle zip_open/zip_close "race" for new files
-- [feature] support streaming output (creating new archive to e.g. stdout)
-- [feature] add functions to:
-  . set compression method for new/changed entry
-  . set last modification time for entry
-  . read/set EAs
-  . parse/create some EAs?
-  . read/set ASCII file flag
-+ [test] run regression tests also from CMake framework
-- [test] rename deleted (fails)
-- [test] rename file to dir/ and vice versa (fails)
------------------------------------------------- API issues
-- character encoding in file names and comments (ZIP_AFL_UTF8, see mail)
-- parameters for compression/crypt implementations (extra function)
-  ZIP_CM_DEFLATE/ZIP_CM_BZIP2: compression level
-  			       memlevel?
-* compression/crypt implementations: how to set error code on failure
-+ compression/crypt error messages a la ZIP_ER_ZLIB (no detailed info passing)
-* I/O methods
------------------------------------------------- API ideas
+API Plans
+=========
+
+Compression
+-----------
+int zip_set_file_compression(struct zip *archive, zip_uint64_t idx,
+       			     zip_uint16_t method, zip_uint32_t flags);
+	flags: 0-15: compression ratio (0: fast, 15: best)
+		16: default
+		higher bits: method specific
+
+Encryption
+----------
 struct zip *zip_open_encrypted(const char *path, int flags,
                                const char *password, int *errorp);
 
-int zip_set_file_compression(struct zip *archive, zip_uint64_t idx,
-    			zip_uint16_t method, zip_uint32_t flags);
-	flags: 0-15: compression ratio (0: fast, 15: best)
-		16: default	
-		higher bits: method specific
 int zip_set_encryption(struct zip *archive, zip_uint64_t idx,
     		       zip_uint16_t method, const char *password);
 void zip_set_archive_encryption(struct zip *archive,
      				zip_uint16_t method, const char *password);
 
-struct zip_source *zip_source_writable(struct zip *archive);
-zip_source_write(struct zip_source *, const void *data, size_t len);
-zip_source_printf(struct zip_source *, const char *fmt, ...);
-/* maybe
-zip_source_vprintf(struct zip_source *, const char *fmt, va_list ap);
-*/
------------------------------------------------- others
-* regression tests (duplicate file names, unchange, .{200})
-* zip_commit
-* zip_replace_zip: allow rewinding
-* API for parsing extra fields?
-* API for setting/getting extra fields in cdir?
-* zipcmp: add option for file content comparison
-* support for zip64 (large file)
+Extra Fields
+------------
+zip_uint32_t zip_get_extra_field_num(struct zip *archive, zip_uint64_t idx);
+int zip_get_extra_field_index(struct zip *archive, zip_uint64_t idx,
+			      zip_uint32_t ef_idx, zip_uint16_t *ID,
+			      zip_uint16_t *len, void **content);
+int zip_get_extra_field_id(struct zip *archive, zip_uint64_t idx,
+			   zip_uint16_t ID, zip_uint16_t *len, void **content);
+int zip_set_extra_field_id(struct zip *archive, zip_uint64_t idx,
+			   zip_uint16_t ID, zip_uint16_t len, void *content);
 
-* append to files (for self-extracting files)
+
+API Issues
+==========
+* character encoding in file names and comments (see mail)
+* compression/crypt implementations: how to set error code on failure
+* compression/crypt error messages a la ZIP_ER_ZLIB (no detailed info passing)
+
+
+Features
+========
+* I/O methods
+* do not compress if storing is smaller
+* support streaming output (creating new archive to e.g. stdout)
+* add functions to:
+  . set last modification time for entry
+  . read/set ASCII file flag? (wiz: more general options?)
+  . get/set "version made by" and "external file attributes"
+    (can be used to decide if an entry is a directory, if the
+     archive was created on DOS)
+* zip_commit (to finish changes without closing archive)
+* support for zip64 (large file)
 * add custom compression function support
-* zip_replace_zip: remember compression method, recompress if different speced
-* close even if error...
+* close even if error?
 * support for old compression methods?????
------------------------------------------------- regression tests
+* zip_replace_zip: allow rewinding
+* zip_replace_zip: remember compression method, recompress if different speced
+* zipcmp: add option for file content comparison
+* append to files (for self-extracting files)
+
+
+Bugs
+====
+* check for limits imposed by format (central dir size, file size, ...)
+* set "version of encoding software" to proper value (2.0?)
+* _zip_checkcons return value can overflow
+* _zip_u2d_time: handle localtime(3) failure
+* missing -Wl,-R in pkg-config file
+* zip_open: consistency check: check data descriptor
+* POSIX: zip_open: check whether file can be created and fail if not
+* POSIX: fix permissions of new file to match old one
+* fix inconsistent usage of valid flags (not checked in many places)
+
+Cleanup
+=======
+* get rid of zip_get_{compression,encryption}_implementation
+* use zip_*int*_t internally
+* completely get rid of off_t
+
+
+Consistency
+===========
+* check arguments for every entry point into libzip
+* check that local headers come before central dir
+
+
+Test Case Issues
+================
+* test calls against old API
+* run regression tests also from CMake framework
+* rename file to dir/ and vice versa (fails)
+* fix comment test to be newline insensitive
+
 * (add, replace)
 	add to empty zip
 	add to existing zip
@@ -86,7 +107,6 @@
 	close
 	zipcmp copy expected
 	remove copy
-* (delete)
 * (error_get)
 * (error_get_sys_type)
 * (error_to_str)
@@ -96,7 +116,6 @@
 * (fopen_index)
 	illegal index
 * (get_name)
-* (get_num_files)
 * (rename)
 * (replace)
 * (source_buffer)
diff --git a/cmake-zipconf.h.in b/cmake-zipconf.h.in
index f7b08ae..70c8f2b 100644
--- a/cmake-zipconf.h.in
+++ b/cmake-zipconf.h.in
@@ -11,12 +11,16 @@
 #cmakedefine HAVE_INTTYPES_H_LIBZIP
 #cmakedefine HAVE_STDINT_H_LIBZIP
 #cmakedefine HAVE_SYS_TYPES_H_LIBZIP
+#cmakedefine HAVE___INT8_LIBZIP
 #cmakedefine HAVE_INT8_T_LIBZIP
 #cmakedefine HAVE_UINT8_T_LIBZIP
+#cmakedefine HAVE___INT16_LIBZIP
 #cmakedefine HAVE_INT16_T_LIBZIP
 #cmakedefine HAVE_UINT16_T_LIBZIP
+#cmakedefine HAVE___INT32_LIBZIP
 #cmakedefine HAVE_INT32_T_LIBZIP
 #cmakedefine HAVE_UINT32_T_LIBZIP
+#cmakedefine HAVE___INT64_LIBZIP
 #cmakedefine HAVE_INT64_T_LIBZIP
 #cmakedefine HAVE_UINT64_T_LIBZIP
 #cmakedefine SHORT_LIBZIP ${SHORT_LIBZIP}
@@ -34,26 +38,36 @@
 
 #if defined(HAVE_INT8_T_LIBZIP)
 typedef int8_t zip_int8_t;
+#elif defined(HAVE___INT8_LIBZIP_)
+typedef __int8 zip_int8_t;
 #else
 typedef signed char zip_int8_t;
 #endif
 #if defined(HAVE_UINT8_T_LIBZIP)
 typedef uint8_t zip_uint8_t;
+#elif defined(HAVE___INT8_LIBZIP_)
+typedef unsigned __int8 zip_uint8_t;
 #else
 typedef unsigned char zip_uint8_t;
 #endif
 #if defined(HAVE_INT16_T_LIBZIP)
 typedef int16_t zip_int16_t;
+#elif defined(HAVE___INT16_LIBZIP_)
+typedef __int16 zip_int16_t;
 #elif defined(SHORT_LIBZIP) && SHORT_LIBZIP == 2
 typedef signed short zip_int16_t;
 #endif
 #if defined(HAVE_UINT16_T_LIBZIP)
 typedef uint16_t zip_uint16_t;
+#elif defined(HAVE___INT16_LIBZIP_)
+typedef unsigned __int16 zip_uint16_t;
 #elif defined(SHORT_LIBZIP) && SHORT_LIBZIP == 2
 typedef unsigned short zip_uint16_t;
 #endif
 #if defined(HAVE_INT32_T_LIBZIP)
 typedef int32_t zip_int32_t;
+#elif defined(HAVE___INT32_LIBZIP_)
+typedef __int32 zip_int32_t;
 #elif defined(INT_LIBZIP) && INT_LIBZIP == 4
 typedef signed int zip_int32_t;
 #elif defined(LONG_LIBZIP) && LONG_LIBZIP == 4
@@ -61,6 +75,8 @@
 #endif
 #if defined(HAVE_UINT32_T_LIBZIP)
 typedef uint32_t zip_uint32_t;
+#elif defined(HAVE___INT32_LIBZIP_)
+typedef unsigned __int32 zip_uint32_t;
 #elif defined(INT_LIBZIP) && INT_LIBZIP == 4
 typedef unsigned int zip_uint32_t;
 #elif defined(LONG_LIBZIP) && LONG_LIBZIP == 4
@@ -68,6 +84,8 @@
 #endif
 #if defined(HAVE_INT64_T_LIBZIP)
 typedef int64_t zip_int64_t;
+#elif defined(HAVE___INT64_LIBZIP_)
+typedef __int64 zip_int64_t;
 #elif defined(LONG_LIBZIP) && LONG_LIBZIP == 8
 typedef signed long zip_int64_t;
 #elif defined(LONGLONG_LIBZIP) && LONGLONG_LIBZIP == 8
@@ -75,6 +93,8 @@
 #endif
 #if defined(HAVE_UINT64_T_LIBZIP)
 typedef uint64_t zip_uint64_t;
+#elif defined(HAVE___INT64_LIBZIP_)
+typedef unsigned __int64 zip_uint64_t;
 #elif defined(LONG_LIBZIP) && LONGLONG_LIBZIP == 8
 typedef unsigned long zip_uint64_t;
 #elif defined(LONGLONG_LIBZIP) && LONGLONG_LIBZIP == 8
diff --git a/configure.ac b/configure.ac
index 793c1ca..6e72ecb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.57)
-AC_INIT([libzip],[0.10.1],[libzip-discuss@nih.at])
+AC_INIT([libzip],[0.10b],[libzip-discuss@nih.at])
 AC_CONFIG_SRCDIR([lib/zip_add.c])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index af09a39..99c4014 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -58,6 +58,7 @@
   zip_close.c
   zip_delete.c
   zip_dirent.c
+  zip_discard.c
   zip_entry_free.c
   zip_entry_new.c
   zip_err_str.c
@@ -69,6 +70,7 @@
   zip_error_to_str.c
   zip_fclose.c
   zip_fdopen.c
+  zip_set_file_compression.c
   zip_file_error_clear.c
   zip_file_error_get.c
   zip_file_get_offset.c
@@ -79,7 +81,6 @@
   zip_fopen_index.c
   zip_fopen_index_encrypted.c
   zip_fread.c
-  zip_free.c
   zip_get_archive_comment.c
   zip_get_archive_flag.c
   zip_get_compression_implementation.c
@@ -87,6 +88,7 @@
   zip_get_file_comment.c
   zip_get_file_extra.c
   zip_get_name.c
+  zip_get_num_entries.c
   zip_get_num_files.c
   zip_memdup.c
   zip_name_locate.c
@@ -115,7 +117,9 @@
   zip_source_pop.c
   zip_source_read.c
   zip_source_stat.c
+  zip_source_window.c
   zip_source_zip.c
+  zip_source_zip_new.c
   zip_stat.c
   zip_stat_index.c
   zip_stat_init.c
@@ -124,6 +128,7 @@
   zip_unchange_all.c
   zip_unchange_archive.c
   zip_unchange_data.c
+  zip_utf-8.c
 )
 
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 9f7be38..9a1c28d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -15,6 +15,7 @@
 	zip_close.c \
 	zip_delete.c \
 	zip_dirent.c \
+	zip_discard.c \
 	zip_entry_free.c \
 	zip_entry_new.c \
 	zip_err_str.c \
@@ -36,7 +37,6 @@
 	zip_fopen_index.c \
 	zip_fopen_index_encrypted.c \
 	zip_fread.c \
-	zip_free.c \
 	zip_get_archive_comment.c \
 	zip_get_archive_flag.c \
 	zip_get_compression_implementation.c \
@@ -56,6 +56,7 @@
 	zip_set_archive_flag.c \
 	zip_set_default_password.c \
 	zip_set_file_comment.c \
+	zip_set_file_compression.c \
 	zip_set_file_extra.c \
 	zip_source_buffer.c \
 	zip_source_close.c \
@@ -72,7 +73,9 @@
 	zip_source_pop.c \
 	zip_source_read.c \
 	zip_source_stat.c \
+	zip_source_window.c \
 	zip_source_zip.c \
+	zip_source_zip_new.c \
 	zip_set_name.c \
 	zip_stat.c \
 	zip_stat_index.c \
@@ -81,9 +84,10 @@
 	zip_unchange.c \
 	zip_unchange_all.c \
 	zip_unchange_archive.c \
-	zip_unchange_data.c
+	zip_unchange_data.c \
+	zip_utf-8.c
 
-BUILT_SOURCES=zip_err_str.c zipconf.h
+BUILT_SOURCES=zipconf.h
 CLEANFILES=	${BUILT_SOURCES}
 
 EXTRA_DIST=	CMakeLists.txt \
diff --git a/lib/make_zipconf.sh b/lib/make_zipconf.sh
index 5623cd0..12e7b0a 100644
--- a/lib/make_zipconf.sh
+++ b/lib/make_zipconf.sh
@@ -44,13 +44,13 @@
 
     bits=`expr $bytes '*' 8`
     type="${short}int${bits}"
-    TYPE=`echo $type | tr a-z A-Z`
+    TYPE=`echo $type | tr '[a-z]' '[A-Z]'`
     if grep "define HAVE_${TYPE}_T" "$infile" > /dev/null
     then
 	echo "typedef ${type}_t zip_${type}_t;" >> "$outfile"
 	LTYPE="$TYPE"
     else
-	SHORT=`echo $short | tr a-z A-Z`
+	SHORT=`echo $short | tr '[a-z]' '[A-Z]'`
 	if [ -z "$SHORT" ]
 	then
 	    SHORT='S'
@@ -65,7 +65,7 @@
 	    LTYPE="${SHORT}CHAR"
 	else
 	    ctype=`sed -n "s/.define SIZEOF_\([A-Z_]*\) $bytes/\1/p" "$infile" \
-		| head -1 | tr A-Z_ 'a-z '`
+		| head -1 | tr '[A-Z_]' '[a-z ]'`
 	    if [ -z "$ctype" ]
 	    then
 		echo "$0: no $bits bit type found" >&2
diff --git a/lib/zip.h b/lib/zip.h
index f8b55ac..10e2f36 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -3,7 +3,7 @@
 
 /*
   zip.h -- exported declarations.
-  Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -39,6 +39,8 @@
 #ifndef ZIP_EXTERN
 #ifdef _WIN32
 #define ZIP_EXTERN __declspec(dllimport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ZIP_EXTERN __attribute__ ((visibility ("default")))
 #else
 #define ZIP_EXTERN
 #endif
@@ -59,6 +61,7 @@
 #define ZIP_CREATE           1
 #define ZIP_EXCL             2
 #define ZIP_CHECKCONS        4
+#define ZIP_TRUNCATE         8
 
 
 /* flags for zip_name_locate, zip_fopen, zip_stat, ... */
@@ -70,6 +73,9 @@
 #define ZIP_FL_RECOMPRESS      16 /* force recompression of data */
 #define ZIP_FL_ENCRYPTED       32 /* read encrypted data
 				     (implies ZIP_FL_COMPRESSED) */
+#define ZIP_FL_NAME_GUESS       0 /* guess name encoding (is default) */
+#define ZIP_FL_NAME_RAW        64 /* get unmodified name */
+#define ZIP_FL_NAME_STRICT    128 /* follow specification strictly */
 
 /* archive global flags flags */
 
@@ -79,6 +85,7 @@
 
 /* flags for compression and encryption sources */
 
+#define ZIP_CODEC_DECODE	0 /* decompress/decrypt (encode flag not set) */
 #define ZIP_CODEC_ENCODE	1 /* compress/encrypt */
 
 
@@ -112,6 +119,7 @@
 #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_ENCMISMATCH   28  /* N Encoding of name and comment do not match */
 
 /* type of system error value */
 
@@ -208,6 +216,7 @@
 ZIP_EXTERN zip_int64_t zip_add(struct zip *, const char *, struct zip_source *);
 ZIP_EXTERN zip_int64_t zip_add_dir(struct zip *, const char *);
 ZIP_EXTERN int zip_close(struct zip *);
+ZIP_EXTERN void zip_discard(struct zip *);
 ZIP_EXTERN int zip_delete(struct zip *, zip_uint64_t);
 ZIP_EXTERN void zip_error_clear(struct zip *);
 ZIP_EXTERN void zip_error_get(struct zip *, int *, int *);
@@ -244,6 +253,8 @@
 ZIP_EXTERN int zip_set_default_password(struct zip *, const char *);
 ZIP_EXTERN int zip_set_file_comment(struct zip *, zip_uint64_t,
 				    const char *, int);
+ZIP_EXTERN int zip_set_file_compression(struct zip *, zip_uint64_t,
+					zip_int32_t, zip_uint32_t);
 ZIP_EXTERN int zip_set_file_extra(struct zip *, zip_uint64_t,
 				  const char *, int);
 ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *,
diff --git a/lib/zip_close.c b/lib/zip_close.c
index f4ae2a4..4d8e178 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -1,6 +1,6 @@
 /*
   zip_close.c -- close zip archive and update changes
-  Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -82,29 +82,33 @@
     struct filelist *filelist;
     int reopen_on_error;
     int new_torrentzip;
+    enum zip_encoding_type com_enc, enc;
+    int changed;
 
     reopen_on_error = 0;
 
     if (za == NULL)
 	return -1;
 
-    if (!_zip_changed(za, &survivors)) {
-	_zip_free(za);
-	return 0;
-    }
+    changed = _zip_changed(za, &survivors);
 
     /* don't create zip files with no entries */
     if (survivors == 0) {
-	if (za->zn && za->zp) {
+	if (za->zn && ((za->open_flags & ZIP_TRUNCATE) || (changed && za->zp))) {
 	    if (remove(za->zn) != 0) {
 		_zip_error_set(&za->error, ZIP_ER_REMOVE, errno);
 		return -1;
 	    }
 	}
-	_zip_free(za);
+	zip_discard(za);
 	return 0;
     }	       
 
+    if (!changed) {
+	zip_discard(za);
+	return 0;
+    }
+
     if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors))
 	== NULL)
 	return -1;
@@ -162,32 +166,33 @@
 					      ZIP_FL_UNCHANGED) == 0);
     error = 0;
     for (j=0; j<survivors; j++) {
+	int new_data;
+
 	i = filelist[j].idx;
 
+	new_data = (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip || (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD));
+
 	/* create new local directory entry */
-	if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) {
+	if (new_data) {
 	    _zip_dirent_init(&de);
 
 	    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
 		_zip_dirent_torrent_normalize(&de);
 		
+	    if (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD) {
+		de.settable.comp_method = za->entry[i].changes.comp_method;
+		de.settable.valid |= ZIP_DIRENT_COMP_METHOD;
+	    }
+
 	    /* use it as central directory entry */
 	    memcpy(cd->entry+j, &de, sizeof(cd->entry[j]));
 
 	    /* set/update file name */
-	    if (za->entry[i].ch_filename == NULL) {
-		if (za->entry[i].state == ZIP_ST_ADDED) {
-		    de.filename = strdup("-");
-		    de.filename_len = 1;
-		    cd->entry[j].filename = "-";
-		    cd->entry[j].filename_len = 1;
-		}
-		else {
-		    de.filename = strdup(za->cdir->entry[i].filename);
-		    de.filename_len = strlen(de.filename);
-		    cd->entry[j].filename = za->cdir->entry[i].filename;
-		    cd->entry[j].filename_len = de.filename_len;
-		}
+	    if ((za->entry[i].changes.valid & ZIP_DIRENT_FILENAME) == 0) {
+		de.settable.filename = strdup(za->cdir->entry[i].settable.filename);
+		cd->entry[j].settable.filename = za->cdir->entry[i].settable.filename;
+		de.settable.valid |= ZIP_DIRENT_FILENAME;
+		cd->entry[j].settable.valid |= ZIP_DIRENT_FILENAME;
 	    }
 	}
 	else {
@@ -212,49 +217,61 @@
 	    }
 	}
 
-	if (za->entry[i].ch_filename) {
-	    free(de.filename);
-	    if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) {
+	if (za->entry[i].changes.valid & ZIP_DIRENT_FILENAME) {
+	    free(de.settable.filename);
+	    if ((de.settable.filename=strdup(za->entry[i].changes.filename)) == NULL) {
 		error = 1;
 		break;
 	    }
-	    de.filename_len = strlen(de.filename);
-	    cd->entry[j].filename = za->entry[i].ch_filename;
-	    cd->entry[j].filename_len = de.filename_len;
+	    cd->entry[j].settable.filename = za->entry[i].changes.filename;
 	}
 
-	if (za->entry[i].ch_extra_len != -1) {
-	    free(de.extrafield);
-	    if ((de.extrafield=malloc(za->entry[i].ch_extra_len)) == NULL) {
-		error = 1;
-		break;
-	    }
-	    memcpy(de.extrafield, za->entry[i].ch_extra, za->entry[i].ch_extra_len);
-	    de.extrafield_len = za->entry[i].ch_extra_len;
+	if (za->entry[i].changes.valid & ZIP_DIRENT_EXTRAFIELD) {
+	    free(de.settable.extrafield);
+	    if (za->entry[i].changes.extrafield_len > 0) {
+	        if ((de.settable.extrafield=malloc(za->entry[i].changes.extrafield_len)) == NULL) {
+		    error = 1;
+		    break;
+	        }
+	        memcpy(de.settable.extrafield, za->entry[i].changes.extrafield, za->entry[i].changes.extrafield_len);
+            }
+	    else
+		de.settable.extrafield = NULL;
+	    de.settable.extrafield_len = za->entry[i].changes.extrafield_len;
 	    /* as the rest of cd entries, its malloc/free is done by za */
 	    /* TODO unsure if this should also be set in the CD --
 	     * not done for now
-	    cd->entry[j].extrafield = za->entry[i].ch_extra;
-	    cd->entry[j].extrafield_len = za->entry[i].ch_extra_len;
+	    cd->entry[j].settable.extrafield = za->entry[i].changes.extrafield;
+	    cd->entry[j].settable.extrafield_len = za->entry[i].changes.extrafield_len;
 	    */
 	}
 
 	if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0
-	    && za->entry[i].ch_comment_len != -1) {
+	    && za->entry[i].changes.valid & ZIP_DIRENT_COMMENT) {
 	    /* as the rest of cd entries, its malloc/free is done by za */
-	    cd->entry[j].comment = za->entry[i].ch_comment;
-	    cd->entry[j].comment_len = za->entry[i].ch_comment_len;
+	    cd->entry[j].settable.comment = za->entry[i].changes.comment;
+	    cd->entry[j].settable.comment_len = za->entry[i].changes.comment_len;
 	}
 
+	/* set general purpose bit flag for file name/comment encoding */
+	enc = _zip_guess_encoding(de.settable.filename, strlen(de.settable.filename));
+	com_enc = _zip_guess_encoding(cd->entry[i].settable.comment, cd->entry[i].settable.comment_len);
+	if ((enc == ZIP_ENCODING_UTF8  && com_enc == ZIP_ENCODING_ASCII) ||
+	    (enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8 ) ||
+	    (enc == ZIP_ENCODING_UTF8  && com_enc == ZIP_ENCODING_UTF8 ))
+	    de.bitflags |= ZIP_GPBF_ENCODING_UTF_8;
+	else
+	    de.bitflags &= ~ZIP_GPBF_ENCODING_UTF_8;
+	cd->entry[i].bitflags = de.bitflags;
+
 	cd->entry[j].offset = ftello(out);
 
-	if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) {
+	if (new_data) {
 	    struct zip_source *zs;
 
 	    zs = NULL;
 	    if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) {
-		if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1))
-		    == NULL) {
+		if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, -1, NULL)) == NULL) {
 		    error = 1;
 		    break;
 		}
@@ -270,7 +287,7 @@
 		zip_source_free(zs);
 	    
 	    cd->entry[j].last_mod = de.last_mod;
-	    cd->entry[j].comp_method = de.comp_method;
+	    cd->entry[j].settable.comp_method = de.settable.comp_method;
 	    cd->entry[j].comp_size = de.comp_size;
 	    cd->entry[j].uncomp_size = de.uncomp_size;
 	    cd->entry[j].crc = de.crc;
@@ -338,7 +355,7 @@
     chmod(za->zn, 0666&~mask);
 #endif
 
-    _zip_free(za);
+    zip_discard(za);
     free(temp);
     
     return 0;
@@ -353,7 +370,6 @@
     off_t offstart, offdata, offend;
     struct zip_stat st;
     struct zip_source *s2;
-    zip_compression_implementation comp_impl;
     int ret;
     
     if (zip_source_stat(src, &st) < 0) {
@@ -366,28 +382,57 @@
     if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
 	return -1;
 
-    if ((s2=zip_source_crc(za, src, 0)) == NULL) {
-	zip_source_pop(s2);
-	return -1;
+    if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
+	st.valid |= ZIP_STAT_COMP_METHOD;
+	st.comp_method = ZIP_CM_STORE;
     }
-    
-    /* XXX: deflate 0-byte files for torrentzip? */
-    if (((st.valid & ZIP_STAT_COMP_METHOD) == 0
-	 || st.comp_method == ZIP_CM_STORE)
-	&& ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) {
-	comp_impl = NULL;
-	if ((comp_impl=zip_get_compression_implementation(ZIP_CM_DEFLATE))
-	    == NULL) {
-	    _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
-	    zip_source_pop(s2);
+
+    if ((de->settable.valid & ZIP_DIRENT_COMP_METHOD) == 0 || de->settable.comp_method == ZIP_CM_DEFAULT) {
+	de->settable.valid |= ZIP_DIRENT_COMP_METHOD;
+	de->settable.comp_method = ZIP_CM_DEFLATE;
+    }
+
+    if (st.comp_method != de->settable.comp_method) {
+	struct zip_source *s_store, *s_crc;
+	zip_compression_implementation comp_impl;
+	
+	if (st.comp_method != ZIP_CM_STORE) {
+	    if ((comp_impl=zip_get_compression_implementation(st.comp_method)) == NULL) {
+		_zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+		return -1;
+	    }
+	    if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
+		/* error set by comp_impl */
+		return -1;
+	    }
+	}
+	else
+	    s_store = src;
+
+	if ((s_crc=zip_source_crc(za, s_store, 0)) == NULL) {
+	    if (s_store != src)
+		zip_source_pop(s_store);
 	    return -1;
 	}
-	if ((s2=comp_impl(za, s2, ZIP_CM_DEFLATE, ZIP_CODEC_ENCODE))
-	    == NULL) {
-	    /* XXX: set error? */
-	    zip_source_pop(s2);
-	    return -1;
+
+	/* XXX: deflate 0-byte files for torrentzip? */
+	if (de->settable.comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) {
+	    if ((comp_impl=zip_get_compression_implementation(de->settable.comp_method)) == NULL) {
+		_zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+		zip_source_pop(s_crc);
+		if (s_store != src)
+		    zip_source_pop(s_store);
+		return -1;
+	    }
+	    if ((s2=comp_impl(za, s_crc, de->settable.comp_method, ZIP_CODEC_ENCODE)) == NULL) {
+		zip_source_pop(s_crc);
+		if (s_store != src)
+		    zip_source_pop(s_store);
+		return -1;
+	    }
 	}
+	else
+	    s2 = s_crc;
     }
     else
 	s2 = src;
@@ -418,7 +463,7 @@
     }
 
     de->last_mod = st.mtime;
-    de->comp_method = st.comp_method;
+    de->settable.comp_method = st.comp_method;
     de->crc = st.crc;
     de->uncomp_size = st.size;
     de->comp_size = offend - offdata;
@@ -548,13 +593,18 @@
 _zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src)
 {
     if (src->ch_comment_len != -1) {
-	dest->comment = _zip_memdup(src->ch_comment,
-				    src->ch_comment_len, &src->error);
-	if (dest->comment == NULL)
-	    return -1;
 	dest->comment_len = src->ch_comment_len;
-    } else {
-	if (src->cdir && src->cdir->comment) {
+	if (src->ch_comment_len == 0)
+	    dest->comment = NULL;
+	else {
+	    dest->comment = _zip_memdup(src->ch_comment,
+				        src->ch_comment_len, &src->error);
+	    if (dest->comment == NULL)
+	        return -1;
+	}
+    }
+    else {
+	if (src->cdir && src->cdir->comment_len > 0) {
 	    dest->comment = _zip_memdup(src->cdir->comment,
 					src->cdir->comment_len, &src->error);
 	    if (dest->comment == NULL)
@@ -580,9 +630,7 @@
 	changed = 1;
 
     for (i=0; i<za->nentry; i++) {
-	if ((za->entry[i].state != ZIP_ST_UNCHANGED)
-	    || (za->entry[i].ch_extra_len != -1)
-	    || (za->entry[i].ch_comment_len != -1))
+	if (za->entry[i].state != ZIP_ST_UNCHANGED || za->entry[i].changes.valid != 0)
 	    changed = 1;
 	if (za->entry[i].state != ZIP_ST_DELETED)
 	    survivors++;
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index b5b9d27..4006a5b 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -1,6 +1,6 @@
 /*
   zip_dirent.c -- read directory entry (local or central), clean dirent
-  Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -61,6 +61,7 @@
     for (i=0; i<cd->nentry; i++)
 	_zip_dirent_finalize(cd->entry+i);
     free(cd->comment);
+    free(cd->comment_converted);
     free(cd->entry);
     free(cd);
 }
@@ -77,6 +78,9 @@
 	return -1;
     }
 
+    if (nentry == cd->nentry)
+	return 0;
+
     if ((entry=((struct zip_dirent *)
 		realloc(cd->entry, sizeof(*(cd->entry))*nentry))) == NULL) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
@@ -101,7 +105,9 @@
 	return NULL;
     }
 
-    if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
+    if (nentry == 0)
+	cd->entry = NULL;
+    else if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
 	== NULL) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
 	free(cd);
@@ -114,6 +120,8 @@
     cd->size = cd->offset = 0;
     cd->comment = NULL;
     cd->comment_len = 0;
+    cd->comment_type = ZIP_ENCODING_UNKNOWN;
+    cd->comment_converted = NULL;
 
     return cd;
 }
@@ -157,12 +165,16 @@
 void
 _zip_dirent_finalize(struct zip_dirent *zde)
 {
-    free(zde->filename);
-    zde->filename = NULL;
-    free(zde->extrafield);
-    zde->extrafield = NULL;
-    free(zde->comment);
-    zde->comment = NULL;
+    free(zde->filename_converted);
+    zde->filename_converted = NULL;
+    free(zde->comment_converted);
+    zde->comment_converted = NULL;
+    free(zde->settable.filename);
+    zde->settable.filename = NULL;
+    free(zde->settable.extrafield);
+    zde->settable.extrafield = NULL;
+    free(zde->settable.comment);
+    zde->settable.comment = NULL;
 }
 
 
@@ -170,24 +182,28 @@
 void
 _zip_dirent_init(struct zip_dirent *de)
 {
+    de->settable.valid = 0;
+    de->settable.comp_method = 0;
+    de->settable.filename = NULL;
+    de->settable.extrafield = NULL;
+    de->settable.extrafield_len = 0;
+    de->settable.comment = NULL;
+    de->settable.comment_len = 0;
     de->version_madeby = 0;
     de->version_needed = 20; /* 2.0 */
     de->bitflags = 0;
-    de->comp_method = 0;
     de->last_mod = 0;
     de->crc = 0;
     de->comp_size = 0;
     de->uncomp_size = 0;
-    de->filename = NULL;
-    de->filename_len = 0;
-    de->extrafield = NULL;
-    de->extrafield_len = 0;
-    de->comment = NULL;
-    de->comment_len = 0;
     de->disk_number = 0;
     de->int_attrib = 0;
     de->ext_attrib = 0;
     de->offset = 0;
+    de->fn_type = ZIP_ENCODING_UNKNOWN;
+    de->filename_converted = NULL;
+    de->fc_type = ZIP_ENCODING_UNKNOWN;
+    de->comment_converted = NULL;
 }
 
 
@@ -219,6 +235,7 @@
     unsigned char *cur;
     unsigned short dostime, dosdate;
     zip_uint32_t size;
+    zip_uint16_t filename_len;
 
     if (local)
 	size = LENTRYSIZE;
@@ -249,16 +266,18 @@
     }
     cur += 4;
 
-    
+
     /* convert buffercontents to zip_dirent */
-    
+
+    _zip_dirent_init(zde);
     if (!local)
 	zde->version_madeby = _zip_read2(&cur);
     else
 	zde->version_madeby = 0;
     zde->version_needed = _zip_read2(&cur);
     zde->bitflags = _zip_read2(&cur);
-    zde->comp_method = _zip_read2(&cur);
+    zde->settable.comp_method = _zip_read2(&cur);
+    zde->settable.valid |= ZIP_DIRENT_COMP_METHOD;
     
     /* convert to time_t */
     dostime = _zip_read2(&cur);
@@ -269,28 +288,28 @@
     zde->comp_size = _zip_read4(&cur);
     zde->uncomp_size = _zip_read4(&cur);
     
-    zde->filename_len = _zip_read2(&cur);
-    zde->extrafield_len = _zip_read2(&cur);
+    filename_len = _zip_read2(&cur);
+    zde->settable.extrafield_len = _zip_read2(&cur);
     
     if (local) {
-	zde->comment_len = 0;
+	zde->settable.comment_len = 0;
 	zde->disk_number = 0;
 	zde->int_attrib = 0;
 	zde->ext_attrib = 0;
 	zde->offset = 0;
     } else {
-	zde->comment_len = _zip_read2(&cur);
+	zde->settable.comment_len = _zip_read2(&cur);
 	zde->disk_number = _zip_read2(&cur);
 	zde->int_attrib = _zip_read2(&cur);
 	zde->ext_attrib = _zip_read4(&cur);
 	zde->offset = _zip_read4(&cur);
     }
 
-    zde->filename = NULL;
-    zde->extrafield = NULL;
-    zde->comment = NULL;
+    zde->settable.filename = NULL;
+    zde->settable.extrafield = NULL;
+    zde->settable.comment = NULL;
 
-    size += zde->filename_len+zde->extrafield_len+zde->comment_len;
+    size += filename_len+zde->settable.extrafield_len+zde->settable.comment_len;
 
     if (leftp && (*leftp < size)) {
 	_zip_error_set(error, ZIP_ER_NOZIP, 0);
@@ -298,46 +317,59 @@
     }
 
     if (bufp) {
-	if (zde->filename_len) {
-	    zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
-	    if (!zde->filename)
+	if (filename_len) {
+	    zde->settable.filename = _zip_readstr(&cur, filename_len, 1, error);
+	    if (!zde->settable.filename)
 		    return -1;
 	}
 
-	if (zde->extrafield_len) {
-	    zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
+	if (zde->settable.extrafield_len) {
+	    zde->settable.extrafield = _zip_readstr(&cur, zde->settable.extrafield_len, 0,
 					   error);
-	    if (!zde->extrafield)
+	    if (!zde->settable.extrafield)
 		return -1;
 	}
 
-	if (zde->comment_len) {
-	    zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
-	    if (!zde->comment)
+	if (zde->settable.comment_len) {
+	    zde->settable.comment = _zip_readstr(&cur, zde->settable.comment_len, 0, error);
+	    if (!zde->settable.comment)
 		return -1;
 	}
     }
     else {
-	if (zde->filename_len) {
-	    zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
-	    if (!zde->filename)
+	if (filename_len) {
+	    zde->settable.filename = _zip_readfpstr(fp, filename_len, 1, error);
+	    if (!zde->settable.filename)
 		    return -1;
 	}
 
-	if (zde->extrafield_len) {
-	    zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
+	if (zde->settable.extrafield_len) {
+	    zde->settable.extrafield = _zip_readfpstr(fp, zde->settable.extrafield_len, 0,
 					     error);
-	    if (!zde->extrafield)
+	    if (!zde->settable.extrafield)
 		return -1;
 	}
 
-	if (zde->comment_len) {
-	    zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
-	    if (!zde->comment)
+	if (zde->settable.comment_len) {
+	    zde->settable.comment = _zip_readfpstr(fp, zde->settable.comment_len, 0, error);
+	    if (!zde->settable.comment)
 		return -1;
 	}
     }
 
+    if (filename_len == 0) {
+	if ((zde->settable.filename=strdup("")) == NULL)
+	    return -1;
+    }
+    if (strlen(zde->settable.filename) != filename_len)
+	return -1;
+    zde->settable.valid |= ZIP_DIRENT_FILENAME;
+
+    if (zde->settable.comment_len)
+	zde->settable.valid |= ZIP_DIRENT_COMMENT;
+    if (zde->settable.extrafield_len)
+	zde->settable.valid |= ZIP_DIRENT_EXTRAFIELD;
+
     if (bufp)
       *bufp = cur;
     if (leftp)
@@ -387,7 +419,8 @@
     de->version_madeby = 0;
     de->version_needed = 20; /* 2.0 */
     de->bitflags = 2; /* maximum compression */
-    de->comp_method = ZIP_CM_DEFLATE;
+    de->settable.comp_method = ZIP_CM_DEFLATE;
+    de->settable.valid |= ZIP_DIRENT_COMP_METHOD;
     de->last_mod = last_mod;
 
     de->disk_number = 0;
@@ -395,12 +428,13 @@
     de->ext_attrib = 0;
     de->offset = 0;
 
-    free(de->extrafield);
-    de->extrafield = NULL;
-    de->extrafield_len = 0;
-    free(de->comment);
-    de->comment = NULL;
-    de->comment_len = 0;
+    free(de->settable.extrafield);
+    de->settable.extrafield = NULL;
+    de->settable.extrafield_len = 0;
+    free(de->settable.comment);
+    de->settable.comment = NULL;
+    de->settable.comment_len = 0;
+    de->settable.valid &= ~(ZIP_DIRENT_COMMENT|ZIP_DIRENT_EXTRAFIELD);
 }
 
 
@@ -420,6 +454,9 @@
 		  struct zip_error *error)
 {
     unsigned short dostime, dosdate;
+    zip_uint16_t filename_len;
+
+    filename_len = strlen(zde->settable.filename);
 
     fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
 
@@ -427,7 +464,7 @@
 	_zip_write2(zde->version_madeby, fp);
     _zip_write2(zde->version_needed, fp);
     _zip_write2(zde->bitflags, fp);
-    _zip_write2(zde->comp_method, fp);
+    _zip_write2(zde->settable.comp_method, fp);
 
     _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
     _zip_write2(dostime, fp);
@@ -437,26 +474,26 @@
     _zip_write4(zde->comp_size, fp);
     _zip_write4(zde->uncomp_size, fp);
     
-    _zip_write2(zde->filename_len, fp);
-    _zip_write2(zde->extrafield_len, fp);
+    _zip_write2(filename_len, fp);
+    _zip_write2(zde->settable.extrafield_len, fp);
     
     if (!localp) {
-	_zip_write2(zde->comment_len, fp);
+	_zip_write2(zde->settable.comment_len, fp);
 	_zip_write2(zde->disk_number, fp);
 	_zip_write2(zde->int_attrib, fp);
 	_zip_write4(zde->ext_attrib, fp);
 	_zip_write4(zde->offset, fp);
     }
 
-    if (zde->filename_len)
-	fwrite(zde->filename, 1, zde->filename_len, fp);
+    if (filename_len > 0)
+	fwrite(zde->settable.filename, 1, filename_len, fp);
 
-    if (zde->extrafield_len)
-	fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
+    if (zde->settable.extrafield_len)
+	fwrite(zde->settable.extrafield, 1, zde->settable.extrafield_len, fp);
 
     if (!localp) {
-	if (zde->comment_len)
-	    fwrite(zde->comment, 1, zde->comment_len, fp);
+	if (zde->settable.comment_len)
+	    fwrite(zde->settable.comment, 1, zde->settable.comment_len, fp);
     }
 
     if (ferror(fp)) {
@@ -523,6 +560,9 @@
 {
     char *r, *o;
 
+    if (len == 0 && nulp == 0)
+	return NULL;
+
     r = (char *)malloc(nulp ? len+1 : len);
     if (!r) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
@@ -553,6 +593,9 @@
 {
     char *r, *o;
 
+    if (len == 0 && nulp == 0)
+	return NULL;
+
     r = (char *)malloc(nulp ? len+1 : len);
     if (!r) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
diff --git a/lib/zip_free.c b/lib/zip_discard.c
similarity index 93%
rename from lib/zip_free.c
rename to lib/zip_discard.c
index 9932c14..16cc3d8 100644
--- a/lib/zip_free.c
+++ b/lib/zip_discard.c
@@ -1,6 +1,6 @@
 /*
-  zip_free.c -- free struct zip
-  Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+  zip_discard.c -- discard and free struct zip
+  Copyright (C) 1999-2012 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>
@@ -39,12 +39,12 @@
 
 
 
-/* _zip_free:
+/* zip_discard:
    frees the space allocated to a zipfile struct, and closes the
    corresponding file. */
 
 void
-_zip_free(struct zip *za)
+zip_discard(struct zip *za)
 {
     int i;
 
diff --git a/lib/zip_entry_free.c b/lib/zip_entry_free.c
index e8a7770..f801855 100644
--- a/lib/zip_entry_free.c
+++ b/lib/zip_entry_free.c
@@ -42,14 +42,13 @@
 void
 _zip_entry_free(struct zip_entry *ze)
 {
-    free(ze->ch_filename);
-    ze->ch_filename = NULL;
-    free(ze->ch_extra);
-    ze->ch_extra = NULL;
-    ze->ch_extra_len = -1;
-    free(ze->ch_comment);
-    ze->ch_comment = NULL;
-    ze->ch_comment_len = -1;
+    if (ze->changes.valid & ZIP_DIRENT_FILENAME)
+	free(ze->changes.filename);
+    if (ze->changes.valid & ZIP_DIRENT_EXTRAFIELD)
+	free(ze->changes.extrafield);
+    if (ze->changes.valid & ZIP_DIRENT_COMMENT)
+	free(ze->changes.comment);
+    ze->changes.valid = 0;
 
     _zip_unchange_data(ze);
 }
diff --git a/lib/zip_entry_new.c b/lib/zip_entry_new.c
index ad5d599..b8ab272 100644
--- a/lib/zip_entry_new.c
+++ b/lib/zip_entry_new.c
@@ -1,6 +1,6 @@
 /*
   zip_entry_new.c -- create and init struct zip_entry
-  Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -45,9 +45,8 @@
     struct zip_entry *ze;
     if (!za) {
 	ze = (struct zip_entry *)malloc(sizeof(struct zip_entry));
-	if (!ze) {
+	if (!ze)
 	    return NULL;
-	}
     }
     else {
 	if (za->nentry+1 >= za->nentry_alloc) {
@@ -66,13 +65,8 @@
     }
 
     ze->state = ZIP_ST_UNCHANGED;
-
-    ze->ch_filename = NULL;
-    ze->ch_extra = NULL;
-    ze->ch_extra_len = -1;
-    ze->ch_comment = NULL;
-    ze->ch_comment_len = -1;
     ze->source = NULL;
+    ze->changes.valid = 0;
 
     if (za)
 	za->nentry++;
diff --git a/lib/zip_err_str.c b/lib/zip_err_str.c
index 8fb6003..7cf9b42 100644
--- a/lib/zip_err_str.c
+++ b/lib/zip_err_str.c
@@ -36,6 +36,7 @@
     "Read-only archive", 
     "No password provided",
     "Wrong password provided",
+    "Encoding of name and comment do not match",
 };
 
 const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
@@ -73,4 +74,5 @@
     N, 
     N,
     N,
+    N,
 };
diff --git a/lib/zip_error.c b/lib/zip_error.c
index b8d907a..d82875a 100644
--- a/lib/zip_error.c
+++ b/lib/zip_error.c
@@ -42,6 +42,9 @@
 void
 _zip_error_clear(struct zip_error *err)
 {
+    if (err == NULL)
+	return;
+
     err->zip_err = ZIP_ER_OK;
     err->sys_err = 0;
 }
diff --git a/lib/zip_error_clear.c b/lib/zip_error_clear.c
index 364383e..b4ff103 100644
--- a/lib/zip_error_clear.c
+++ b/lib/zip_error_clear.c
@@ -40,5 +40,8 @@
 ZIP_EXTERN void
 zip_error_clear(struct zip *za)
 {
+    if (za == NULL)
+	return;
+
     _zip_error_clear(&za->error);
 }
diff --git a/lib/zip_fdopen.c b/lib/zip_fdopen.c
index fec9d0c..46f078f 100644
--- a/lib/zip_fdopen.c
+++ b/lib/zip_fdopen.c
@@ -43,6 +43,11 @@
     int fd;
     FILE *fp;
 
+    if (flags & ZIP_TRUNCATE) {
+	*zep = ZIP_ER_INVAL;
+	return NULL;
+    }
+
     /* We dup() here to avoid messing with the passed in fd.
        We could not restore it to the original state in case of error. */
 
diff --git a/lib/zip_file_error_clear.c b/lib/zip_file_error_clear.c
index ef6fa10..ce8b6cb 100644
--- a/lib/zip_file_error_clear.c
+++ b/lib/zip_file_error_clear.c
@@ -40,5 +40,8 @@
 ZIP_EXTERN void
 zip_file_error_clear(struct zip_file *zf)
 {
+    if (zf == NULL)
+	return;
+
     _zip_error_clear(&zf->error);
 }
diff --git a/lib/zip_file_get_offset.c b/lib/zip_file_get_offset.c
index b96fd5e..17a47b8 100644
--- a/lib/zip_file_get_offset.c
+++ b/lib/zip_file_get_offset.c
@@ -51,7 +51,7 @@
 */
 
 unsigned int
-_zip_file_get_offset(struct zip *za, int idx)
+_zip_file_get_offset(struct zip *za, int idx, struct zip_error *ze)
 {
     struct zip_dirent de;
     unsigned int offset;
@@ -59,14 +59,14 @@
     offset = za->cdir->entry[idx].offset;
 
     if (fseeko(za->zp, offset, SEEK_SET) != 0) {
-	_zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+	_zip_error_set(ze, ZIP_ER_SEEK, errno);
 	return 0;
     }
 
-    if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, &za->error) != 0)
+    if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, ze) != 0)
 	return 0;
 
-    offset += LENTRYSIZE + de.filename_len + de.extrafield_len;
+    offset += LENTRYSIZE + strlen(de.settable.filename) + de.settable.extrafield_len;
 
     _zip_dirent_finalize(&de);
 
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c
index 2e617bf..657ed01 100644
--- a/lib/zip_fopen_index_encrypted.c
+++ b/lib/zip_fopen_index_encrypted.c
@@ -48,98 +48,10 @@
 			  const char *password)
 {
     struct zip_file *zf;
-    zip_compression_implementation comp_impl;
-    zip_encryption_implementation enc_impl;
-    struct zip_source *src, *s2;
-    zip_uint64_t start;
-    struct zip_stat st;
+    struct zip_source *src;
 
-    if (fileno >= za->nentry) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+    if ((src=_zip_source_zip_new(za, za, fileno, flags, 0, 0, password)) == NULL)
 	return NULL;
-    }
-
-    if ((flags & ZIP_FL_UNCHANGED) == 0
-	&& ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) {
-	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
-	return NULL;
-    }
-
-    if (fileno >= za->cdir->nentry) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return NULL;
-    }
-
-    if (flags & ZIP_FL_ENCRYPTED)
-	flags |= ZIP_FL_COMPRESSED;
-
-    zip_stat_index(za, fileno, flags, &st);
-
-    enc_impl = NULL;
-    if ((flags & ZIP_FL_ENCRYPTED) == 0) {
-	if (st.encryption_method != ZIP_EM_NONE) {
-	    if (password == NULL) {
-		_zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
-		return NULL;
-	    }
-	    if ((enc_impl=zip_get_encryption_implementation(
-		     st.encryption_method)) == 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)) == NULL) {
-		_zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
-		return NULL;
-	    }
-	}
-    }
-
-    if ((start=_zip_file_get_offset(za, fileno)) == 0)
-	return NULL;
-
-    if (st.comp_size == 0) {
-	if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL)
-	    return NULL;
-    }
-    else {
-	if ((src=_zip_source_file_or_p(za, NULL, za->zp, start, st.comp_size,
-				       0, &st)) == NULL)
-	    return NULL;
-	if (enc_impl) {
-	    if ((s2=enc_impl(za, src, ZIP_EM_TRAD_PKWARE, 0,
-			     password)) == NULL) {
-		zip_source_free(src);
-		/* XXX: set error (how?) */
-		return NULL;
-	    }
-	    src = s2;
-	}
-	if (comp_impl) {
-	    if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method,
-			      0)) == NULL) {
-		zip_source_free(src);
-		/* XXX: set error (how?) */
-		return NULL;
-	    }
-	    src = s2;
-	}
-	if ((flags & ZIP_FL_COMPRESSED) == 0
-	    || st.comp_method == ZIP_CM_STORE ) {
-	    if ((s2=zip_source_crc(za, src, 1)) == NULL) {
-		zip_source_free(src);
-		/* XXX: set error (how?) */
-		return NULL;
-	    }
-	    src = s2;
-	}
-    }
 
     if (zip_source_open(src) < 0) {
 	_zip_error_set_from_source(&za->error, src);
@@ -147,7 +59,10 @@
 	return NULL;
     }
 
-    zf = _zip_file_new(za);
+    if ((zf=_zip_file_new(za)) == NULL) {
+	zip_source_free(src);
+	return NULL;
+    }
 
     zf->src = src;
 
diff --git a/lib/zip_get_archive_comment.c b/lib/zip_get_archive_comment.c
index 669eb70..0a3589b 100644
--- a/lib/zip_get_archive_comment.c
+++ b/lib/zip_get_archive_comment.c
@@ -1,6 +1,6 @@
 /*
   zip_get_archive_comment.c -- get archive comment
-  Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -33,6 +33,8 @@
 
 
 
+#include <string.h>
+
 #include "zipint.h"
 
 
@@ -40,12 +42,32 @@
 ZIP_EXTERN const char *
 zip_get_archive_comment(struct zip *za, int *lenp, int flags)
 {
+    const char *ret;
     if ((flags & ZIP_FL_UNCHANGED)
 	|| (za->ch_comment_len == -1)) {
 	if (za->cdir) {
 	    if (lenp != NULL)
 		*lenp = za->cdir->comment_len;
-	    return za->cdir->comment;
+	    ret = za->cdir->comment;
+	    
+	    if (flags & ZIP_FL_NAME_RAW)
+		return ret;
+
+	    /* start guessing */
+	    if (za->cdir->comment_type == ZIP_ENCODING_UNKNOWN)
+		za->cdir->comment_type = _zip_guess_encoding(ret, za->cdir->comment_len);
+
+	    if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->comment_type != ZIP_ENCODING_ASCII))
+		|| (za->cdir->comment_type == ZIP_ENCODING_CP437)) {
+		if (za->cdir->comment_converted == NULL)
+		    za->cdir->comment_converted = _zip_cp437_to_utf8(ret, za->cdir->comment_len,
+								     &za->cdir->comment_converted_len, &za->error);
+		ret = za->cdir->comment_converted;
+		if (lenp != NULL)
+		    *lenp = za->cdir->comment_converted_len;
+	    }
+
+	    return ret;
 	}
 	else {
 	    if (lenp != NULL)
@@ -53,7 +75,8 @@
 	    return NULL;
 	}
     }
-    
+
+    /* already UTF-8, no conversion needed */
     if (lenp != NULL)
 	*lenp = za->ch_comment_len;
     return za->ch_comment;
diff --git a/lib/zip_get_file_comment.c b/lib/zip_get_file_comment.c
index b9dacbe..ee71609 100644
--- a/lib/zip_get_file_comment.c
+++ b/lib/zip_get_file_comment.c
@@ -1,6 +1,6 @@
 /*
   zip_get_file_comment.c -- get file comment
-  Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -33,6 +33,8 @@
 
 
 
+#include <string.h>
+
 #include "zipint.h"
 
 
@@ -40,19 +42,53 @@
 ZIP_EXTERN const char *
 zip_get_file_comment(struct zip *za, zip_uint64_t idx, int *lenp, int flags)
 {
+    const char *ret;
+
     if (idx >= za->nentry) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return NULL;
     }
 
-    if ((flags & ZIP_FL_UNCHANGED)
-	|| (za->entry[idx].ch_comment_len == -1)) {
+    if ((flags & ZIP_FL_UNCHANGED) || (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT) == 0) {
+	if (za->cdir == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_NOENT, 0);
+	    return NULL;
+	}
+	if (idx >= za->cdir->nentry) {
+	    _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	    return NULL;
+	}
+	    
 	if (lenp != NULL)
-	    *lenp = za->cdir->entry[idx].comment_len;
-	return za->cdir->entry[idx].comment;
+	    *lenp = za->cdir->entry[idx].settable.comment_len;
+	ret = za->cdir->entry[idx].settable.comment;
+
+	if (flags & ZIP_FL_NAME_RAW)
+	    return ret;
+
+	/* file comment already is UTF-8? */
+	if (za->cdir->entry[idx].bitflags & ZIP_GPBF_ENCODING_UTF_8)
+	    return ret;
+	
+	/* undeclared, start guessing */
+	if (za->cdir->entry[idx].fc_type == ZIP_ENCODING_UNKNOWN)
+	    za->cdir->entry[idx].fc_type = _zip_guess_encoding(ret, za->cdir->entry[idx].settable.comment_len);
+
+	if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->entry[idx].fc_type != ZIP_ENCODING_ASCII))
+	    || (za->cdir->entry[idx].fc_type == ZIP_ENCODING_CP437)) {
+	    if (za->cdir->entry[idx].comment_converted == NULL)
+		za->cdir->entry[idx].comment_converted = _zip_cp437_to_utf8(ret, za->cdir->entry[idx].settable.comment_len,
+									    &za->cdir->entry[idx].comment_converted_len, &za->error);
+	    ret = za->cdir->entry[idx].comment_converted;
+	    if (lenp != NULL)
+		*lenp = za->cdir->entry[idx].comment_converted_len;
+	}
+
+	return ret;
     }
-    
+
+    /* already UTF-8, no conversion necessary */
     if (lenp != NULL)
-	*lenp = za->entry[idx].ch_comment_len;
-    return za->entry[idx].ch_comment;
+	*lenp = za->entry[idx].changes.comment_len;
+    return za->entry[idx].changes.comment;
 }
diff --git a/lib/zip_get_file_extra.c b/lib/zip_get_file_extra.c
index afa507b..cb3d2b5 100644
--- a/lib/zip_get_file_extra.c
+++ b/lib/zip_get_file_extra.c
@@ -45,14 +45,18 @@
 	return NULL;
     }
 
-    if ((flags & ZIP_FL_UNCHANGED)
-	|| (za->entry[idx].ch_extra_len == -1)) {
+    if ((flags & ZIP_FL_UNCHANGED) || (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD) == 0) {
+	if (idx >= za->cdir->nentry) {
+	    _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	    return NULL;
+	}
+
 	if (lenp != NULL)
-	    *lenp = za->cdir->entry[idx].extrafield_len;
-	return za->cdir->entry[idx].extrafield;
+	    *lenp = za->cdir->entry[idx].settable.extrafield_len;
+	return za->cdir->entry[idx].settable.extrafield;
     }
 
     if (lenp != NULL)
-	*lenp = za->entry[idx].ch_extra_len;
-    return za->entry[idx].ch_extra;
+	*lenp = za->entry[idx].changes.extrafield_len;
+    return za->entry[idx].changes.extrafield;
 }
diff --git a/lib/zip_get_name.c b/lib/zip_get_name.c
index 531af50..7c3f7b9 100644
--- a/lib/zip_get_name.c
+++ b/lib/zip_get_name.c
@@ -1,6 +1,6 @@
 /*
   zip_get_name.c -- get filename for a file in zip file
-  Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -33,6 +33,8 @@
 
 
 
+#include <string.h>
+
 #include "zipint.h"
 
 
@@ -49,6 +51,10 @@
 _zip_get_name(struct zip *za, zip_uint64_t idx, int flags,
 	      struct zip_error *error)
 {
+    enum zip_encoding_type enc;
+    const char *ret;
+
+    ret = NULL;
     if (idx >= za->nentry) {
 	_zip_error_set(error, ZIP_ER_INVAL, 0);
 	return NULL;
@@ -59,14 +65,34 @@
 	    _zip_error_set(error, ZIP_ER_DELETED, 0);
 	    return NULL;
 	}
-	if (za->entry[idx].ch_filename)
-	    return za->entry[idx].ch_filename;
+	if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME)
+	    return za->entry[idx].changes.filename; /* must be UTF-8 */
     }
 
+    /* XXX: read Infozip UTF-8 Extension 0x7075 file name? */
     if (za->cdir == NULL || idx >= za->cdir->nentry) {
 	_zip_error_set(error, ZIP_ER_INVAL, 0);
 	return NULL;
     }
-    
-    return za->cdir->entry[idx].filename;
+    ret = za->cdir->entry[idx].settable.filename;
+
+    if (flags & ZIP_FL_NAME_RAW)
+	return ret;
+
+    /* file name already is UTF-8? */
+    if (za->cdir->entry[idx].bitflags & ZIP_GPBF_ENCODING_UTF_8)
+	return ret;
+
+    /* undeclared, start guessing */
+    if (za->cdir->entry[idx].fn_type == ZIP_ENCODING_UNKNOWN)
+	za->cdir->entry[idx].fn_type = _zip_guess_encoding(ret, strlen(ret));
+
+    if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->entry[idx].fn_type != ZIP_ENCODING_ASCII))
+	|| (za->cdir->entry[idx].fn_type == ZIP_ENCODING_CP437)) {
+	if (za->cdir->entry[idx].filename_converted == NULL)
+	    za->cdir->entry[idx].filename_converted = _zip_cp437_to_utf8(ret, strlen(ret), NULL, error);
+	ret = za->cdir->entry[idx].filename_converted;
+    }
+
+    return ret;
 }
diff --git a/lib/zip_memdup.c b/lib/zip_memdup.c
index 641125e..06af2da 100644
--- a/lib/zip_memdup.c
+++ b/lib/zip_memdup.c
@@ -1,6 +1,6 @@
 /*
   zip_memdup.c -- internal zip function, "strdup" with len
-  Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -43,6 +43,9 @@
 {
     void *ret;
 
+    if (len == 0)
+	return NULL;
+
     ret = malloc(len);
     if (!ret) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
diff --git a/lib/zip_name_locate.c b/lib/zip_name_locate.c
index 1f7081b..44e3c85 100644
--- a/lib/zip_name_locate.c
+++ b/lib/zip_name_locate.c
@@ -72,12 +72,9 @@
 
     n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry;
     for (i=0; i<n; i++) {
-	if (flags & ZIP_FL_UNCHANGED)
-	    fn = za->cdir->entry[i].filename;
-	else
-	    fn = _zip_get_name(za, i, flags, error);
+	fn = _zip_get_name(za, i, flags, error);
 
-	/* newly added (partially filled) entry */
+	/* newly added (partially filled) entry or error */
 	if (fn == NULL)
 	    continue;
 	
@@ -87,8 +84,10 @@
 		fn = p+1;
 	}
 
-	if (cmp(fname, fn) == 0)
+	if (cmp(fname, fn) == 0) {
+	    _zip_error_clear(error);
 	    return i;
+	}
     }
 
     _zip_error_set(error, ZIP_ER_NOENT, 0);
diff --git a/lib/zip_open.c b/lib/zip_open.c
index e9dfa3a..7aebdd3 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -1,6 +1,6 @@
 /*
   zip_open.c -- open zip archive by name
-  Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -43,7 +43,7 @@
 #include "zipint.h"
 
 static void set_error(int *, struct zip_error *, int);
-static struct zip *_zip_allocate_new(const char *, int *);
+static struct zip *_zip_allocate_new(const char *, int, int *);
 static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
 static void _zip_check_torrentzip(struct zip *);
 static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, off_t);
@@ -66,8 +66,18 @@
     case -1:
 	return NULL;
     case 0:
-	return _zip_allocate_new(fn, zep);
+	return _zip_allocate_new(fn, flags, zep);
     default:
+	if (flags & ZIP_TRUNCATE) {
+	    FILE *f;
+	    
+	    if ((f = fopen(fn, "rb")) == NULL) {
+		set_error(zep, NULL, ZIP_ER_OPEN);
+		return NULL;
+	    }
+	    fclose(f);
+	    return _zip_allocate_new(fn, flags, zep);
+	}
 	break;
     }
 
@@ -97,7 +107,7 @@
 
     /* treat empty files as empty archives */
     if (len == 0) {
-	if ((za=_zip_allocate_new(fn, zep)) == NULL)
+	if ((za=_zip_allocate_new(fn, flags, zep)) == NULL)
 	    fclose(fp);
 	else
 	    za->zp = fp;
@@ -110,7 +120,7 @@
 	return NULL;
     }
 
-    if ((za=_zip_allocate_new(fn, zep)) == NULL) {
+    if ((za=_zip_allocate_new(fn, flags, zep)) == NULL) {
 	_zip_cdir_free(cdir);
 	fclose(fp);
 	return NULL;
@@ -119,10 +129,12 @@
     za->cdir = cdir;
     za->zp = fp;
 
-    if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
-					      * cdir->nentry)) == NULL) {
+    if (cdir->nentry == 0)
+	za->entry = NULL;
+    else if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
+						   * cdir->nentry)) == NULL) {
 	set_error(zep, NULL, ZIP_ER_MEMORY);
-	_zip_free(za);
+	zip_discard(za);
 	return NULL;
     }
     for (i=0; i<cdir->nentry; i++)
@@ -275,7 +287,6 @@
 	    }
 	}
     }
-
     cd->nentry = i;
     
     return cd;
@@ -312,7 +323,7 @@
 	}
 	
 	j = cd->entry[i].offset + cd->entry[i].comp_size
-	    + cd->entry[i].filename_len + LENTRYSIZE;
+	    + strlen(cd->entry[i].settable.filename) + LENTRYSIZE;
 	if (j > max)
 	    max = j;
 	if (max > cd->offset) {
@@ -391,11 +402,9 @@
 	   and global headers for the bitflags */
 	|| (h1->bitflags != h2->bitflags)
 #endif
-	|| (h1->comp_method != h2->comp_method)
+	|| (h1->settable.comp_method != h2->settable.comp_method)
 	|| (h1->last_mod != h2->last_mod)
-	|| (h1->filename_len != h2->filename_len)
-	|| !h1->filename || !h2->filename
-	|| strcmp(h1->filename, h2->filename))
+	|| strcmp(h1->settable.filename, h2->settable.filename))
 	return -1;
 
     /* check that CRC and sizes are zero if data descriptor is used */
@@ -420,10 +429,10 @@
     }
     
     if ((local1p == local2p)
-	&& ((h1->extrafield_len != h2->extrafield_len)
-	    || (h1->extrafield_len && h2->extrafield
-		&& memcmp(h1->extrafield, h2->extrafield,
-			  h1->extrafield_len))))
+	&& ((h1->settable.extrafield_len != h2->settable.extrafield_len)
+	    || (h1->settable.extrafield_len && h2->settable.extrafield
+		&& memcmp(h1->settable.extrafield, h2->settable.extrafield,
+			  h1->settable.extrafield_len))))
 	return -1;
 
     /* if either is local, nothing more to check */
@@ -435,9 +444,9 @@
 	|| (h1->int_attrib != h2->int_attrib)
 	|| (h1->ext_attrib != h2->ext_attrib)
 	|| (h1->offset != h2->offset)
-	|| (h1->comment_len != h2->comment_len)
-	|| (h1->comment_len && h2->comment
-	    && memcmp(h1->comment, h2->comment, h1->comment_len)))
+	|| (h1->settable.comment_len != h2->settable.comment_len)
+	|| (h1->settable.comment_len && h2->settable.comment
+	    && memcmp(h1->settable.comment, h2->settable.comment, h1->settable.comment_len)))
 	return -1;
 
     return 0;
@@ -446,7 +455,7 @@
 
 
 static struct zip *
-_zip_allocate_new(const char *fn, int *zep)
+_zip_allocate_new(const char *fn, int flags, int *zep)
 {
     struct zip *za;
     struct zip_error error;
@@ -461,11 +470,12 @@
     else {
 	za->zn = strdup(fn);
 	if (!za->zn) {
-	    _zip_free(za);
+	    zip_discard(za);
 	    set_error(zep, NULL, ZIP_ER_MEMORY);
 	    return NULL;
 	}
     }
+    za->open_flags = flags;
     return za;
 }
 
diff --git a/lib/zip_rename.c b/lib/zip_rename.c
index d78bbe8..ea2e676 100644
--- a/lib/zip_rename.c
+++ b/lib/zip_rename.c
@@ -45,7 +45,7 @@
     const char *old_name;
     int old_is_dir, new_is_dir;
     
-    if (idx >= za->nentry || name[0] == '\0') {
+    if (idx >= za->nentry || name == NULL || strlen(name) > ZIP_UINT16_MAX) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return -1;
     }
diff --git a/lib/zip_replace.c b/lib/zip_replace.c
index c444e78..e8249f9 100644
--- a/lib/zip_replace.c
+++ b/lib/zip_replace.c
@@ -60,23 +60,31 @@
 _zip_replace(struct zip *za, zip_uint64_t idx, const char *name,
 	     struct zip_source *source)
 {
+    zip_uint64_t za_nentry_prev;
     if (ZIP_IS_RDONLY(za)) {
 	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
 	return -1;
     }
 
+    za_nentry_prev = za->nentry;
     if (idx == ZIP_UINT64_MAX) {
 	if (_zip_entry_new(za) == NULL)
 	    return -1;
-
+	
 	idx = za->nentry - 1;
+	za->entry[idx].changes.valid |= ZIP_DIRENT_COMP_METHOD;
+	za->entry[idx].changes.comp_method = ZIP_CM_DEFLATE; /* XXX: default */
     }
     
+    if (name && _zip_set_name(za, idx, name) != 0) {
+	za->nentry = za_nentry_prev;
+	return -1;
+    }
+
+    /* does not change any name related data, so we can do it here;
+     * needed for a double add of the same file name */
     _zip_unchange_data(za->entry+idx);
 
-    if (name && _zip_set_name(za, idx, name) != 0)
-	return -1;
-    
     za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry)
 			    ? ZIP_ST_ADDED : ZIP_ST_REPLACED);
     za->entry[idx].source = source;
diff --git a/lib/zip_set_archive_comment.c b/lib/zip_set_archive_comment.c
index 3bb85d1..bbb9a73 100644
--- a/lib/zip_set_archive_comment.c
+++ b/lib/zip_set_archive_comment.c
@@ -1,6 +1,6 @@
 /*
   zip_set_archive_comment.c -- set archive comment
-  Copyright (C) 2006-2009 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -55,6 +55,11 @@
 	return -1;
     }
 
+    if (_zip_guess_encoding(comment, len) == ZIP_ENCODING_CP437) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
     if (len > 0) {
 	if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL)
 	    return -1;
diff --git a/lib/zip_set_file_comment.c b/lib/zip_set_file_comment.c
index 6ae76a0..bccad10 100644
--- a/lib/zip_set_file_comment.c
+++ b/lib/zip_set_file_comment.c
@@ -1,6 +1,6 @@
 /*
   zip_set_file_comment.c -- set comment for file in archive
-  Copyright (C) 2006-2009 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -34,6 +34,7 @@
 
 
 #include <stdlib.h>
+#include <string.h>
 
 #include "zipint.h"
 
@@ -44,6 +45,8 @@
 		     const char *comment, int len)
 {
     char *tmpcom;
+    const char *name;
+    enum zip_encoding_type com_enc, enc;
 
     if (idx >= za->nentry
 	|| len < 0 || len > MAXCOMLEN
@@ -57,6 +60,20 @@
 	return -1;
     }
 
+    if ((com_enc=_zip_guess_encoding(comment, len)) == ZIP_ENCODING_CP437) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    if ((name=zip_get_name(za, idx, ZIP_FL_NAME_RAW)) == NULL)
+	return -1;
+    enc = _zip_guess_encoding(name, strlen(name));
+
+    if (enc == ZIP_ENCODING_CP437 && com_enc == ZIP_ENCODING_UTF8) {
+	_zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0);
+	return -1;
+    }
+
     if (len > 0) {
 	if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL)
 	    return -1;
@@ -64,9 +81,11 @@
     else
 	tmpcom = NULL;
 
-    free(za->entry[idx].ch_comment);
-    za->entry[idx].ch_comment = tmpcom;
-    za->entry[idx].ch_comment_len = len;
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT)
+	free(za->entry[idx].changes.comment);
+    za->entry[idx].changes.comment = tmpcom;
+    za->entry[idx].changes.comment_len = len;
+    za->entry[idx].changes.valid |= ZIP_DIRENT_COMMENT;
     
     return 0;
 }
diff --git a/lib/zip_free.c b/lib/zip_set_file_compression.c
similarity index 60%
copy from lib/zip_free.c
copy to lib/zip_set_file_compression.c
index 9932c14..25cb5a0 100644
--- a/lib/zip_free.c
+++ b/lib/zip_set_file_compression.c
@@ -1,6 +1,6 @@
 /*
-  zip_free.c -- free struct zip
-  Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+  zip_set_file_compression.c -- set compression for file in archive
+  Copyright (C) 2012 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>
@@ -33,51 +33,41 @@
 
 
 
-#include <stdlib.h>
-
 #include "zipint.h"
 
 
 
-/* _zip_free:
-   frees the space allocated to a zipfile struct, and closes the
-   corresponding file. */
-
-void
-_zip_free(struct zip *za)
+ZIP_EXTERN int
+zip_set_file_compression(struct zip *za, zip_uint64_t idx,
+			 zip_int32_t method, zip_uint32_t flags)
 {
-    int i;
-
-    if (za == NULL)
-	return;
-
-    if (za->zn)
-	free(za->zn);
-
-    if (za->zp)
-	fclose(za->zp);
-
-    free(za->default_password);
-    _zip_cdir_free(za->cdir);
-    free(za->ch_comment);
-
-    if (za->entry) {
-	for (i=0; i<za->nentry; i++) {
-	    _zip_entry_free(za->entry+i);
-	}
-	free(za->entry);
+    if (idx >= za->nentry) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
     }
 
-    for (i=0; i<za->nfile; i++) {
-	if (za->file[i]->error.zip_err == ZIP_ER_OK) {
-	    _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0);
-	    za->file[i]->za = NULL;
-	}
+    if (method != ZIP_CM_DEFAULT && method != ZIP_CM_STORE && method != ZIP_CM_DEFLATE) {
+	_zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+	return -1;
     }
 
-    free(za->file);
+    if (ZIP_IS_RDONLY(za)) {
+	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+	return -1;
+    }
+
+    /* XXX: needs support for better of deflate/store
+     *      update man page when fixing this */
+    if (method == ZIP_CM_DEFAULT)
+	method = ZIP_CM_DEFLATE;
+
+    if (za->cdir != NULL && idx < za->cdir->nentry &&
+	method == za->cdir->entry[idx].settable.comp_method)
+	za->entry[idx].changes.valid &= ~ZIP_DIRENT_COMP_METHOD;
+    else {
+	za->entry[idx].changes.valid |= ZIP_DIRENT_COMP_METHOD;
+	za->entry[idx].changes.comp_method = method;
+    }
     
-    free(za);
-
-    return;
+    return 0;
 }
diff --git a/lib/zip_set_file_extra.c b/lib/zip_set_file_extra.c
index 9b80bde..1a85bff 100644
--- a/lib/zip_set_file_extra.c
+++ b/lib/zip_set_file_extra.c
@@ -64,9 +64,11 @@
     else
 	tmpext = NULL;
 
-    free(za->entry[idx].ch_extra);
-    za->entry[idx].ch_extra = tmpext;
-    za->entry[idx].ch_extra_len = len;
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD)
+	free(za->entry[idx].changes.extrafield);
+    za->entry[idx].changes.extrafield = tmpext;
+    za->entry[idx].changes.extrafield_len = len;
+    za->entry[idx].changes.valid |= ZIP_DIRENT_EXTRAFIELD;
 
     return 0;
 }
diff --git a/lib/zip_set_name.c b/lib/zip_set_name.c
index 2a90601..7b43131 100644
--- a/lib/zip_set_name.c
+++ b/lib/zip_set_name.c
@@ -1,6 +1,6 @@
 /*
   zip_set_name.c -- rename helper function
-  Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -44,13 +44,21 @@
 _zip_set_name(struct zip *za, zip_uint64_t idx, const char *name)
 {
     char *s;
+    const char *com;
+    int comlen;
     zip_int64_t i;
+    enum zip_encoding_type enc, com_enc;
     
     if (idx >= za->nentry || name == NULL) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return -1;
     }
 
+    if ((enc=_zip_guess_encoding(name, strlen(name))) == ZIP_ENCODING_CP437) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
     if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) {
 	_zip_error_set(&za->error, ZIP_ER_EXISTS, 0);
 	return -1;
@@ -59,7 +67,17 @@
     /* no effective name change */
     if (i == idx)
 	return 0;
-    
+
+    com = zip_get_file_comment(za, idx, &comlen, ZIP_FL_NAME_RAW);
+    if (com == NULL)
+	com_enc = ZIP_ENCODING_ASCII;
+    else
+	com_enc = _zip_guess_encoding(com, comlen);
+    if (com_enc == ZIP_ENCODING_CP437 && enc == ZIP_ENCODING_UTF8) {
+	_zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0);
+	return -1;
+    }
+
     if ((s=strdup(name)) == NULL) {
 	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 	return -1;
@@ -68,8 +86,10 @@
     if (za->entry[idx].state == ZIP_ST_UNCHANGED) 
 	za->entry[idx].state = ZIP_ST_RENAMED;
 
-    free(za->entry[idx].ch_filename);
-    za->entry[idx].ch_filename = s;
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME)
+	free(za->entry[idx].changes.filename);
+    za->entry[idx].changes.filename = s;
+    za->entry[idx].changes.valid |= ZIP_DIRENT_FILENAME;
 
     return 0;
 }
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 7e26ff6..8c75c7b 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -65,7 +65,7 @@
     if (za == NULL)
 	return NULL;
 
-    if (file == NULL || start < 0 || len < -1) {
+    if (file == NULL || len < -1) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return NULL;
     }
diff --git a/lib/zip_source_window.c b/lib/zip_source_window.c
new file mode 100644
index 0000000..0f8f1a9
--- /dev/null
+++ b/lib/zip_source_window.c
@@ -0,0 +1,149 @@
+/*
+  zip_source_window.c -- return part of lower source
+  Copyright (C) 2012 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 "zipint.h"
+
+struct window {
+    zip_uint64_t skip;
+    zip_uint64_t len;
+    zip_uint64_t left;
+    int e[2];
+};
+
+static zip_int64_t window_read(struct zip_source *, void *, void *,
+			       zip_uint64_t, enum zip_source_cmd);
+
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_window(struct zip *za, struct zip_source *src, zip_uint64_t start, zip_uint64_t len)
+{
+    struct window *ctx;
+
+    if (src == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+
+    if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+	return NULL;
+    }
+
+    ctx->skip = start;
+    ctx->len = len;
+    ctx->left = len;
+
+    return zip_source_layered(za, src, window_read, ctx);
+}
+
+
+
+static zip_int64_t
+window_read(struct zip_source *src, void *_ctx, void *data,
+	    zip_uint64_t len, enum zip_source_cmd cmd)
+{
+    struct window *ctx;
+    zip_int64_t i, n;
+    char b[8192];
+
+    ctx = (struct window *)_ctx;
+
+    switch (cmd) {
+    case ZIP_SOURCE_OPEN:
+	for (n=0; n<ctx->skip; n+=i) {
+	    i = (ctx->skip-n > sizeof(b) ? sizeof(b) : ctx->skip-n);
+	    if ((i=zip_source_read(src, b, i)) < 0)
+		return ZIP_SOURCE_ERR_LOWER;
+	    if (i==0) {
+		ctx->e[0] = ZIP_ER_EOF;
+		ctx->e[1] = 0;
+		return -1;
+	    }
+	}
+	return 0;
+
+    case ZIP_SOURCE_READ:
+	if (len > ctx->left)
+	    len = ctx->left;
+	
+	if (len <= 0)
+	    return 0;
+
+	if ((n=zip_source_read(src, data, len)) < 0)
+	    return ZIP_SOURCE_ERR_LOWER;
+
+	ctx->left -= n;
+
+	if (n == 0) {
+	    if (ctx->left > 0) {
+		ctx->e[0] = ZIP_ER_EOF;
+		ctx->e[1] = 0;
+		return -1;
+	    }
+	}
+	return n;
+
+    case ZIP_SOURCE_CLOSE:
+	return 0;
+
+    case ZIP_SOURCE_STAT:
+	{
+	    struct zip_stat *st;
+
+	    st = (struct zip_stat *)data;
+
+	    st->size = ctx->len;
+	    st->valid |= ZIP_STAT_SIZE;
+	    st->valid &= ~(ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE);
+	}
+	return 0;
+	
+    case ZIP_SOURCE_ERROR:
+	memcpy(data, ctx->e, sizeof(ctx->e));
+	return 0;
+
+    case ZIP_SOURCE_FREE:
+	free(ctx);
+	return 0;
+
+    default:
+	return -1;
+    }
+    
+}
diff --git a/lib/zip_source_zip.c b/lib/zip_source_zip.c
index 2b9061f..7426c4b 100644
--- a/lib/zip_source_zip.c
+++ b/lib/zip_source_zip.c
@@ -38,153 +38,19 @@
 
 #include "zipint.h"
 
-struct read_zip {
-    struct zip_file *zf;
-    struct zip_stat st;
-    zip_uint64_t off;
-    zip_int64_t len;
-};
-
-static zip_int64_t read_zip(void *st, void *data, zip_uint64_t len,
-			enum zip_source_cmd cmd);
-
 
 
 ZIP_EXTERN struct zip_source *
 zip_source_zip(struct zip *za, struct zip *srcza, zip_uint64_t srcidx,
 	       int flags, zip_uint64_t start, zip_int64_t len)
 {
-    struct zip_error error;
-    struct zip_source *zs;
-    struct read_zip *p;
-
-    /* XXX: ZIP_FL_RECOMPRESS */
-
-    if (za == NULL)
-	return NULL;
-
-    if (srcza == NULL || len < -1 || srcidx < 0 || srcidx >= srcza->nentry) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return NULL;
-    }
-
-    if ((flags & ZIP_FL_UNCHANGED) == 0
-	&& ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) {
-	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
-	return NULL;
-    }
-
     if (len == 0)
 	len = -1;
 
-    if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0)
+    if (start == 0 && len == -1)
 	flags |= ZIP_FL_COMPRESSED;
     else
 	flags &= ~ZIP_FL_COMPRESSED;
 
-    if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) {
-	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
-	return NULL;
-    }
-	
-    _zip_error_copy(&error, &srcza->error);
-	
-    if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0
-	|| (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) {
-	free(p);
-	_zip_error_copy(&za->error, &srcza->error);
-	_zip_error_copy(&srcza->error, &error);
-	
-	return NULL;
-    }
-    p->off = start;
-    p->len = len;
-
-    if ((flags & ZIP_FL_COMPRESSED) == 0) {
-	p->st.size = p->st.comp_size = len;
-	p->st.comp_method = ZIP_CM_STORE;
-	p->st.crc = 0;
-    }
-    
-    if ((zs=zip_source_function(za, read_zip, p)) == NULL) {
-	free(p);
-	return NULL;
-    }
-
-    return zs;
-}
-
-
-
-static zip_int64_t
-read_zip(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd)
-{
-    struct read_zip *z;
-    char b[8192], *buf;
-    int i;
-    zip_uint64_t n;
-
-    z = (struct read_zip *)state;
-    buf = (char *)data;
-
-    switch (cmd) {
-    case ZIP_SOURCE_OPEN:
-	for (n=0; n<z->off; n+= i) {
-	    i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n);
-	    if ((i=zip_fread(z->zf, b, i)) < 0) {
-		zip_fclose(z->zf);
-		z->zf = NULL;
-		return -1;
-	    }
-	}
-	return 0;
-	
-    case ZIP_SOURCE_READ:
-	if (z->len != -1)
-	    n = len > z->len ? z->len : len;
-	else
-	    n = len;
-	
-
-	if ((i=zip_fread(z->zf, buf, n)) < 0)
-	    return -1;
-
-	if (z->len != -1)
-	    z->len -= i;
-
-	return i;
-	
-    case ZIP_SOURCE_CLOSE:
-	return 0;
-
-    case ZIP_SOURCE_STAT:
-	if (len < sizeof(z->st))
-	    return -1;
-	len = sizeof(z->st);
-
-	memcpy(data, &z->st, len);
-	return len;
-
-    case ZIP_SOURCE_ERROR:
-	{
-	    int *e;
-
-	    if (len < sizeof(int)*2)
-		return -1;
-
-	    e = (int *)data;
-	    zip_file_error_get(z->zf, e, e+1);
-	}
-	return sizeof(int)*2;
-
-    case ZIP_SOURCE_FREE:
-	zip_fclose(z->zf);
-	free(z);
-	return 0;
-
-    default:
-	;
-    }
-
-    return -1;
+    return _zip_source_zip_new(za, srcza, srcidx, flags, start, len, NULL);
 }
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c
new file mode 100644
index 0000000..b5364a1
--- /dev/null
+++ b/lib/zip_source_zip_new.c
@@ -0,0 +1,175 @@
+/*
+  zip_source_zip_new.c -- prepare data structures for zip_fopen/zip_source_zip
+  Copyright (C) 2012 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 "zipint.h"
+
+
+
+struct zip_source *
+_zip_source_zip_new(struct zip *za, struct zip *srcza, zip_uint64_t srcidx, int flags,
+		    zip_uint64_t start, zip_int64_t len, const char *password)
+{
+    zip_compression_implementation comp_impl;
+    zip_encryption_implementation enc_impl;
+    struct zip_source *src, *s2;
+    zip_uint64_t offset;
+    struct zip_stat st;
+
+    if (za == NULL)
+	return NULL;
+
+    if (srcza == NULL || len < -1 || srcidx >= srcza->nentry) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+	&& (ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx) || srcza->entry[srcidx].state == ZIP_ST_DELETED)) {
+	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
+	return NULL;
+    }
+
+    if (srcza->cdir == NULL || srcidx >= srcza->cdir->nentry) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+
+    if (flags & ZIP_FL_ENCRYPTED)
+	flags |= ZIP_FL_COMPRESSED;
+
+    if ((start > 0 || len > 0) && (flags & ZIP_FL_COMPRESSED)) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+
+    if (zip_stat_index(srcza, srcidx, flags, &st) < 0) {
+	_zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
+	return NULL;
+    }
+
+    if (len == -1)
+	len = 0;
+
+    /* overflow or past end of file */
+    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 (password == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
+	    return NULL;
+	}
+	if ((enc_impl=zip_get_encryption_implementation(
+		 st.encryption_method)) == 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)) == 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) {
+	if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL)
+	    return NULL;
+    }
+    else {
+	if (start+len > 0 && enc_impl == NULL && comp_impl == NULL) {
+	    if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset+start,
+					   len ? len : st.size-start,
+					   0, &st)) == NULL)
+		return NULL;
+	}
+	else {
+	    if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset, st.comp_size,
+					   0, &st)) == NULL)
+		return NULL;
+	}
+	
+	if (enc_impl) {
+	    if ((s2=enc_impl(za, src, st.encryption_method, 0, password)) == NULL) {
+		zip_source_free(src);
+		/* XXX: set error (how?) */
+		return NULL;
+	    }
+	    src = s2;
+	}
+	if (comp_impl) {
+	    if ((s2=comp_impl(za, src, st.comp_method, 0)) == NULL) {
+		zip_source_free(src);
+		/* XXX: set error (how?) */
+		return NULL;
+	    }
+	    src = s2;
+	}
+	if (((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE)
+	    && (len == 0 || start+len == st.comp_size)) {
+	    /* when reading the whole file, check for crc errors */
+	    if ((s2=zip_source_crc(za, src, 1)) == NULL) {
+		zip_source_free(src);
+		/* XXX: set error (how?) */
+		return NULL;
+	    }
+	    src = s2;
+	}
+
+	if (start+len > 0 && (comp_impl || enc_impl)) {
+	    if ((s2=zip_source_window(za, src, start, len ? len : st.size-start)) == NULL) {
+		zip_source_free(src);
+		/* XXX: set error (how?) (why?) */
+		return NULL;
+	    }
+	    src = s2;
+	}
+    }
+
+    return src;
+}
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c
index 0e15b55..771c686 100644
--- a/lib/zip_stat_index.c
+++ b/lib/zip_stat_index.c
@@ -71,7 +71,10 @@
 	st->size = za->cdir->entry[index].uncomp_size;
 	st->mtime = za->cdir->entry[index].last_mod;
 	st->comp_size = za->cdir->entry[index].comp_size;
-	st->comp_method = za->cdir->entry[index].comp_method;
+	if ((flags & ZIP_FL_UNCHANGED) == 0 && (za->entry[index].changes.valid & ZIP_DIRENT_COMP_METHOD))
+	    st->comp_method = za->entry[index].changes.comp_method;
+	else
+	    st->comp_method = za->cdir->entry[index].settable.comp_method;
 	if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) {
 	    if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) {
 		/* XXX */
diff --git a/lib/zip_unchange.c b/lib/zip_unchange.c
index e64186e..61adf50 100644
--- a/lib/zip_unchange.c
+++ b/lib/zip_unchange.c
@@ -57,7 +57,7 @@
 	return -1;
     }
 
-    if (za->entry[idx].ch_filename) {
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME) {
 	if (!allow_duplicates) {
 	    i = _zip_name_locate(za,
 			 _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL),
@@ -68,16 +68,14 @@
 	    }
 	}
 
-	free(za->entry[idx].ch_filename);
-	za->entry[idx].ch_filename = NULL;
+	free(za->entry[idx].changes.filename);
     }
 
-    free(za->entry[idx].ch_extra);
-    za->entry[idx].ch_extra = NULL;
-    za->entry[idx].ch_extra_len = -1;
-    free(za->entry[idx].ch_comment);
-    za->entry[idx].ch_comment = NULL;
-    za->entry[idx].ch_comment_len = -1;
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD)
+	free(za->entry[idx].changes.extrafield);
+    if (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT)
+	free(za->entry[idx].changes.comment);
+    za->entry[idx].changes.valid = 0;
 
     _zip_unchange_data(za->entry+idx);
 
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c
index 431f2d0..fab51de 100644
--- a/lib/zip_unchange_data.c
+++ b/lib/zip_unchange_data.c
@@ -45,6 +45,6 @@
 	ze->source = NULL;
     }
     
-    ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED;
+    ze->state = (ze->changes.valid & ZIP_DIRENT_FILENAME) ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED;
 }
 
diff --git a/lib/zip_utf-8.c b/lib/zip_utf-8.c
new file mode 100644
index 0000000..ab49169
--- /dev/null
+++ b/lib/zip_utf-8.c
@@ -0,0 +1,229 @@
+/*
+  zip_utf-8.c -- UTF-8 support functions for libzip
+  Copyright (C) 2011-2012 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 "zip.h"
+#include "zipint.h"
+
+#include <stdlib.h>
+
+
+
+static const zip_uint16_t _cp437_to_unicode[256] = {
+    /* 0x00 - 0x0F */
+    0x2007, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
+    0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
+
+    /* 0x10 - 0x1F */
+    0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
+    0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
+
+    /* 0x20 - 0x2F */
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+
+    /* 0x30 - 0x3F */
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+
+    /* 0x40 - 0x4F */
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+
+    /* 0x50 - 0x5F */
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+
+    /* 0x60 - 0x6F */
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+
+    /* 0x70 - 0x7F */
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302,
+
+    /* 0x80 - 0x8F */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+
+    /* 0x90 - 0x9F */
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+
+    /* 0xA0 - 0xAF */
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+
+    /* 0xB0 - 0xBF */
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+
+    /* 0xC0 - 0xCF */
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+
+    /* 0xD0 - 0xDF */
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+
+    /* 0xE0 - 0xEF */
+    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+    0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+
+    /* 0xF0 - 0xFF */
+    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#define UTF_8_LEN_2_MASK     0xe0
+#define UTF_8_LEN_2_MATCH    0xc0
+#define UTF_8_LEN_3_MASK     0xf0
+#define UTF_8_LEN_3_MATCH    0xe0
+#define UTF_8_LEN_4_MASK     0xf8
+#define UTF_8_LEN_4_MATCH    0xf0
+#define UTF_8_CONTINUE_MASK  0xc0
+#define UTF_8_CONTINUE_MATCH 0x80
+
+
+
+enum zip_encoding_type
+_zip_guess_encoding(const zip_uint8_t * const name, zip_uint32_t len)
+{
+    zip_uint32_t i;
+    int ret;
+    int j, ulen;
+
+    ret = ZIP_ENCODING_ASCII;
+    for (i=0; i<len; i++) {
+	if ((name[i] > 31 && name[i] < 128) || name[i] == '\r' || name[i] == '\n' || name[i] == '\t')
+	    continue;
+
+	ret = ZIP_ENCODING_UTF8;
+	if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH)
+	    ulen = 1;
+	else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH)
+	    ulen = 2;
+	else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH)
+	    ulen = 3;
+	else
+	    return ZIP_ENCODING_CP437;
+
+	if (i + ulen >= len)
+	    return ZIP_ENCODING_CP437;
+
+	for (j=1; j<=ulen; j++) {
+	    if ((name[i+j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH)
+		return ZIP_ENCODING_CP437;
+	}
+	i += ulen;
+    }
+
+    return ret;
+}
+
+
+
+static zip_uint32_t
+_zip_unicode_to_utf8_len(zip_uint32_t codepoint)
+{
+    if (codepoint < 0x0080)
+	return 1;
+    if (codepoint < 0x0800)
+	return 2;
+    if (codepoint < 0x10000)
+	return 3;
+    return 4;
+}
+
+
+
+static zip_uint32_t
+_zip_unicode_to_utf8(zip_uint32_t codepoint, zip_uint8_t *buf)
+{
+    if (codepoint < 0x0080) {
+	buf[0] = codepoint & 0xff;
+	return 1;
+    }
+    if (codepoint < 0x0800) {
+	buf[0] = UTF_8_LEN_2_MATCH | ((codepoint >> 6) & 0x1f);
+	buf[1] = UTF_8_CONTINUE_MATCH | (codepoint & 0x3f);
+	return 2;
+    }
+    if (codepoint < 0x10000) {
+	buf[0] = UTF_8_LEN_3_MATCH | ((codepoint >> 12) & 0x0f);
+	buf[1] = UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f);
+	buf[2] = UTF_8_CONTINUE_MATCH | (codepoint & 0x3f);
+	return 3;
+    }
+    buf[0] = UTF_8_LEN_4_MATCH | ((codepoint >> 18) & 0x07);
+    buf[1] = UTF_8_CONTINUE_MATCH | ((codepoint >> 12) & 0x3f);
+    buf[2] = UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f);
+    buf[3] = UTF_8_CONTINUE_MATCH | (codepoint & 0x3f);
+    return 4;
+}
+
+
+
+zip_uint8_t *
+_zip_cp437_to_utf8(const zip_uint8_t * const cp437buf, zip_uint32_t len,
+		   zip_uint32_t *utf8_lenp, struct zip_error *error)
+{
+    zip_uint8_t *utf8buf;
+    zip_uint32_t buflen, i, offset;
+
+    if (len == 0) {
+	if (utf8_lenp)
+	    *utf8_lenp = 0;
+	return NULL;
+    }
+
+    buflen = 1;
+    for (i=0; i<len; i++)
+	buflen += _zip_unicode_to_utf8_len(_cp437_to_unicode[cp437buf[i]]);
+
+    if ((utf8buf=(zip_uint8_t*)malloc(buflen)) == NULL) {
+	_zip_error_set(error, ZIP_ER_MEMORY, 0);
+	return NULL;
+    }
+
+    offset = 0;
+    for (i=0; i<len; i++)
+	offset += _zip_unicode_to_utf8(_cp437_to_unicode[cp437buf[i]],
+				       utf8buf+offset);
+
+    utf8buf[buflen-1] = 0;
+    if (utf8_lenp)
+	*utf8_lenp = buflen-1;
+    return utf8buf;
+}
diff --git a/lib/zipint.h b/lib/zipint.h
index 2f748bd..895fbbf 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -3,7 +3,7 @@
 
 /*
   zipint.h -- internal declarations.
-  Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2012 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>
@@ -160,6 +160,8 @@
 ZIP_EXTERN zip_int64_t zip_source_read(struct zip_source *, void *,
 				       zip_uint64_t);
 ZIP_EXTERN int zip_source_stat(struct zip_source *, struct zip_stat *);
+ZIP_EXTERN struct zip_source *zip_source_window(struct zip *, struct zip_source *,
+						zip_uint64_t, zip_uint64_t);
 
 
 /* This function will probably remain private.  It is not needed to
@@ -184,6 +186,15 @@
 #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 */
+
+/* encoding type */
+enum zip_encoding_type {
+    ZIP_ENCODING_UNKNOWN, /* not yet analyzed */
+    ZIP_ENCODING_ASCII,   /* plain ASCII */
+    ZIP_ENCODING_UTF8,    /* possibly UTF-8 */
+    ZIP_ENCODING_CP437    /* Code Page 437 */
+};
 
 /* error information */
 
@@ -198,6 +209,7 @@
 struct zip {
     char *zn;			/* file name */
     FILE *zp;			/* file */
+    int open_flags;		/* flags passed to zip_open */
     struct zip_error error;	/* error information */
 
     unsigned int flags;		/* archive global flags */
@@ -228,37 +240,55 @@
 
 /* zip archive directory entry (central or local) */
 
+#define ZIP_DIRENT_COMP_METHOD	0x0001
+#define ZIP_DIRENT_FILENAME	0x0002
+#define ZIP_DIRENT_COMMENT	0x0004
+#define ZIP_DIRENT_EXTRAFIELD	0x0008
+#define ZIP_DIRENT_ALL		0xffff
+
+struct zip_dirent_settable {
+    zip_uint32_t valid;
+    zip_int32_t comp_method;		/* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */
+    char *filename;			/* (cl) file name (NUL-terminated) */
+    char *comment;			/* (c)  file comment */
+    zip_uint16_t comment_len;		/* (c)  length of file comment */
+    char *extrafield;			/* (cl) extra field */
+    zip_uint16_t extrafield_len;	/* (cl) length of extra field */
+};
+
 struct zip_dirent {
     unsigned short version_madeby;	/* (c)  version of creator */
     unsigned short version_needed;	/* (cl) version needed to extract */
     unsigned short bitflags;		/* (cl) general purpose bit flag */
-    unsigned short comp_method;		/* (cl) compression method used */
     time_t last_mod;			/* (cl) time of last modification */
     unsigned int crc;			/* (cl) CRC-32 of uncompressed data */
-    unsigned int comp_size;		/* (cl) size of commpressed data */
-    unsigned int uncomp_size;		/* (cl) size of uncommpressed data */
-    char *filename;			/* (cl) file name (NUL-terminated) */
-    unsigned short filename_len;	/* (cl) length of filename (w/o NUL) */
-    char *extrafield;			/* (cl) extra field */
-    unsigned short extrafield_len;	/* (cl) length of extra field */
-    char *comment;			/* (c)  file comment */
-    unsigned short comment_len;		/* (c)  length of file comment */
+    unsigned int comp_size;		/* (cl) size of compressed data */
+    unsigned int uncomp_size;		/* (cl) size of uncompressed data */
     unsigned short disk_number;		/* (c)  disk number start */
     unsigned short int_attrib;		/* (c)  internal file attributes */
     unsigned int ext_attrib;		/* (c)  external file attributes */
-    unsigned int offset;		/* (c)  offset of local header  */
+    unsigned int offset;		/* (c)  offset of local header */
+    unsigned short fn_type;		/*      file name encoding (autorecognition) */
+    char *filename_converted;		/*      file name (autoconverted) */
+    unsigned short fc_type;		/*      file comment encoding (autorecognition) */
+    char *comment_converted;		/*      file comment (autoconverted) */
+    zip_uint32_t comment_converted_len;	/*      file comment length (autoconverted) */
+    struct zip_dirent_settable settable;
 };
 
 /* zip archive central directory */
 
 struct zip_cdir {
-    struct zip_dirent *entry;	/* directory entries */
-    int nentry;			/* number of entries */
+    struct zip_dirent *entry;	 	/* directory entries */
+    int nentry;			 	/* number of entries */
 
-    unsigned int size;		/* size of central direcotry */
-    unsigned int offset;	/* offset of central directory in file */
-    char *comment;		/* zip archive comment */
-    unsigned short comment_len;	/* length of zip archive comment */
+    unsigned int size;		 	/* size of central direcotry */
+    unsigned int offset;	 	/* offset of central directory in file */
+    char *comment;		 	/* zip archive comment */
+    unsigned short comment_len;	 	/* length of zip archive comment */
+    unsigned short comment_type; 	/* archive comment encoding (autorecognition) */
+    char *comment_converted;     	/* archive comment (autoconverted) */
+    zip_uint32_t comment_converted_len;	/* archive comment length (autoconverted) */
 };
 
 
@@ -279,11 +309,7 @@
 struct zip_entry {
     enum zip_state state;
     struct zip_source *source;
-    char *ch_filename;
-    char *ch_extra;
-    int ch_extra_len;
-    char *ch_comment;
-    int ch_comment_len;
+    struct zip_dirent_settable changes;
 };
 
 
@@ -329,19 +355,25 @@
 const char *_zip_error_strerror(struct zip_error *);
 
 int _zip_file_fillbuf(void *, size_t, struct zip_file *);
-unsigned int _zip_file_get_offset(struct zip *, int);
+unsigned int _zip_file_get_offset(struct zip *, int, struct zip_error *);
 
 int _zip_filerange_crc(FILE *, off_t, off_t, uLong *, struct zip_error *);
 
+enum zip_encoding_type _zip_guess_encoding(const zip_uint8_t * const,
+					   zip_uint32_t);
+zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t * const, zip_uint32_t,
+				zip_uint32_t *, struct zip_error *error);
+
 struct zip *_zip_open(const char *, FILE *, int, int, int *);
 
 struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *,
 					 zip_uint64_t, zip_int64_t, int,
 					 const struct zip_stat *);
 struct zip_source *_zip_source_new(struct zip *);
+struct zip_source *_zip_source_zip_new(struct zip *, struct zip *, zip_uint64_t, int,
+				       zip_uint64_t, zip_int64_t, const char *);
 
 int _zip_changed(struct zip *, int *);
-void _zip_free(struct zip *);
 const char *_zip_get_name(struct zip *, zip_uint64_t, int, struct zip_error *);
 int _zip_local_header_read(struct zip *, int);
 void *_zip_memdup(const void *, size_t, struct zip_error *);
diff --git a/libzip.pc.in b/libzip.pc.in
index f1301be..7ab8986 100644
--- a/libzip.pc.in
+++ b/libzip.pc.in
@@ -2,7 +2,7 @@
 exec_prefix=@exec_prefix@
 libdir=@libdir@
 includedir=@includedir@
-libincludedir=@libdir@/libzip/include
+libincludedir=@libdir@/@PACKAGE@/include
 
 zipcmp=@prefix@/bin/zipcmp
 
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
index 19c0eaa..53d114b 100644
--- a/man/CMakeLists.txt
+++ b/man/CMakeLists.txt
@@ -4,6 +4,7 @@
   zip_add_dir.mdoc
   zip_close.mdoc
   zip_delete.mdoc
+  zip_discard.mdoc
   zip_error_clear.mdoc
   zip_error_get.mdoc
   zip_error_get_sys_type.mdoc
@@ -29,6 +30,7 @@
   zip_set_archive_flag.mdoc
   zip_set_default_password.mdoc
   zip_set_file_comment.mdoc
+  zip_set_file_compression.mdoc
   zip_set_file_extra.mdoc
   zip_source_buffer.mdoc
   zip_source_file.mdoc
diff --git a/man/Makefile.am b/man/Makefile.am
index a4e5a69..9e83698 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -11,6 +11,7 @@
 	zip_add_dir.mdoc \
 	zip_close.mdoc \
 	zip_delete.mdoc \
+	zip_discard.mdoc \
 	zip_error_clear.mdoc \
 	zip_error_get.mdoc \
 	zip_error_get_sys_type.mdoc \
@@ -36,6 +37,7 @@
 	zip_set_archive_flag.mdoc \
 	zip_set_default_password.mdoc \
 	zip_set_file_comment.mdoc \
+	zip_set_file_compression.mdoc \
         zip_set_file_extra.mdoc \
 	zip_source_buffer.mdoc \
 	zip_source_file.mdoc \
diff --git a/man/libzip.man b/man/libzip.man
index 68678a9..fef5c4e 100644
--- a/man/libzip.man
+++ b/man/libzip.man
@@ -1,5 +1,5 @@
 .\" libzip.mdoc \-- general overview of available functions
-.\" Copyright (C) 2005-2011 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2005-2012 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>
@@ -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.
 .\"
-.TH LIBZIP 3 "February 14, 2011" NiH
+.TH LIBZIP 3 "February 13, 2012" NiH
 .SH "NAME"
 libzip \- library for manipulating zip archives
 .SH "LIBRARY"
@@ -57,6 +57,7 @@
 zip_fclose(3)
 .SS "close archive"
 zip_close(3)
+zip_discard(3)
 .SS "miscellaneous"
 zip_stat(3)
 zip_get_archive_comment(3)
@@ -73,6 +74,7 @@
 zip_add_dir(3)
 zip_replace(3)
 zip_set_file_comment(3)
+zip_set_file_compression(3)
 zip_source_buffer(3)
 zip_source_file(3)
 zip_source_filep(3)
@@ -87,6 +89,9 @@
 zip_unchange(3)
 zip_unchange_all(3)
 zip_unchange_archive(3)
+.SS "modify extra fields"
+zip_get_file_extra(3)
+zip_set_file_extra(3)
 .SS "close archive"
 zip_close(3)
 .SS "miscellaneous"
diff --git a/man/libzip.mdoc b/man/libzip.mdoc
index 9647f1c..c3e598f 100644
--- a/man/libzip.mdoc
+++ b/man/libzip.mdoc
@@ -1,5 +1,5 @@
 .\" libzip.mdoc -- general overview of available functions
-.\" Copyright (C) 2005-2011 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2005-2012 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>
@@ -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 February 14, 2011
+.Dd February 13, 2012
 .Dt LIBZIP 3
 .Os
 .Sh NAME
@@ -60,6 +60,7 @@
 .Xr zip_fclose 3
 .Ss close archive
 .Xr zip_close 3
+.Xr zip_discard 3
 .Ss miscellaneous
 .Xr zip_stat 3
 .Xr zip_get_archive_comment 3
@@ -76,6 +77,7 @@
 .Xr zip_add_dir 3
 .Xr zip_replace 3
 .Xr zip_set_file_comment 3
+.Xr zip_set_file_compression 3
 .Xr zip_source_buffer 3
 .Xr zip_source_file 3
 .Xr zip_source_filep 3
@@ -90,6 +92,9 @@
 .Xr zip_unchange 3
 .Xr zip_unchange_all 3
 .Xr zip_unchange_archive 3
+.Ss modify extra fields
+.Xr zip_get_file_extra 3
+.Xr zip_set_file_extra 3
 .Ss close archive
 .Xr zip_close 3
 .Ss miscellaneous
diff --git a/man/zip_add.man b/man/zip_add.man
index dcf6d31..914f161 100644
--- a/man/zip_add.man
+++ b/man/zip_add.man
@@ -1,5 +1,5 @@
 .\" zip_add.mdoc \-- add files to zip archive
-.\" Copyright (C) 2004-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-2012 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>
@@ -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.
 .\"
-.TH ZIP_ADD 3 "March 10, 2009" NiH
+.TH ZIP_ADD 3 "February 18, 2012" NiH
 .SH "NAME"
 zip_add , \- .Nm zip_replace
 add file to zip archive or replace file in zip archive
@@ -110,6 +110,9 @@
 or
 \fBindex\fR
 is invalid.
+This error is also returned when
+\fBname\fR
+is not a valid UTF-8 encoded string.
 .TP 4
 [ZIP_ER_MEMORY]
 Required memory could not be allocated.
diff --git a/man/zip_add.mdoc b/man/zip_add.mdoc
index bc5c204..b4dfd44 100644
--- a/man/zip_add.mdoc
+++ b/man/zip_add.mdoc
@@ -1,5 +1,5 @@
 .\" zip_add.mdoc -- add files to zip archive
-.\" Copyright (C) 2004-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-2012 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>
@@ -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 March 10, 2009
+.Dd February 20, 2012
 .Dt ZIP_ADD 3
 .Os
 .Sh NAME
@@ -62,6 +62,8 @@
 .Ar index
 specifies which file should be replaced (for
 .Fn zip_replace ) .
+.Ar name
+must be encoded in ASCII or UTF-8.
 The data is obtained from the
 .Ar source
 argument.
@@ -109,6 +111,9 @@
 or
 .Ar index
 is invalid.
+This error is also returned when
+.Ar name
+is not a valid UTF-8 encoded string.
 .It Bq Er ZIP_ER_MEMORY
 Required memory could not be allocated.
 .El
diff --git a/man/zip_close.man b/man/zip_close.man
index 3fc9a2a..6e599f3 100644
--- a/man/zip_close.man
+++ b/man/zip_close.man
@@ -1,5 +1,5 @@
 .\" zip_close.mdoc \-- close zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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.
 .\"
-.TH ZIP_CLOSE 3 "February 15, 2009" NiH
+.TH ZIP_CLOSE 3 "February 13, 2012" NiH
 .SH "NAME"
 zip_close \- close zip archive
 .SH "LIBRARY"
@@ -56,6 +56,9 @@
 \fBarchive\fR
 contains no files, the file is completely removed (no empty archive is
 written).
+.PP
+To close a zip file without saving changes, use
+zip_discard(3).
 .SH "RETURN VALUES"
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error code in
@@ -108,6 +111,7 @@
 for added or replaced files will be passed back.
 .SH "SEE ALSO"
 libzip(3),
+zip_discard(3),
 zip_error_get(3),
 zip_fdopen(3),
 zip_open(3),
diff --git a/man/zip_close.mdoc b/man/zip_close.mdoc
index 0db9bb6..3896038 100644
--- a/man/zip_close.mdoc
+++ b/man/zip_close.mdoc
@@ -1,5 +1,5 @@
 .\" zip_close.mdoc -- close zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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 February 15, 2009
+.Dd February 13, 2012
 .Dt ZIP_CLOSE 3
 .Os
 .Sh NAME
@@ -58,6 +58,9 @@
 .Ar archive
 contains no files, the file is completely removed (no empty archive is
 written).
+.Pp
+To close a zip file without saving changes, use
+.Xr zip_discard 3 .
 .Sh RETURN VALUES
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error code in
@@ -99,6 +102,7 @@
 for added or replaced files will be passed back.
 .Sh SEE ALSO
 .Xr libzip 3 ,
+.Xr zip_discard 3 ,
 .Xr zip_error_get 3 ,
 .Xr zip_fdopen 3 ,
 .Xr zip_open 3 ,
diff --git a/man/zip_discard.man b/man/zip_discard.man
new file mode 100644
index 0000000..1f2b2b5
--- /dev/null
+++ b/man/zip_discard.man
@@ -0,0 +1,56 @@
+.\" zip_discard.mdoc \-- close zip archive and discard changes
+.\" Copyright (C) 2012 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.
+.\"
+.TH ZIP_DISCARD 3 "February 13, 2012" NiH
+.SH "NAME"
+zip_discard \- close zip archive and discard changes
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+#include <zip.h>
+.PP
+void
+zip_discard(struct zip *archive);
+.SH "DESCRIPTION"
+The
+zip_discard
+function closes
+\fBarchive\fR
+and frees the memory allocated for it.
+Any changes to the archive are not written to disk and discarded.
+.SH "SEE ALSO"
+libzip(3),
+zip_close(3)
+.SH "AUTHORS"
+
+Dieter Baron <dillo@giga.or.at>
+and
+Thomas Klausner <tk@giga.or.at>
diff --git a/man/zip_discard.mdoc b/man/zip_discard.mdoc
new file mode 100644
index 0000000..8512ea7
--- /dev/null
+++ b/man/zip_discard.mdoc
@@ -0,0 +1,58 @@
+.\" zip_discard.mdoc -- close zip archive and discard changes
+.\" Copyright (C) 2012 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.
+.\"
+.Dd February 13, 2012
+.Dt ZIP_DISCARD 3
+.Os
+.Sh NAME
+.Nm zip_discard
+.Nd close zip archive and discard changes
+.Sh LIBRARY
+libzip (-lzip)
+.Sh SYNOPSIS
+.In zip.h
+.Ft void
+.Fn zip_discard "struct zip *archive"
+.Sh DESCRIPTION
+The
+.Fn zip_discard
+function closes
+.Ar archive
+and frees the memory allocated for it.
+Any changes to the archive are not written to disk and discarded.
+.Sh SEE ALSO
+.Xr libzip 3 ,
+.Xr zip_close 3
+.Sh AUTHORS
+.An -nosplit
+.An Dieter Baron Aq dillo@giga.or.at
+and
+.An Thomas Klausner Aq tk@giga.or.at
diff --git a/man/zip_fdopen.man b/man/zip_fdopen.man
index e08e806..5cccd98 100644
--- a/man/zip_fdopen.man
+++ b/man/zip_fdopen.man
@@ -1,5 +1,5 @@
 .\" zip_fdopen.mdoc \-- open zip archive using existing file descriptor
-.\" Copyright (C) 2009-2010 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2009-2012 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>
@@ -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.
 .\"
-.TH ZIP_FDOPEN 3 "February 1, 2010" NiH
+.TH ZIP_FDOPEN 3 "February 13, 2012" NiH
 .SH "NAME"
 zip_fdopen \- open zip archive using open file descriptor
 .SH "LIBRARY"
@@ -63,8 +63,8 @@
 .RS
 .TP 15
 \fBZIP_CHECKCONS\fR
-Perform additional consistency checks on the archive, and error if
-they fail.
+Perform additional stricter consistency checks on the archive, and
+error if they fail.
 .RE
 .PP
 If an error occurs and
@@ -100,10 +100,10 @@
 .TP 4
 [ZIP_ER_INCONS]
 Inconsistencies were found in the file specified by
-\fBpath\fR
-and
+\fBpath.\fR
+This error is often caused by specifying
 \fBZIP_CHECKCONS\fR
-was specified.
+but can also happen without it.
 .TP 4
 [ZIP_ER_INVAL]
 The
diff --git a/man/zip_fdopen.mdoc b/man/zip_fdopen.mdoc
index 86fdaa3..e070dfc 100644
--- a/man/zip_fdopen.mdoc
+++ b/man/zip_fdopen.mdoc
@@ -1,5 +1,5 @@
 .\" zip_fdopen.mdoc -- open zip archive using existing file descriptor
-.\" Copyright (C) 2009-2010 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2009-2012 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>
@@ -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 February 1, 2010
+.Dd February 13, 2012
 .Dt ZIP_FDOPEN 3
 .Os
 .Sh NAME
@@ -63,8 +63,8 @@
 the following values, or 0 for none of them.
 .Bl -tag -offset indent -width ZIP_CHECKCONS
 .It Dv ZIP_CHECKCONS
-Perform additional consistency checks on the archive, and error if
-they fail.
+Perform additional stricter consistency checks on the archive, and
+error if they fail.
 .El
 .Pp
 If an error occurs and
@@ -98,10 +98,10 @@
 .Bl -tag -width Er
 .It Bq Er ZIP_ER_INCONS
 Inconsistencies were found in the file specified by
-.Ar path
-and
+.Ar path .
+This error is often caused by specifying
 .Dv ZIP_CHECKCONS
-was specified.
+but can also happen without it.
 .It Bq Er ZIP_ER_INVAL
 The
 .Ar flags
diff --git a/man/zip_get_archive_comment.mdoc b/man/zip_get_archive_comment.mdoc
index dee3317..7f2b3f6 100644
--- a/man/zip_get_archive_comment.mdoc
+++ b/man/zip_get_archive_comment.mdoc
@@ -1,5 +1,5 @@
 .\" zip_get_archive_comment.mdoc -- get zip archive comment
-.\" Copyright (C) 2006 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2006-2012 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>
@@ -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 April 23, 2006
+.Dd February 20, 2012
 .Dt ZIP_GET_ARCHIVE_COMMENT 3
 .Os
 .Sh NAME
@@ -45,8 +45,14 @@
 The
 .Fn zip_get_archive_comment
 function returns the comment for the entire zip archive.
+The name is in UTF-8 encoding unless
+.Dv ZIP_FL_NAME_RAW
+was specified (see below).
 This pointer should not be modified or
-.Xr free 3 Ap d .
+.Xr free 3 Ap d ,
+and becomes invalid when
+.Ar archive
+is closed.
 If
 .Ar lenp
 is not
@@ -58,6 +64,21 @@
 is set to
 .Dv ZIP_FL_UNCHANGED ,
 the original unchanged comment is returned.
+.Pp
+Additionally, the following flags are supported:
+.Bl -tag -width ZIP_FL_NAME_STRICTXX -offset indent
+.It Dv ZIP_FL_NAME_RAW
+Return the unmodified archive comment as it is in the ZIP archive.
+.It Dv ZIP_FL_NAME_GUESS
+(Default.)
+Guess the encoding of the archive comment in the ZIP archive and convert it
+to UTF-8, if necessary.
+.It Dv ZIP_FL_NAME_STRICT
+Follow the ZIP specification for file names and extend it to the archive comment,
+thus also expecting it in CP-437 encoding.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8.
+.El
 .Sh RETURN VALUES
 Upon successful completion, a pointer to the comment is returned,
 or
diff --git a/man/zip_get_file_comment.man b/man/zip_get_file_comment.man
index aa6b762..0280b9e 100644
--- a/man/zip_get_file_comment.man
+++ b/man/zip_get_file_comment.man
@@ -78,6 +78,7 @@
 \fBindex\fR
 is not a valid file index in
 \fBarchive.\fR
+.RE
 .SH "SEE ALSO"
 libzip(3),
 zip_get_archive_comment(3)
diff --git a/man/zip_get_file_comment.mdoc b/man/zip_get_file_comment.mdoc
index 780db5f..8e19d76 100644
--- a/man/zip_get_file_comment.mdoc
+++ b/man/zip_get_file_comment.mdoc
@@ -1,5 +1,5 @@
 .\" zip_get_file_comment.mdoc -- get comment for file in zip
-.\" Copyright (C) 2006-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2006-2012 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 March 10, 2009
+.Dd February 20, 2012
 .Dt ZIP_GET_FILE_COMMENT 3
 .Os
 .Sh NAME
@@ -47,8 +47,14 @@
 function returns the comment for the file at position
 .Ar index
 in the zip archive.
+The name is in UTF-8 encoding unless
+.Dv ZIP_FL_NAME_RAW
+was specified (see below).
 This pointer should not be modified or
-.Xr free 3 Ap d .
+.Xr free 3 Ap d ,
+and becomes invalid when
+.Ar archive
+is closed.
 If
 .Ar lenp
 is not
@@ -60,6 +66,21 @@
 is set to
 .Dv ZIP_FL_UNCHANGED ,
 the original unchanged comment is returned.
+.Pp
+Additionally, the following flags are supported:
+.Bl -tag -width ZIP_FL_NAME_STRICTXX -offset indent
+.It Dv ZIP_FL_NAME_RAW
+Return the unmodified comment as it is in the ZIP archive.
+.It Dv ZIP_FL_NAME_GUESS
+(Default.)
+Guess the encoding of the comment in the ZIP archive and convert it
+to UTF-8, if necessary.
+.It Dv ZIP_FL_NAME_STRICT
+Follow the ZIP specification for file names and extend it to file comments,
+expecting them to be encoded in CP-437 in the ZIP archive.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8.
+.El
 .Sh RETURN VALUES
 Upon successful completion, a pointer to the comment is returned,
 or
@@ -78,6 +99,7 @@
 .Ar index
 is not a valid file index in
 .Ar archive .
+.El
 .Sh SEE ALSO
 .Xr libzip 3 ,
 .Xr zip_get_archive_comment 3
diff --git a/man/zip_get_name.man b/man/zip_get_name.man
index 66b7340..65a16b8 100644
--- a/man/zip_get_name.man
+++ b/man/zip_get_name.man
@@ -1,5 +1,5 @@
 .\" zip_get_name.mdoc \-- get name of file by index
-.\" Copyright (C) 2003, 2004, 2005 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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.
 .\"
-.TH ZIP_GET_NAME 3 "January 20, 2005" NiH
+.TH ZIP_GET_NAME 3 "February 15, 2012" NiH
 .SH "NAME"
 zip_get_name \- get name of file by index
 .SH "LIBRARY"
@@ -46,6 +46,11 @@
 \fBindex\fR
 in
 \fBarchive.\fR
+The name is in UTF-8 encoding unless
+\fBZIP_FL_NAME_RAW\fR
+was specified (see below).
+(ASCII is a subset of UTF-8.)
+.PP
 If
 \fBflags\fR
 is set to
@@ -54,6 +59,24 @@
 The returned string must not be modified or freed, and becomes invalid when
 \fBarchive\fR
 is closed.
+.PP
+Additionally, the following flags are supported:
+.RS
+.TP 22
+\fBZIP_FL_NAME_RAW\fR
+Return the unmodified names as it is in the ZIP archive.
+.TP 22
+\fBZIP_FL_NAME_GUESS\fR
+(Default.)
+Guess the encoding of the name in the ZIP archive and convert it
+to UTF-8, if necessary.
+.TP 22
+\fBZIP_FL_NAME_STRICT\fR
+Follow the ZIP specification and expect CP-437 encoded names in
+the ZIP archive.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8.
+.RE
 .SH "RETURN VALUES"
 Upon successful completion, a pointer to the name is returned.
 Otherwise,
@@ -82,6 +105,10 @@
 points to an added file and
 \fBZIP_FL_UNCHANGED\fR
 is set.
+.TP 4
+[ZIP_ER_MEMORY]
+Required memory could not be allocated.
+.RE
 .SH "SEE ALSO"
 libzip(3),
 zip_name_locate(3)
diff --git a/man/zip_get_name.mdoc b/man/zip_get_name.mdoc
index 743f117..15ba09f 100644
--- a/man/zip_get_name.mdoc
+++ b/man/zip_get_name.mdoc
@@ -1,5 +1,5 @@
 .\" zip_get_name.mdoc -- get name of file by index
-.\" Copyright (C) 2003, 2004, 2005 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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 20, 2005
+.Dd February 15, 2012
 .Dt ZIP_GET_NAME 3
 .Os
 .Sh NAME
@@ -48,6 +48,11 @@
 .Ar index
 in
 .Ar archive .
+The name is in UTF-8 encoding unless
+.Dv ZIP_FL_NAME_RAW
+was specified (see below).
+(ASCII is a subset of UTF-8.)
+.Pp
 If
 .Ar flags
 is set to
@@ -56,6 +61,21 @@
 The returned string must not be modified or freed, and becomes invalid when
 .Ar archive
 is closed.
+.Pp
+Additionally, the following flags are supported:
+.Bl -tag -width ZIP_FL_NAME_STRICTXX -offset indent
+.It Dv ZIP_FL_NAME_RAW
+Return the unmodified names as it is in the ZIP archive.
+.It Dv ZIP_FL_NAME_GUESS
+(Default.)
+Guess the encoding of the name in the ZIP archive and convert it
+to UTF-8, if necessary.
+.It Dv ZIP_FL_NAME_STRICT
+Follow the ZIP specification and expect CP-437 encoded names in
+the ZIP archive.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8.
+.El
 .Sh RETURN VALUES
 Upon successful completion, a pointer to the name is returned.
 Otherwise,
@@ -81,6 +101,9 @@
 points to an added file and
 .Dv ZIP_FL_UNCHANGED
 is set.
+.It Bq Er ZIP_ER_MEMORY
+Required memory could not be allocated.
+.El
 .Sh SEE ALSO
 .Xr libzip 3 ,
 .Xr zip_name_locate 3
diff --git a/man/zip_name_locate.man b/man/zip_name_locate.man
index e3702df..5c3901a 100644
--- a/man/zip_name_locate.man
+++ b/man/zip_name_locate.man
@@ -1,5 +1,5 @@
 .\" zip_name_locate.mdoc \-- get index of file by name
-.\" Copyright (C) 2003, 2005 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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.
 .\"
-.TH ZIP_NAME_LOCATE 3 "October 4, 2006" NiH
+.TH ZIP_NAME_LOCATE 3 "February 15, 2012" NiH
 .SH "NAME"
 zip_name_locate \- get index of file by name
 .SH "LIBRARY"
@@ -58,9 +58,25 @@
 .TP 15
 \fBZIP_FL_NOCASE\fR
 Ignore case distinctions.
+(Will only work well if the file names are ASCII.)
 .TP 15
 \fBZIP_FL_NODIR\fR
 Ignore directory part of file name in archive.
+.TP 15
+\fBZIP_FL_NAME_RAW\fR
+Compare against the unmodified names as it is in the ZIP archive.
+.TP 15
+\fBZIP_FL_NAME_GUESS\fR
+(Default.)
+Guess the encoding of the name in the ZIP archive and convert it
+to UTF-8, if necessary, before comparing.
+.TP 15
+\fBZIP_FL_NAME_STRICT\fR
+Follow the ZIP specification and expect CP-437 encoded names in
+the ZIP archive.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8 before comparing.
+.RE
 .RE
 .SH "RETURN VALUES"
 zip_name_locate
@@ -70,15 +86,21 @@
 \fBarchive\fR
 does not contain an entry of that name.
 .SH "ERRORS"
-The
 zip_name_locate
-function fails and sets the error information to
-ZIP_ER_NOENT
-if no entry of the name
+fails if:
+.RS
+.TP 4
+[ZIP_ER_NOENT]
+No entry of the name
 \fBfname\fR
 is found in the archive.
-If one of the arguments is invalid, the error information is set to
-ZIP_ER_INVAL.
+.TP 4
+[ZIP_ER_INVAL]
+One of the arguments is invalid.
+.TP 4
+[ZIP_ER_MEMORY]
+Required memory could not be allocated.
+.RE
 .SH "SEE ALSO"
 libzip(3),
 zip_get_name(3)
diff --git a/man/zip_name_locate.mdoc b/man/zip_name_locate.mdoc
index eeac3ed..e73deac 100644
--- a/man/zip_name_locate.mdoc
+++ b/man/zip_name_locate.mdoc
@@ -1,5 +1,5 @@
 .\" zip_name_locate.mdoc -- get index of file by name
-.\" Copyright (C) 2003, 2005 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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 October 4, 2006
+.Dd February 15, 2012
 .Dt ZIP_NAME_LOCATE 3
 .Os
 .Sh NAME
@@ -59,8 +59,21 @@
 .Bl -tag -offset indent -width ZIP_FL_NOCASE
 .It Dv ZIP_FL_NOCASE
 Ignore case distinctions.
+(Will only work well if the file names are ASCII.)
 .It Dv ZIP_FL_NODIR
 Ignore directory part of file name in archive.
+.It Dv ZIP_FL_NAME_RAW
+Compare against the unmodified names as it is in the ZIP archive.
+.It Dv ZIP_FL_NAME_GUESS
+(Default.)
+Guess the encoding of the name in the ZIP archive and convert it
+to UTF-8, if necessary, before comparing.
+.It Dv ZIP_FL_NAME_STRICT
+Follow the ZIP specification and expect CP-437 encoded names in
+the ZIP archive.
+(ASCII is a subset of CP-437.)
+Convert it to UTF-8 before comparing.
+.El
 .El
 .Sh RETURN VALUES
 .Fn zip_name_locate
@@ -70,15 +83,18 @@
 .Ar archive
 does not contain an entry of that name.
 .Sh ERRORS
-The
 .Fn zip_name_locate
-function fails and sets the error information to
-.Er ZIP_ER_NOENT
-if no entry of the name
+fails if:
+.Bl -tag -width Er
+.It Bq Er ZIP_ER_NOENT
+No entry of the name
 .Ar fname
 is found in the archive.
-If one of the arguments is invalid, the error information is set to
-.Er ZIP_ER_INVAL .
+.It Bq Er ZIP_ER_INVAL
+One of the arguments is invalid.
+.It Bq Er ZIP_ER_MEMORY
+Required memory could not be allocated.
+.El
 .Sh SEE ALSO
 .Xr libzip 3 ,
 .Xr zip_get_name 3
diff --git a/man/zip_open.man b/man/zip_open.man
index 0efd895..08f9bc4 100644
--- a/man/zip_open.man
+++ b/man/zip_open.man
@@ -1,5 +1,5 @@
 .\" zip_open.mdoc \-- open zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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.
 .\"
-.TH ZIP_OPEN 3 "February 15, 2009" NiH
+.TH ZIP_OPEN 3 "February 13, 2012" NiH
 .SH "NAME"
 zip_open \- open zip archive
 .SH "LIBRARY"
@@ -53,15 +53,19 @@
 the following values, or 0 for none of them.
 .RS
 .TP 15
+\fBZIP_CHECKCONS\fR
+Perform additional stricter consistency checks on the archive, and
+error if they fail.
+.TP 15
 \fBZIP_CREATE\fR
 Create the archive if it does not exist.
 .TP 15
 \fBZIP_EXCL\fR
 Error if archive already exists.
 .TP 15
-\fBZIP_CHECKCONS\fR
-Perform additional consistency checks on the archive, and error if
-they fail.
+\fBZIP_TRUNCATE\fR
+If archive exists, ignore its current contents.
+In other words, handle it the same way as an empty archive.
 .RE
 .PP
 If an error occurs and
@@ -94,10 +98,10 @@
 .TP 4
 [ZIP_ER_INCONS]
 Inconsistencies were found in the file specified by
-\fBpath\fR
-and
+\fBpath.\fR
+This error is often caused by specifying
 \fBZIP_CHECKCONS\fR
-was specified.
+but can also happen without it.
 .TP 4
 [ZIP_ER_INVAL]
 The
diff --git a/man/zip_open.mdoc b/man/zip_open.mdoc
index 1f1a556..0602499 100644
--- a/man/zip_open.mdoc
+++ b/man/zip_open.mdoc
@@ -1,5 +1,5 @@
 .\" zip_open.mdoc -- open zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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 February 15, 2009
+.Dd February 13, 2012
 .Dt ZIP_OPEN 3
 .Os
 .Sh NAME
@@ -53,13 +53,16 @@
 .Em or Ns No 'ing
 the following values, or 0 for none of them.
 .Bl -tag -offset indent -width ZIP_CHECKCONS
+.It Dv ZIP_CHECKCONS
+Perform additional stricter consistency checks on the archive, and
+error if they fail.
 .It Dv ZIP_CREATE
 Create the archive if it does not exist.
 .It Dv ZIP_EXCL
 Error if archive already exists.
-.It Dv ZIP_CHECKCONS
-Perform additional consistency checks on the archive, and error if
-they fail.
+.It Dv ZIP_TRUNCATE
+If archive exists, ignore its current contents.
+In other words, handle it the same way as an empty archive.
 .El
 .Pp
 If an error occurs and
@@ -89,10 +92,10 @@
 is set.
 .It Bq Er ZIP_ER_INCONS
 Inconsistencies were found in the file specified by
-.Ar path
-and
+.Ar path .
+This error is often caused by specifying
 .Dv ZIP_CHECKCONS
-was specified.
+but can also happen without it.
 .It Bq Er ZIP_ER_INVAL
 The
 .Ar path
diff --git a/man/zip_rename.man b/man/zip_rename.man
index 38c5a02..d0b79e0 100644
--- a/man/zip_rename.man
+++ b/man/zip_rename.man
@@ -1,5 +1,5 @@
 .\" zip_rename.mdoc \-- rename file in zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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.
 .\"
-.TH ZIP_RENAME 3 "March 10, 2009" NiH
+.TH ZIP_RENAME 3 "February 18, 2012" NiH
 .SH "NAME"
 zip_rename \- rename file in zip archive
 .SH "LIBRARY"
@@ -69,8 +69,8 @@
 is not a valid file index in
 \fBarchive,\fR
 \fBname is\fR
-\fBNULL\fR
-or the empty string.
+\fBNULL,\fR
+the empty string, or not a valid UTF-8 encoded string.
 Also a file cannot be renamed to a directory or vice versa.
 Directories are denoted by a trailing slash.
 .RE
diff --git a/man/zip_rename.mdoc b/man/zip_rename.mdoc
index 9c80a1b..c7dbacf 100644
--- a/man/zip_rename.mdoc
+++ b/man/zip_rename.mdoc
@@ -1,5 +1,5 @@
 .\" zip_rename.mdoc -- rename file in zip archive
-.\" Copyright (C) 2003-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2012 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>
@@ -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 March 10, 2009
+.Dd February 20, 2012
 .Dt ZIP_RENAME 3
 .Os
 .Sh NAME
@@ -48,6 +48,8 @@
 .Ar archive
 is renamed to
 .Ar name .
+.Ar name
+must be encoded in ASCII or UTF-8.
 .Sh RETURN VALUES
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error code in
@@ -59,6 +61,23 @@
 .Bl -tag -width Er
 .It Bq Er ZIP_ER_DELETED
 The file to be renamed has been deleted from the archive.
+.It Bq Er ZIP_ER_ENCMISMATCH
+The file comment is encoded in CP437 and the file name is in UTF-8.
+Workaround: read out the file comment with
+.Xr zip_get_file_comment 3
+and the
+.Dv ZIP_FL_GUESS
+flag (optionally verify it), then delete it with
+.Xr zip_set_file_comment 3
+and a
+.Dv NULL
+argument.
+Finally, set the file name with
+.Nm
+and reinstate the file comment with
+.Xr zip_set_file_comment 3
+using the result from the previous call of
+.Xr zip_get_file_comment 3 .
 .It Bq Er ZIP_ER_EXISTS
 There is already a file called
 .Ar name
@@ -68,8 +87,8 @@
 is not a valid file index in
 .Ar archive ,
 .Ar name is
-.Dv NULL
-or the empty string.
+.Dv NULL ,
+the empty string, or not a valid UTF-8 encoded string.
 Also a file cannot be renamed to a directory or vice versa.
 Directories are denoted by a trailing slash.
 .El
diff --git a/man/zip_set_archive_comment.mdoc b/man/zip_set_archive_comment.mdoc
index 1e1b602..38a6b38 100644
--- a/man/zip_set_archive_comment.mdoc
+++ b/man/zip_set_archive_comment.mdoc
@@ -1,5 +1,5 @@
 .\" zip_set_archive_comment.mdoc -- set zip archive comment
-.\" Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2006-2012 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>
@@ -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 October 26, 2007
+.Dd February 20, 2012
 .Dt ZIP_SET_ARCHIVE_COMMENT 3
 .Os
 .Sh NAME
@@ -53,6 +53,8 @@
 and
 .Ar len
 is 0, the archive comment will be removed.
+.Ar comment
+must be encoded in ASCII or UTF-8.
 .Sh RETURN VALUES
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error information in
@@ -65,7 +67,9 @@
 .It Bq Er ZIP_ER_INVAL
 .Ar len
 is less than 0 or longer than the maximum comment length in a zip file
-(65535).
+(65535), or
+.Ar comment
+is not a valid UTF-8 encoded string.
 .It Bq Er ZIP_ER_MEMORY
 Required memory could not be allocated.
 .El
diff --git a/man/zip_set_file_comment.mdoc b/man/zip_set_file_comment.mdoc
index 068304f..62d3c16 100644
--- a/man/zip_set_file_comment.mdoc
+++ b/man/zip_set_file_comment.mdoc
@@ -1,5 +1,5 @@
 .\" zip_set_file_comment.mdoc -- set comment for file in zip
-.\" Copyright (C) 2006-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2006-2012 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 March 10, 2009
+.Dd February 20, 2012
 .Dt ZIP_SET_FILE_COMMENT 3
 .Os
 .Sh NAME
@@ -58,6 +58,8 @@
 and
 .Ar len
 is 0, the file comment will be removed.
+.Ar comment
+must be encoded in ASCII or UTF-8.
 .Sh RETURN VALUES
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error information in
@@ -67,6 +69,10 @@
 .Fn zip_set_file_comment
 fails if:
 .Bl -tag -width Er
+.It Bq Er ZIP_ER_ENCMISMATCH
+The file name is encoded in CP437 and the file comment is in UTF-8.
+Workaround: see
+.Xr zip_rename 3 .
 .It Bq Er ZIP_ER_INVAL
 .Ar index
 is not a valid file index in
@@ -74,7 +80,9 @@
 or
 .Ar len
 is less than 0 or longer than the maximum comment length in a zip file
-(65535).
+(65535), or
+.Ar comment
+is not a valid UTF-8 encoded string.
 .It Bq Er ZIP_ER_MEMORY
 Required memory could not be allocated.
 .El
diff --git a/man/zip_set_file_compression.man b/man/zip_set_file_compression.man
new file mode 100644
index 0000000..0571dd2
--- /dev/null
+++ b/man/zip_set_file_compression.man
@@ -0,0 +1,114 @@
+.\" zip_set_file_compression.mdoc \-- set compression method and its flags
+.\" Copyright (C) 2012 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>
+.\"
+.\" 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.
+.\"
+.TH ZIP_SET_FILE_COMPRESSION 3 "February 27, 2012" NiH
+.SH "NAME"
+zip_set_file_compression \- set compression method for file in zip
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+#include <zip.h>
+.PP
+int
+zip_set_file_compression(struct zip *archive, zip_uint64_t index); \
+"zip_int32_t comp" "zip_uint32_t comp_flags"
+.SH "DESCRIPTION"
+The
+zip_set_file_compression
+function sets the compression method for the file at position
+\fBindex\fR
+in the zip archive to
+\fBcomp\fR
+with the compression method specific
+\fBflags.\fR
+The
+\fBcomp\fR
+is the same as returned by
+zip_stat(3).
+For the
+\fBcomp\fR
+argument, currently only the following values are supported:
+.RS
+.TP 19
+\fBZIP_CM_DEFAULT\fR
+default compression; currently the same as
+\fBZIP_CM_DEFLATE.\fR
+.TP 19
+\fBZIP_CM_STORE\fR
+Store the file uncompressed.
+.TP 19
+\fBZIP_CM_DEFLATE\fR
+Deflate the file with the
+zlib(3)
+algorithm and default options
+.RE
+.PP
+The flags argument is currently ignored.
+.\" For the flags argument, the lower 4 bits define the compression
+.\" level.
+.\" 0 is fastest compression, 15 is highest compression
+.\" \fBZIP_COMP_FL_DEFAULT\fR
+.\" can be used to specify that the default shall be used.
+.\" Further compression method specific flags will be added over time.
+.PP
+The current compression method for a file in a zip archive can be
+determined using
+zip_stat(3).
+.SH "RETURN VALUES"
+Upon successful completion 0 is returned.
+Otherwise, \-1 is returned and the error information in
+\fBarchive\fR
+is set to indicate the error.
+.SH "ERRORS"
+zip_set_file_compression
+fails if:
+.RS
+.TP 4
+[ZIP_ER_INVAL]
+\fBindex\fR
+is not a valid file index in
+\fBarchive,\fR
+or the argument combination is invalid.
+.TP 4
+[ZIP_ER_COMPNOTSUPP]
+Unsupported compression method requested.
+.TP 4
+[ZIP_ER_RDONLY]
+Read-only zip file, no changes allowed.
+.RE
+.SH "SEE ALSO"
+libzip(3),
+zip_stat(3)
+.SH "AUTHORS"
+
+Dieter Baron <dillo@giga.or.at>
+and
+Thomas Klausner <tk@giga.or.at>
diff --git a/man/zip_set_file_compression.mdoc b/man/zip_set_file_compression.mdoc
index 0036a1a..6cf2f99 100644
--- a/man/zip_set_file_compression.mdoc
+++ b/man/zip_set_file_compression.mdoc
@@ -1,5 +1,5 @@
 .\" zip_set_file_compression.mdoc -- set compression method and its flags
-.\" Copyright (C) 2011 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2012 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,19 +29,19 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd March 17, 2011
+.Dd February 27, 2012
 .Dt ZIP_SET_FILE_COMPRESSION 3
 .Os
 .Sh NAME
 .Nm zip_set_file_compression
-.Nd set compression method and corresponding options for file in zip
+.Nd set compression method for file in zip
 .Sh LIBRARY
 libzip (-lzip)
 .Sh SYNOPSIS
 .In zip.h
 .Ft int
 .Fn zip_set_file_compression "struct zip *archive" "zip_uint64_t index" \
-"zip_uint16_t comp" "zip_uint32_t comp_flags"
+"zip_int32_t comp" "zip_uint32_t comp_flags"
 .Sh DESCRIPTION
 The
 .Fn zip_set_file_compression
@@ -57,19 +57,30 @@
 .Xr zip_stat 3 .
 For the
 .Ar comp
-argument, currently only the
-.\" XXX: adapt to real defines
-.Dv DEFLATE
-and
-.Dv STORE
-methods are supported.
+argument, currently only the following values are supported:
+.Bl -tag -width ZIP_CM_DEFLATE_XX
+.It Dv ZIP_CM_DEFAULT
+default compression; currently the same as
+.Dv ZIP_CM_DEFLATE .
+.It Dv ZIP_CM_STORE
+Store the file uncompressed.
+.It Dv ZIP_CM_DEFLATE
+Deflate the file with the
+.Xr zlib 3
+algorithm and default options
+.El
 .Pp
-For the 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.
+The flags argument is currently ignored.
+.\" For the 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.
+.Pp
+The current compression method for a file in a zip archive can be
+determined using
+.Xr zip_stat 3 .
 .Sh RETURN VALUES
 Upon successful completion 0 is returned.
 Otherwise, \-1 is returned and the error information in
@@ -84,8 +95,10 @@
 is not a valid file index in
 .Ar archive ,
 or the argument combination is invalid.
-.\" .It Bq Er ZIP_ER_MEMORY
-.\" Required memory could not be allocated.
+.It Bq Er ZIP_ER_COMPNOTSUPP
+Unsupported compression method requested.
+.It Bq Er ZIP_ER_RDONLY
+Read-only zip file, no changes allowed.
 .El
 .Sh SEE ALSO
 .Xr libzip 3 ,
diff --git a/man/zip_source_function.man b/man/zip_source_function.man
index 1b7a19b..4a5686b 100644
--- a/man/zip_source_function.man
+++ b/man/zip_source_function.man
@@ -1,5 +1,5 @@
 .\" zip_source_function.mdoc \-- create data source from function
-.\" Copyright (C) 2004-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-2011 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>
@@ -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.
 .\"
-.TH ZIP_SOURCE_FUNCTION 3 "March 30, 2009" NiH
+.TH ZIP_SOURCE_FUNCTION 3 "March 22, 2011" NiH
 .SH "NAME"
 zip_source_function \- create data source from function
 .SH "LIBRARY"
@@ -94,6 +94,10 @@
 Information only available after the source has been read (e.g. size)
 can be omitted in an earlier call.
 Return sizeof(struct zip_stat) on success, \-1 on error.
+.I NOTE :
+zip_source_function
+may be called with this argument even after being called with
+\fBZIP_SOURCE_CLOSE.\fR
 .TP 21
 \fBZIP_SOURCE_ERROR\fR
 Get error information.
diff --git a/man/zip_source_function.mdoc b/man/zip_source_function.mdoc
index 5fbfef8..4cf7ba6 100644
--- a/man/zip_source_function.mdoc
+++ b/man/zip_source_function.mdoc
@@ -1,5 +1,5 @@
 .\" zip_source_function.mdoc -- create data source from function
-.\" Copyright (C) 2004-2009 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-2011 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>
@@ -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 March 30, 2009
+.Dd March 22, 2011
 .Dt ZIP_SOURCE_FUNCTION 3
 .Os
 .Sh NAME
@@ -92,6 +92,10 @@
 Information only available after the source has been read (e.g. size)
 can be omitted in an earlier call.
 Return sizeof(struct zip_stat) on success, \-1 on error.
+.Em NOTE :
+.Fn zip_source_function
+may be called with this argument even after being called with
+.Dv ZIP_SOURCE_CLOSE .
 .It Dv ZIP_SOURCE_ERROR
 Get error information.
 .Ar data
diff --git a/man/zip_stat.man b/man/zip_stat.man
index ff5cf99..5b93286 100644
--- a/man/zip_stat.man
+++ b/man/zip_stat.man
@@ -102,31 +102,31 @@
 before accessing the fields:
 .RS
 .TP 30
-ZIP_STAT_NAME
+\fBZIP_STAT_NAME\fR
 \fBname\fR
 .TP 30
-ZIP_STAT_INDEX
+\fBZIP_STAT_INDEX\fR
 \fBindex\fR
 .TP 30
-ZIP_STAT_SIZE
+\fBZIP_STAT_SIZE\fR
 \fBsize\fR
 .TP 30
-ZIP_STAT_COMP_SIZE
+\fBZIP_STAT_COMP_SIZE\fR
 \fBcomp_size\fR
 .TP 30
-ZIP_STAT_MTIME
+\fBZIP_STAT_MTIME\fR
 \fBmtime\fR
 .TP 30
-ZIP_STAT_CRC
+\fBZIP_STAT_CRC\fR
 \fBcrc\fR
 .TP 30
-ZIP_STAT_COMP_METHOD
+\fBZIP_STAT_COMP_METHOD\fR
 \fBcomp_method\fR
 .TP 30
-ZIP_STAT_ENCRYPTION_METHOD
+\fBZIP_STAT_ENCRYPTION_METHOD\fR
 \fBencryption_method\fR
 .TP 30
-ZIP_STAT_FLAGS
+\fBZIP_STAT_FLAGS\fR
 \fBflags\fR
 .RE
 .SH "RETURN VALUES"
diff --git a/man/zip_stat.mdoc b/man/zip_stat.mdoc
index 3d4db87..052e690 100644
--- a/man/zip_stat.mdoc
+++ b/man/zip_stat.mdoc
@@ -101,23 +101,23 @@
 .Ar valid
 before accessing the fields:
 .Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent
-.It ZIP_STAT_NAME
+.It Dv ZIP_STAT_NAME
 .Ar name
-.It ZIP_STAT_INDEX
+.It Dv ZIP_STAT_INDEX
 .Ar index
-.It ZIP_STAT_SIZE
+.It Dv ZIP_STAT_SIZE
 .Ar size
-.It ZIP_STAT_COMP_SIZE
+.It Dv ZIP_STAT_COMP_SIZE
 .Ar comp_size
-.It ZIP_STAT_MTIME
+.It Dv ZIP_STAT_MTIME
 .Ar mtime
-.It ZIP_STAT_CRC
+.It Dv ZIP_STAT_CRC
 .Ar crc
-.It ZIP_STAT_COMP_METHOD
+.It Dv ZIP_STAT_COMP_METHOD
 .Ar comp_method
-.It ZIP_STAT_ENCRYPTION_METHOD
+.It Dv ZIP_STAT_ENCRYPTION_METHOD
 .Ar encryption_method
-.It ZIP_STAT_FLAGS
+.It Dv ZIP_STAT_FLAGS
 .Ar flags
 .El
 .Sh RETURN VALUES
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt
index bf62886..cb5873c 100644
--- a/regress/CMakeLists.txt
+++ b/regress/CMakeLists.txt
@@ -6,6 +6,7 @@
   add_from_filep
   add_from_zip
   encrypt
+  fopen_unchanged
   fread
   get_comment
   name_locate
@@ -16,15 +17,49 @@
 )
 
 SET(HELPER_TEST_PROGRAMS
+  modify
+  rename
+  set_compression
+  stat_index
   tryopen
 )
 
 SET(EXTRA_TESTS
+  delete_add_same.test
+  delete_invalid.test
+  delete_last.test
+  delete_multiple_last.test
+  delete_multiple_partial.test
+  delete_renamed_rename.test
+  file_comment_encmismatch.test
+  open_cons_extrabytes.test
+  open_empty.test
+  open_empty_2.test
+  open_extrabytes.test
   open_new_but_exists.test
   open_new_ok.test
   open_nonarchive.test
   open_nosuchfile.test
   open_ok.test
+  open_truncate.test
+  rename_ascii.test
+  rename_cp437.test
+  rename_deleted.test
+  rename_fail.test
+  rename_ok.test
+  rename_utf8.test
+  rename_utf8_encmismatch.test
+  set_compression_deflate_to_deflate.test
+  set_compression_deflate_to_store.test
+  set_compression_store_to_deflate.test
+  set_compression_store_to_store.test
+  set_compression_unknown.test
+  stat_index_cp437_guess.test
+  stat_index_cp437_raw.test
+  stat_index_cp437_strict.test
+  stat_index_utf8_guess.test
+  stat_index_utf8_raw.test
+  stat_index_utf8_strict.test
 )
 
 SET(ENV{srcdir} ${CMAKE_CURRENT_SOURCE_DIR})
@@ -44,4 +79,5 @@
 ENDFOREACH(CASE ${EXTRA_TESTS})
 
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib
+	${CMAKE_CURRENT_SOURCE_DIR}/../src
 	${CMAKE_CURRENT_BINARY_DIR}/..)
diff --git a/regress/Makefile.am b/regress/Makefile.am
index 0f9ef05..58cbcb0 100644
--- a/regress/Makefile.am
+++ b/regress/Makefile.am
@@ -5,17 +5,20 @@
 	add_from_filep \
 	add_from_zip \
 	encrypt \
+	fopen_unchanged \
 	fread \
 	get_comment \
+	modify \
 	name_locate \
+	rename \
 	set_comment_all \
 	set_comment_localonly \
 	set_comment_removeglobal \
 	set_comment_revert \
+	set_compression \
+	stat_index \
 	tryopen
 
-EXTRA_PROGRAMS=deltest ziptest
-
 EXTRA_DIST= \
 	CMakeLists.txt \
 	runtest \
@@ -23,13 +26,23 @@
 	broken.zip \
 	encrypt.zip \
 	manyfiles.zip \
+	rename_ok.zip \
 	test.zip \
+	test2.zip \
+	test-cp437.zip \
+	test-cp437-fc.zip \
+	test-utf8.zip \
+	test-utf8-unmarked.zip \
 	testbuffer.zip \
 	testdir.zip \
 	testchanged.zip \
 	testchangedlocal.zip \
 	testcomment.zip \
+	testcomment13.zip \
 	testcommentremoved.zip \
+	testdeflated.zip \
+	testempty.zip \
+	testextrabytes.zip \
 	testfile.txt \
 	testfile.zip \
 	testnottorrent.zip \
@@ -42,27 +55,64 @@
 	add_dir.test \
 	add_from_buffer.test \
 	add_from_file.test \
+	add_from_file_duplicate.test \
+	add_from_file_twice_duplicate.test \
 	add_from_filep.test \
 	add_from_zip.test \
+	delete_add_same.test \
+	delete_invalid.test \
+	delete_last.test \
+	delete_multiple_last.test \
+	delete_multiple_partial.test \
+	delete_renamed_rename.test \
 	encrypt.test \
+	file_comment_encmismatch.test \
+	fopen_unchanged.test \
 	fread.test \
 	get_comment.test \
 	name_locate.test \
+	open_cons_extrabytes.test \
+	open_empty.test \
+	open_empty_2.test \
+	open_extrabytes.test \
 	open_many_ok.test \
 	open_new_but_exists.test \
 	open_new_ok.test \
 	open_nonarchive.test \
 	open_nosuchfile.test \
 	open_ok.test \
+	open_truncate.test \
+	rename_ascii.test \
+	rename_cp437.test \
+	rename_deleted.test \
+	rename_fail.test \
+	rename_ok.test \
+	rename_utf8.test \
+	rename_utf8_encmismatch.test \
 	set_comment_all.test \
 	set_comment_localonly.test \
 	set_comment_removeglobal.test \
 	set_comment_revert.test \
+	set_compression_deflate_to_deflate.test \
+	set_compression_deflate_to_store.test \
+	set_compression_store_to_deflate.test \
+	set_compression_store_to_store.test \
+	set_compression_unknown.test \
+	stat_index_cp437_guess.test \
+	stat_index_cp437_raw.test \
+	stat_index_cp437_strict.test \
+	stat_index_utf8_guess.test \
+	stat_index_utf8_raw.test \
+	stat_index_utf8_strict.test \
+	stat_index_utf8_unmarked_strict.test \
 	torrent-already.test \
 	torrent-new.test
-# problems with comparing stderr output
-NOTYET= \
-	add_from_file_duplicate.test
 
-AM_CPPFLAGS=-I${top_srcdir}/lib
+DISABLED_TESTS= \
+	encoding-ascii.test \
+	encoding-cp437.test \
+	encoding-cp437-all.test \
+	encoding-utf-8.test
+
+AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib -I${top_srcdir}/src
 LDADD=${top_builddir}/lib/libzip.la
diff --git a/regress/add_dir.c b/regress/add_dir.c
index ddd6758..6294d97 100644
--- a/regress/add_dir.c
+++ b/regress/add_dir.c
@@ -67,7 +67,7 @@
     
     if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
 	zip_error_to_str(buf, sizeof(buf), err, errno);
-	fprintf(stderr, "%s: can't open zip archive %s: %s\n", prg,
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
 		archive, buf);
 	return 1;
     }
@@ -81,8 +81,8 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive %s\n", prg,
-		archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/add_from_buffer.c b/regress/add_from_buffer.c
index 40efd21..f3fa7e9 100644
--- a/regress/add_from_buffer.c
+++ b/regress/add_from_buffer.c
@@ -64,7 +64,7 @@
     
     if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
 	zip_error_to_str(buf, sizeof(buf), err, errno);
-	fprintf(stderr, "%s: can't open zip archive %s: %s\n", prg,
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
 		archive, buf);
 	return 1;
     }
@@ -83,8 +83,8 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive %s\n", prg,
-		archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/add_from_file.c b/regress/add_from_file.c
index cbcf5d9..d4decbd 100644
--- a/regress/add_from_file.c
+++ b/regress/add_from_file.c
@@ -52,45 +52,50 @@
     struct zip_source *zs;
     char buf[100];
     int err;
+    int i;
+    int ret = 0;
 
     prg = argv[0];
 
-    if (argc != 3) {
-	fprintf(stderr, "usage: %s archive file\n", prg);
+    if (argc < 3) {
+	fprintf(stderr, "usage: %s archive file [file ...]\n", prg);
 	return 1;
     }
 
     archive = argv[1];
-    file = argv[2];
-    
     if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
 	zip_error_to_str(buf, sizeof(buf), err, errno);
-	fprintf(stderr, "%s: can't open zip archive %s: %s\n", prg,
+	fprintf(stderr, "can't open zip archive `%s': %s\n",
 		archive, buf);
 	return 1;
     }
 
-    if ((zs=zip_source_file(za, file, 0, -1)) == NULL) {
-	fprintf(stderr, "%s: error creating file source for `%s': %s\n", prg,
-		file, zip_strerror(za));
-	return 1;
-    }
+    for (i=2; i<argc; i++) {
+	file = argv[i];
+    
+	if ((zs=zip_source_file(za, file, 0, -1)) == NULL) {
+	    fprintf(stderr, "error creating file source for `%s': %s\n",
+		    file, zip_strerror(za));
+	    ret = 1;
+	    continue;
+	}
 
-    if ((name=strrchr(file, '/')) == NULL)
-	name = file;
+	if ((name=strrchr(file, '/')) == NULL)
+	    name = file;
 
-    if (zip_add(za, name, zs) == -1) {
-	zip_source_free(zs);
-	fprintf(stderr, "%s: can't add file `%s': %s\n", prg,
-		file, zip_strerror(za));
-	return 1;
+	if (zip_add(za, name, zs) == -1) {
+	    zip_source_free(zs);
+	    fprintf(stderr, "can't add file `%s': %s\n",
+		    file, zip_strerror(za));
+	    ret = 1;
+	}
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg,
-		archive);
+	fprintf(stderr, "can't close zip archive `%s': %s\n",
+		archive, zip_strerror(za));
 	return 1;
     }
 
-    return 0;
+    return ret;
 }
diff --git a/regress/add_from_file_twice_duplicate.test b/regress/add_from_file_twice_duplicate.test
new file mode 100644
index 0000000..287624c
--- /dev/null
+++ b/regress/add_from_file_twice_duplicate.test
@@ -0,0 +1,7 @@
+# add file to zip twice, making duplicate names
+program add_from_file
+return 1
+args testfile.zip testfile.txt testfile.txt
+file testfile.txt testfile.txt testfile.txt
+file-new testfile.zip testfile.zip
+stderr can't add file `testfile.txt': File already exists
diff --git a/regress/add_from_filep.c b/regress/add_from_filep.c
index 059e957..e4edb35 100644
--- a/regress/add_from_filep.c
+++ b/regress/add_from_filep.c
@@ -66,7 +66,7 @@
     
     if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
 	zip_error_to_str(buf, sizeof(buf), err, errno);
-	fprintf(stderr, "%s: can't open zip archive %s: %s\n", prg,
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
 		archive, buf);
 	return 1;
     }
@@ -94,8 +94,8 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg,
-		archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/add_from_zip.c b/regress/add_from_zip.c
index f509fb7..bdea8c5 100644
--- a/regress/add_from_zip.c
+++ b/regress/add_from_zip.c
@@ -68,7 +68,7 @@
 
     if ((z_in=zip_open(source, ZIP_CHECKCONS, &err)) == NULL) {
 	zip_error_to_str(buf, sizeof(buf), err, errno);
-	fprintf(stderr, "%s: can't open source zip archive %s: %s\n", prg,
+	fprintf(stderr, "%s: can't open source zip archive `%s': %s\n", prg,
 		source, buf);
 	return 1;
     }
@@ -101,8 +101,8 @@
     }
 
     if (zip_close(z_out) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg,
-		archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(z_out));
 	return 1;
     }
 
diff --git a/regress/add_from_zip.test b/regress/add_from_zip.test
index 53dcfd7..0a20c2e 100644
--- a/regress/add_from_zip.test
+++ b/regress/add_from_zip.test
@@ -1,6 +1,6 @@
 # add file from zip to zip
 program add_from_zip
 return 0
-args teststored.zip testfile.zip empty.txt
+args teststored.zip testfile.zip abac-repeat.txt
 file teststored.zip teststored.zip teststored.zip
 file-new testfile.zip teststored.zip
diff --git a/regress/add_invalid.c b/regress/add_invalid.c
deleted file mode 100644
index 01b2e27..0000000
--- a/regress/add_invalid.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "zip.h"
-#include "error.h"
-
-char *prg;
-#define BUFSIZE 65536
-
-int
-main(int argc, char *argv[])
-{
-    struct zip *za, *destza;
-    
-    prg = argv[0];
-    
-    if (argc != 3) {
-	myerror(ERRDEF, "call with two options: src dest\n");
-	return 1;
-    }
-
-    seterrinfo(NULL, argv[1]);
-    if ((za=zip_open(argv[1], 0))==NULL) {
-	myerror(ERRZIPSTR, "can't open file: %s", zip_err_str[zip_err]);
-	return 1;
-    }
-
-    seterrinfo(NULL, argv[2]);
-    if ((destza=zip_open(argv[2], ZIP_CREATE))==NULL) {
-	myerror(ERRZIPSTR, "can't open file: %s", zip_err_str[zip_err]);
-	return 1;
-    }
-
-    if (zip_add_zip(destza, NULL, NULL, za, 1, 0, 0) == -1)
-	myerror(ERRZIPSTR, "can't add file to zip-file: %s", zip_err_str[zip_err]);
-
-    if (zip_close(destza)!=0) {
-	myerror(ERRZIPSTR, "can't close file: %s", zip_err_str[zip_err]);
-	return 1;
-    }
-
-    seterrinfo(NULL, argv[1]);
-    if (zip_close(za)!=0) {
-	myerror(ERRZIPSTR, "can't close file %s", zip_err_str[zip_err]);
-	return 1;
-    }
-    
-    return 0;
-}
diff --git a/regress/mkname.c b/regress/cp437.c
similarity index 69%
rename from regress/mkname.c
rename to regress/cp437.c
index 647e836..8ead593 100644
--- a/regress/mkname.c
+++ b/regress/cp437.c
@@ -1,6 +1,6 @@
 /*
-  mkname.c -- add srcdir to name
-  Copyright (C) 2005 Dieter Baron and Thomas Klausner
+  cp437.c -- tool for CP437 decoding tests
+  Copyright (C) 2011 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>
@@ -31,49 +31,32 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "mkname.h"
+#include "zip.h"
+#include "zipint.h"
 
-
-
-const char *
-mkname(const char *name)
+int
+main(int argc, char *argv[])
 {
-    static const char *srcdir;
-    static char *fullname;
-    static int len = 0;
-    static int srcdir_done = 0;
+    unsigned char in[256];
+    unsigned char *out;
+    int i;
+    struct zip_error err;
 
-    int nlen;
-
-    if (!srcdir_done) {
-	srcdir = getenv("SRCDIR");
-	srcdir_done = 1;
+#if 0
+    if (argc != 1) {
+	fprintf(stderr, "usage: %s\n", argv[0]);
+	exit(1);
     }
+#endif
+    for (i=0; i<256; i++)
+	in[i] = i+1;
 
-    if (!srcdir)
-	return name;
+    out = _zip_cp437_to_utf8(in, 256, &err);
+    printf("UTF-8 version: %s\n", out ? (char *)out : "(conversion error)");
 
-    nlen = strlen(srcdir) + strlen(name) + 2;
-
-    if (nlen > len) {
-	if (len == 0)
-	    fullname = malloc(nlen);
-	else
-	    fullname = realloc(fullname, nlen);
-
-	if (fullname == NULL) {
-	    fprintf(stderr, "malloc failure\n");
-	    exit(2);
-	}
-    }
-
-    sprintf(fullname, "%s/%s", srcdir, name);
-
-    return fullname;
+    exit(0);
 }
diff --git a/regress/delete_add_same.test b/regress/delete_add_same.test
new file mode 100644
index 0000000..7974d89
--- /dev/null
+++ b/regress/delete_add_same.test
@@ -0,0 +1,5 @@
+# delete entry in zip archive then add file of same name
+program modify
+return 0
+args testfile.zip delete 0 add testfile.txt test
+file testfile.zip testfile.zip test2.zip
diff --git a/regress/delete_invalid.test b/regress/delete_invalid.test
new file mode 100644
index 0000000..82e9bcf
--- /dev/null
+++ b/regress/delete_invalid.test
@@ -0,0 +1,6 @@
+# delete last entry in zip archive
+program modify
+return 0
+args testfile.zip delete 5
+file testfile.zip testfile.zip testfile.zip
+stderr can't delete file at index `5': Invalid argument
diff --git a/regress/delete_last.test b/regress/delete_last.test
new file mode 100644
index 0000000..cd2ab6b
--- /dev/null
+++ b/regress/delete_last.test
@@ -0,0 +1,5 @@
+# delete last entry in zip archive
+program modify
+return 0
+args testfile.zip delete 0
+file-del testfile.zip testfile.zip
diff --git a/regress/delete_multiple_last.test b/regress/delete_multiple_last.test
new file mode 100644
index 0000000..441a9b3
--- /dev/null
+++ b/regress/delete_multiple_last.test
@@ -0,0 +1,5 @@
+# delete multiple entries in zip archive, emptying it
+program modify
+return 0
+args testfile.zip delete 0 delete 1 delete 2 delete 3
+file-del testfile.zip testcomment.zip
diff --git a/regress/delete_multiple_partial.test b/regress/delete_multiple_partial.test
new file mode 100644
index 0000000..9e6dcc5
--- /dev/null
+++ b/regress/delete_multiple_partial.test
@@ -0,0 +1,5 @@
+# delete some entries in zip archive
+program modify
+return 0
+args testfile.zip delete 1 delete 3
+file testfile.zip testcomment.zip testcomment13.zip
diff --git a/regress/delete_renamed_rename.test b/regress/delete_renamed_rename.test
new file mode 100644
index 0000000..f60895b
--- /dev/null
+++ b/regress/delete_renamed_rename.test
@@ -0,0 +1,5 @@
+# delete renamed entry in zip archive then rename file to same name
+program modify
+return 0
+args testfile.zip rename 0 something add test test delete 0 rename 1 testfile.txt
+file testfile.zip testfile.zip test2.zip
diff --git a/regress/deltest.c b/regress/deltest.c
deleted file mode 100644
index 87991e5..0000000
--- a/regress/deltest.c
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "zip.h"
-#include "error.h"
-
-char *prg;
-#define BUFSIZE 65536
-
-int
-main(int argc, char *argv[])
-{
-    struct zip *za;
-
-    if (argc != 2) {
-	fprintf(stderr, "%s: call with one option: zip-file. First file"
-		" in zip-file will be deleted\n", argv[0]);
-	return 1;
-    }
-
-    if ((za=zip_open(argv[1], ZIP_CHECKCONS))==NULL) {
-	fprintf(stderr, "%s: can't open '%s': %s\n", argv[0], argv[1],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-
-    if (zip_delete(za, 0)< 0) {
-	fprintf(stderr, "%s: can't delete first file in '%s': %s", 
-		argv[0], argv[1], zip_err_str[zip_err]);
-	return 1;
-    }
-
-    if (zip_close(za)!=0) {
-	fprintf(stderr, "%s: can't close file '%s': %s", argv[0], argv[1],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-    
-    return 0;
-}
diff --git a/regress/encoding-ascii.test b/regress/encoding-ascii.test
new file mode 100644
index 0000000..5d086f8
--- /dev/null
+++ b/regress/encoding-ascii.test
@@ -0,0 +1,5 @@
+# recognize ASCII
+program encoding
+return 0
+args ABC%^&&*!@#_.as./-
+stdout guessing ABC%^&&*!@#_.as./-: ASCII
diff --git a/regress/encoding-cp437-all.test b/regress/encoding-cp437-all.test
new file mode 100644
index 0000000..1e5ca73
--- /dev/null
+++ b/regress/encoding-cp437-all.test
@@ -0,0 +1,5 @@
+# convert all CP437
+program cp437
+return 0
+args ""
+stdout UTF-8 version: ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■  
diff --git a/regress/encoding-cp437.test b/regress/encoding-cp437.test
new file mode 100644
index 0000000..184c477
--- /dev/null
+++ b/regress/encoding-cp437.test
@@ -0,0 +1,6 @@
+# recognize CP437
+program encoding
+return 0
+args TestŽ™Ašá^$
+stdout guessing TestŽ™Ašá^$: CP437
+stdout UTF-8 version: TestÄÖAÜß^$
diff --git a/regress/encoding-utf-8.test b/regress/encoding-utf-8.test
new file mode 100644
index 0000000..74e431b
--- /dev/null
+++ b/regress/encoding-utf-8.test
@@ -0,0 +1,5 @@
+# recognize UTF-8
+program encoding
+return 0
+args TestÄÖAÜß^$
+stdout guessing TestÄÖAÜß^$: UTF-8
diff --git a/regress/mkname.c b/regress/encoding.c
similarity index 68%
copy from regress/mkname.c
copy to regress/encoding.c
index 647e836..7ba76d0 100644
--- a/regress/mkname.c
+++ b/regress/encoding.c
@@ -1,6 +1,6 @@
 /*
-  mkname.c -- add srcdir to name
-  Copyright (C) 2005 Dieter Baron and Thomas Klausner
+  encoding.c -- tool for encoding tests
+  Copyright (C) 2011 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>
@@ -31,49 +31,37 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "mkname.h"
+#include "zip.h"
+#include "zipint.h"
 
-
+const char *result[] = {
+    "ASCII",
+    "UTF-8",
+    "CP437"
+};
 
-const char *
-mkname(const char *name)
+int
+main(int argc, char *argv[])
 {
-    static const char *srcdir;
-    static char *fullname;
-    static int len = 0;
-    static int srcdir_done = 0;
+    int ret;
+    const char *conv = NULL;
+    struct zip_error err;
 
-    int nlen;
+    if (argc != 2) {
+	fprintf(stderr, "usage: %s string_to_guess\n", argv[0]);
+	exit(1);
+    }
+    ret = _zip_guess_encoding((const zip_uint8_t *)argv[1], strlen(argv[1]));
 
-    if (!srcdir_done) {
-	srcdir = getenv("SRCDIR");
-	srcdir_done = 1;
+    printf("guessing %s: %s\n", argv[1], result[ret]);
+    if (ret == ZIP_ENCODING_CP437) {
+	conv = (const char *)_zip_cp437_to_utf8((const zip_uint8_t *)argv[1], strlen(argv[1]), &err);
+	printf("UTF-8 version: %s\n", conv ? conv : "(conversion error)");
     }
 
-    if (!srcdir)
-	return name;
-
-    nlen = strlen(srcdir) + strlen(name) + 2;
-
-    if (nlen > len) {
-	if (len == 0)
-	    fullname = malloc(nlen);
-	else
-	    fullname = realloc(fullname, nlen);
-
-	if (fullname == NULL) {
-	    fprintf(stderr, "malloc failure\n");
-	    exit(2);
-	}
-    }
-
-    sprintf(fullname, "%s/%s", srcdir, name);
-
-    return fullname;
+    exit(0);
 }
diff --git a/regress/encrypt.c b/regress/encrypt.c
index d5b00ca..41a879e 100644
--- a/regress/encrypt.c
+++ b/regress/encrypt.c
@@ -77,7 +77,7 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/file_comment_encmismatch.test b/regress/file_comment_encmismatch.test
new file mode 100644
index 0000000..18fa655
--- /dev/null
+++ b/regress/file_comment_encmismatch.test
@@ -0,0 +1,6 @@
+# set file comment to UTF-8 for CP437 encoded filename (fails)
+program modify
+return 0
+args testfile file_comment 0 ÄÖÜßäöü
+file testfile test-cp437.zip test-cp437.zip
+stderr can't set file comment at index `0' to `ÄÖÜßäöü': Encoding of name and comment do not match
diff --git a/regress/fileadd.c b/regress/fileadd.c
deleted file mode 100644
index 83ce168..0000000
--- a/regress/fileadd.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "zip.h"
-
-int
-main(int argc, char *argv[])
-{
-    struct zip *za;
-    int i;
-
-    if (argc < 3) {
-	fprintf(stderr, "%s: need at least two arguments: zipfile"
-		" and files to add\n", argv[0]);
-	exit(1);
-    }
-
-    if ((za=zip_open(argv[1], ZIP_CHECKCONS|ZIP_CREATE)) == NULL) {
-	fprintf(stderr, "%s: can't open zipfile %s: %s\n", argv[0],
-		argv[1], zip_err_str[zip_err]);
-	exit(1);
-    }
-
-    for (i=0; i<argc-2; i++)
-	if (zip_add_file(za, NULL, NULL, argv[i+2], 0, -1)==-1) {
-	    fprintf(stderr, "%s: can't add file %s: %s\n", argv[0],
-		    argv[i+2], zip_err_str[zip_err]);
-	    exit(1);
-	}
-
-    if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zipfile %s: %s\n", argv[0],
-		argv[1], zip_err_str[zip_err]);
-	exit(1);
-    }
-
-    return 0;
-}
diff --git a/regress/fopen_unchanged.c b/regress/fopen_unchanged.c
new file mode 100644
index 0000000..2df665f
--- /dev/null
+++ b/regress/fopen_unchanged.c
@@ -0,0 +1,99 @@
+/*
+  fopen_unchanged.c -- test case for adding file and reading from unchanged
+  Copyright (C) 2012 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zip.h"
+
+const char *teststr="This is a test.\n";
+const char *file="teststring.txt";
+const char *prg;
+
+int
+main(int argc, char *argv[])
+{
+    const char *archive;
+    struct zip *za;
+    struct zip_source *zs;
+    char buf[100];
+    int err;
+
+    prg = argv[0];
+
+    if (argc != 2) {
+	fprintf(stderr, "usage: %s archive\n", prg);
+	return 1;
+    }
+
+    archive = argv[1];
+    
+    if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
+	zip_error_to_str(buf, sizeof(buf), err, errno);
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
+		archive, buf);
+	return 1;
+    }
+
+    if ((zs=zip_source_buffer(za, teststr, strlen(teststr), 0)) == NULL) {
+	fprintf(stderr, "%s: can't create zip_source from buffer: %s\n", prg,
+		zip_strerror(za));
+	exit(1);
+    }
+
+    if (zip_add(za, file, zs) == -1) {
+	zip_source_free(zs);
+	fprintf(stderr, "%s: can't add file `%s': %s\n", prg,
+		file, zip_strerror(za));
+	return 1;
+    }
+
+    if (zip_fopen(za, file, ZIP_FL_UNCHANGED) == NULL) {
+	/* expected error, don't pollute with prg */
+	fprintf(stderr, "can't zip_fopen file `%s': %s\n",
+		file, zip_strerror(za));
+	return 1;
+    }
+
+    if (zip_close(za) == -1) {
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(za));
+	return 1;
+    }
+
+    return 0;
+}
diff --git a/regress/fopen_unchanged.test b/regress/fopen_unchanged.test
new file mode 100644
index 0000000..5e55d0c
--- /dev/null
+++ b/regress/fopen_unchanged.test
@@ -0,0 +1,5 @@
+# add buffer contents as file to zip, then read unchanged from it
+program fopen_unchanged
+return 1
+args testbuffer.zip
+stderr can't zip_fopen file `teststring.txt': No such file
diff --git a/regress/fread.c b/regress/fread.c
index 9080b8a..258a070 100644
--- a/regress/fread.c
+++ b/regress/fread.c
@@ -75,7 +75,7 @@
 
     if ((z=zip_open(archive, 0, &ze)) == NULL) {
 	zip_error_to_str(errstr, sizeof(errstr), ze, errno);
-	printf("%s: opening zip archive ``%s'' failed: %s\n",
+	printf("%s: can't open zip archive `%s': %s\n",
 	       prg, archive, errstr);
 	return 1;
     }
@@ -113,7 +113,7 @@
     zip_unchange_all(z);
 
     if (zip_close(z) == -1) {
-        fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+        fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(z));
         return 1;
     }
 
diff --git a/regress/get_comment.c b/regress/get_comment.c
index 62a521f..2446f5a 100644
--- a/regress/get_comment.c
+++ b/regress/get_comment.c
@@ -81,7 +81,7 @@
     }	
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/mkname.h b/regress/mkname.h
deleted file mode 100644
index d85bde5..0000000
--- a/regress/mkname.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef HAD_MKNAME_H
-
-const char *mkname(const char *);
-
-#endif /* mkname.h */
diff --git a/regress/modify.c b/regress/modify.c
new file mode 100644
index 0000000..2de8201
--- /dev/null
+++ b/regress/modify.c
@@ -0,0 +1,128 @@
+/*
+  modify.c -- test case for modifying zip archive in multiple ways
+  Copyright (C) 2012 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zip.h"
+
+const char *prg;
+
+int
+main(int argc, char *argv[])
+{
+    const char *archive;
+    struct zip *za;
+    struct zip_source *zs;
+    char buf[100];
+    int err;
+    int arg;
+    int idx;
+
+    arg = 0;
+    prg = argv[arg++];
+
+    if (argc < 2) {
+	fprintf(stderr, "usage: %s archive [add name content|add_dir name|delete index|file_comment index comment|rename index name]\n", prg);
+	return 1;
+    }
+
+    archive = argv[arg++];
+    
+    if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) {
+	zip_error_to_str(buf, sizeof(buf), err, errno);
+	fprintf(stderr, "can't open zip archive `%s': %s\n", archive, buf);
+	return 1;
+    }
+
+    while (arg < argc) {
+	if (strcmp(argv[arg], "add") == 0 && arg+2 < argc) {
+	    /* add */
+    	    if ((zs=zip_source_buffer(za, argv[arg+2], strlen(argv[arg+2]), 0)) == NULL) {
+		fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
+		break;
+	    }
+
+	    if (zip_add(za, argv[arg+1], zs) == -1) {
+		zip_source_free(zs);
+		fprintf(stderr, "can't add file `%s': %s\n", argv[arg+1], zip_strerror(za));
+		break;
+	    }
+	    arg += 3;
+	} else if (strcmp(argv[arg], "add_dir") == 0 && arg+1 < argc) {
+	    /* add directory */
+	    if (zip_add_dir(za, argv[arg+1]) < 0) {
+		fprintf(stderr, "can't add directory `%s': %s\n", argv[arg+1], zip_strerror(za));
+		break;
+	    }
+	    arg += 2;
+	} else if (strcmp(argv[arg], "delete") == 0 && arg+1 < argc) {
+	    /* delete */
+	    idx = atoi(argv[arg+1]);
+	    if (zip_delete(za, idx) < 0) {
+		fprintf(stderr, "can't delete file at index `%d': %s\n", idx, zip_strerror(za));
+		break;
+	    }
+	    arg += 2;
+	} else if (strcmp(argv[arg], "file_comment") == 0 && arg+2 < argc) {
+	    /* set file comment */
+	    idx = atoi(argv[arg+1]);
+	    if (zip_set_file_comment(za, idx, argv[arg+2], strlen(argv[arg+2])) < 0) {
+		fprintf(stderr, "can't set file comment at index `%d' to `%s': %s\n", idx, argv[arg+2], zip_strerror(za));
+		break;
+	    }
+	    arg += 3;
+	} else if (strcmp(argv[arg], "rename") == 0 && arg+2 < argc) {
+	    /* rename */
+	    idx = atoi(argv[arg+1]);
+	    if (zip_rename(za, idx, argv[arg+2]) < 0) {
+		fprintf(stderr, "can't rename file at index `%d' to `%s': %s\n", idx, argv[arg+2], zip_strerror(za));
+		break;
+	    }
+	    arg += 3;
+	} else {
+	    fprintf(stderr, "unrecognized command `%s'\n", argv[arg]);
+	    break;
+	}
+    }
+
+    if (zip_close(za) == -1) {
+	fprintf(stderr, "can't close zip archive `%s': %s\n", archive, zip_strerror(za));
+	return 1;
+    }
+
+    return 0;
+}
diff --git a/regress/name_locate.c b/regress/name_locate.c
index 62d3714..eb997c5 100644
--- a/regress/name_locate.c
+++ b/regress/name_locate.c
@@ -64,8 +64,10 @@
     archive = argv[1];
 
     if ((z=zip_open(archive, 0, &ze)) == NULL) {
-	printf("%s: opening zip archive ``%s'' failed (%d)\n", prg,
-	       archive, ze);
+        char buf[100];
+        zip_error_to_str(buf, sizeof(buf), ze, errno);
+	printf("%s: can't open zip archive `%s': %s\n", prg,
+	       archive, buf);
 	return 1;
     }
 
@@ -88,8 +90,8 @@
     fail += find_success(z, "test", 0);
 
     if (zip_close(z) == -1) {
-	fprintf(stderr, "%s: can't close zip archive %s\n", prg,
-		archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(z));
 	return 1;
     }
 
@@ -108,8 +110,8 @@
 	zip_error_get(z, &ze, &se);
 	if (ze != zerr) {
 	    zip_error_to_str(expected, sizeof(expected), zerr, 0);
-	    printf("%s: unexpected error while looking for ``%s'': "
-		   "got ``%s'', expected ``%s''\n", prg, name,
+	    printf("%s: unexpected error while looking for `%s': "
+		   "got `%s', expected `%s'\n", prg, name,
 		   zip_strerror(z), expected);
 	    return 1;
 	}
@@ -127,7 +129,7 @@
 {
 
     if (zip_name_locate(z, name, flags) < 0) {
-	printf("%s: unexpected error while looking for ``%s'': %s\n",
+	printf("%s: unexpected error while looking for `%s': %s\n",
 	       prg, name, zip_strerror(z));
 	return 1;
     }
diff --git a/regress/open_cons_extrabytes.test b/regress/open_cons_extrabytes.test
new file mode 100644
index 0000000..8fdf2cc
--- /dev/null
+++ b/regress/open_cons_extrabytes.test
@@ -0,0 +1,6 @@
+# zip_open: file has extra bytes at end of archive
+program tryopen
+file testextrabytes.zip testextrabytes.zip testextrabytes.zip
+args -c testextrabytes.zip
+return 1
+stdout opening `testextrabytes.zip' returned error 21
diff --git a/regress/open_empty.test b/regress/open_empty.test
new file mode 100644
index 0000000..250bc40
--- /dev/null
+++ b/regress/open_empty.test
@@ -0,0 +1,6 @@
+# zip_open: file contains no entry, but is valid
+program tryopen
+file testempty.zip testempty.zip testempty.zip
+args testempty.zip
+return 0
+stdout opening `testempty.zip' succeeded, 0 entries
diff --git a/regress/open_empty_2.test b/regress/open_empty_2.test
new file mode 100644
index 0000000..0f6e215
--- /dev/null
+++ b/regress/open_empty_2.test
@@ -0,0 +1,6 @@
+# zip_open: 0 size file is recognized as empty zip
+program tryopen
+file testfile.txt testfile.txt testfile.txt
+args testfile.txt
+return 0
+stdout opening `testfile.txt' succeeded, 0 entries
diff --git a/regress/open_extrabytes.test b/regress/open_extrabytes.test
new file mode 100644
index 0000000..e647373
--- /dev/null
+++ b/regress/open_extrabytes.test
@@ -0,0 +1,6 @@
+# zip_open: file has extra bytes at end of archive
+program tryopen
+file testextrabytes.zip testextrabytes.zip testextrabytes.zip
+args testextrabytes.zip
+return 0
+stdout opening `testextrabytes.zip' succeeded, 1 entries
diff --git a/regress/open_new_but_exists.test b/regress/open_new_but_exists.test
index 612c8c9..9fb0460 100644
--- a/regress/open_new_but_exists.test
+++ b/regress/open_new_but_exists.test
@@ -3,4 +3,4 @@
 args -e test.zip
 return 1
 file test.zip test.zip test.zip
-stdout opening `test.zip' returned error 10/0
+stdout opening `test.zip' returned error 10
diff --git a/regress/open_nonarchive.test b/regress/open_nonarchive.test
index b523abf..979a26e 100644
--- a/regress/open_nonarchive.test
+++ b/regress/open_nonarchive.test
@@ -3,4 +3,4 @@
 file Makefile.am Makefile.am Makefile.am
 args Makefile.am
 return 1
-stdout opening `Makefile.am' returned error 19/2
+stdout opening `Makefile.am' returned error 19
diff --git a/regress/open_truncate.test b/regress/open_truncate.test
new file mode 100644
index 0000000..ac23068
--- /dev/null
+++ b/regress/open_truncate.test
@@ -0,0 +1,6 @@
+# zip_open: file opens fine and gets truncated
+program tryopen
+args -t test.zip
+return 0
+file-del test.zip test.zip
+stdout opening `test.zip' succeeded, 0 entries
diff --git a/regress/rename.c b/regress/rename.c
new file mode 100644
index 0000000..8b379cf
--- /dev/null
+++ b/regress/rename.c
@@ -0,0 +1,95 @@
+/*
+  rename.c -- test cases for renaming files in zip archives
+  Copyright (C) 2012 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "zip.h"
+
+const char *prg;
+
+
+
+int
+main(int argc, char *argv[])
+{
+    zip_uint64_t idx;
+    int ze;
+    struct zip *z;
+    const char *archive;
+    const char *oldname;
+    const char *newname;
+
+    prg = argv[0];
+
+    if (argc != 4) {
+        fprintf(stderr, "usage: %s archive oldname newname\n", prg);
+        return 1;
+    }
+
+    archive = argv[1];
+    oldname = argv[2];
+    newname = argv[3];
+
+    if ((z=zip_open(archive, 0, &ze)) == NULL) {
+	char buf[100];
+	zip_error_to_str(buf, sizeof(buf), ze, errno);
+	printf("%s: can't open zip archive `%s': %s\n", prg,
+	       archive, buf);
+	return 1;
+    }
+
+    if ((idx=zip_name_locate(z, oldname, 0)) < 0) {
+	printf("%s: unexpected error while looking for `%s': %s\n",
+	       prg, oldname, zip_strerror(z));
+	return 1;
+    }
+
+    if (zip_rename(z, idx, newname) < 0) {
+	/* expected error, so no prg prefix */
+	printf("error renaming `%s' to `%s': %s\n",
+	       oldname, newname, zip_strerror(z));
+	return 1;
+    }
+
+    if (zip_close(z) == -1) {
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg,
+		archive, zip_strerror(z));
+	return 1;
+    }
+
+    exit(0);
+}
diff --git a/regress/rename_ascii.test b/regress/rename_ascii.test
new file mode 100644
index 0000000..bab7301
--- /dev/null
+++ b/regress/rename_ascii.test
@@ -0,0 +1,5 @@
+# rename file to ASCII name in zip archive
+program modify
+return 0
+args testfile rename 0 testfile.txt
+file testfile testfile-UTF8.zip testfile.zip
diff --git a/regress/rename_cp437.test b/regress/rename_cp437.test
new file mode 100644
index 0000000..6596afd
--- /dev/null
+++ b/regress/rename_cp437.test
@@ -0,0 +1,6 @@
+# rename file to CP437 name in zip archive (fails)
+program modify
+return 0
+args testfile.zip rename 0 ‚ƒ„…†‡ˆ‰Š‹ŒŽ
+file testfile.zip testfile.zip testfile.zip
+stderr can't rename file at index `0' to `‚ƒ„…†‡ˆ‰Š‹ŒŽ': Invalid argument
diff --git a/regress/rename_deleted.test b/regress/rename_deleted.test
new file mode 100644
index 0000000..a5ae64b
--- /dev/null
+++ b/regress/rename_deleted.test
@@ -0,0 +1,6 @@
+# rename deleted entry in zip archive (fails)
+program modify
+return 0
+args testfile.zip delete 1 delete 3 rename 1 othername
+file testfile.zip testcomment.zip testcomment13.zip
+stderr can't rename file at index `1' to `othername': Entry has been deleted
diff --git a/regress/rename_fail.test b/regress/rename_fail.test
new file mode 100644
index 0000000..cd95c54
--- /dev/null
+++ b/regress/rename_fail.test
@@ -0,0 +1,6 @@
+# rename file inside zip archive, but file name already exists
+program rename
+return 1
+args rename.zip file2 file4
+file rename.zip testcomment.zip testcomment.zip
+stdout error renaming `file2' to `file4': File already exists
diff --git a/regress/rename_ok.test b/regress/rename_ok.test
new file mode 100644
index 0000000..efff5c5
--- /dev/null
+++ b/regress/rename_ok.test
@@ -0,0 +1,5 @@
+# rename file inside zip archive
+program rename
+return 0
+args rename.zip file2 notfile2
+file rename.zip testcomment.zip rename_ok.zip
diff --git a/regress/rename_ok.zip b/regress/rename_ok.zip
new file mode 100644
index 0000000..ad07306
--- /dev/null
+++ b/regress/rename_ok.zip
Binary files differ
diff --git a/regress/rename_utf8.test b/regress/rename_utf8.test
new file mode 100644
index 0000000..25b92f0
--- /dev/null
+++ b/regress/rename_utf8.test
@@ -0,0 +1,5 @@
+# rename file to UTF-8 name in zip archive
+program modify
+return 0
+args testfile rename 0 ÄÖÜßäöü
+file testfile testfile.zip testfile-UTF8.zip
diff --git a/regress/rename_utf8_encmismatch.test b/regress/rename_utf8_encmismatch.test
new file mode 100644
index 0000000..b45ff0f
--- /dev/null
+++ b/regress/rename_utf8_encmismatch.test
@@ -0,0 +1,6 @@
+# rename file to UTF-8 name in zip archive with CP437 comment (fails)
+program modify
+return 0
+args testfile rename 0 ÄÖÜßäöü
+file testfile test-cp437-fc.zip test-cp437-fc.zip
+stderr can't rename file at index `0' to `ÄÖÜßäöü': Encoding of name and comment do not match
diff --git a/regress/runtest b/regress/runtest
index a104251..2d397e2 100755
--- a/regress/runtest
+++ b/regress/runtest
@@ -288,7 +288,7 @@
     test_empty "${RET}" return
     RET="$arg";;
   stderr)
-    echo "${PROGRAM}: $arg" >> stderr;;
+    echo "$arg" >> stderr;;
   stdout)
     echo "$arg" >> stdout;;
   *)
diff --git a/regress/set_comment_all.c b/regress/set_comment_all.c
index 489a272..be886f0 100644
--- a/regress/set_comment_all.c
+++ b/regress/set_comment_all.c
@@ -1,6 +1,6 @@
 /*
   set_comment_all.c -- set global and file comments
-  Copyright (C) 2006 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -38,7 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "zip.h"
+#include "zipint.h"
 
 const char *prg;
 const char *new_archive_comment="This is the new,\r\n"
@@ -87,7 +87,7 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/set_comment_localonly.c b/regress/set_comment_localonly.c
index 55e25d3..b01ff21 100644
--- a/regress/set_comment_localonly.c
+++ b/regress/set_comment_localonly.c
@@ -1,6 +1,6 @@
 /*
   set_comment_localonly.c -- set file comments
-  Copyright (C) 2006 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -38,7 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "zip.h"
+#include "zipint.h"
 
 const char *prg;
 
@@ -83,7 +83,7 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/set_comment_removeglobal.c b/regress/set_comment_removeglobal.c
index c8ff6c5..2792372 100644
--- a/regress/set_comment_removeglobal.c
+++ b/regress/set_comment_removeglobal.c
@@ -1,6 +1,6 @@
 /*
   set_comment_removeglobal.c -- remove archive comment
-  Copyright (C) 2006 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -38,7 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "zip.h"
+#include "zipint.h"
 
 const char *prg;
 
@@ -73,7 +73,7 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/set_comment_revert.c b/regress/set_comment_revert.c
index 46a1b85..cd5611f 100644
--- a/regress/set_comment_revert.c
+++ b/regress/set_comment_revert.c
@@ -1,6 +1,6 @@
 /*
   set_comment_revert.c -- set global and file comments, but revert
-  Copyright (C) 2006 Dieter Baron and Thomas Klausner
+  Copyright (C) 2006-2012 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>
@@ -38,7 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "zip.h"
+#include "zipint.h"
 
 const char *prg;
 const char *new_archive_comment="This is the new,\r\n"
@@ -93,7 +93,7 @@
     }
 
     if (zip_close(za) == -1) {
-	fprintf(stderr, "%s: can't close zip archive `%s'\n", prg, archive);
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
 	return 1;
     }
 
diff --git a/regress/set_compression.c b/regress/set_compression.c
new file mode 100644
index 0000000..e72d73d
--- /dev/null
+++ b/regress/set_compression.c
@@ -0,0 +1,89 @@
+/*
+  set_compression.c -- set compression method for file in archive
+  Copyright (C) 2012 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zipint.h"
+
+const char *prg;
+
+int
+main(int argc, char *argv[])
+{
+    const char *archive, *name;
+    int method;
+    struct zip *za;
+    char buf[100];
+    int err;
+    int i;
+    int idx;
+
+    prg = argv[0];
+
+    if (argc != 4) {
+	fprintf(stderr, "usage: %s archive file method\n", prg);
+	return 1;
+    }
+
+    archive = argv[1];
+    name = argv[2];
+    method = atoi(argv[3]);
+    
+    if ((za=zip_open(archive, 0, &err)) == NULL) {
+	zip_error_to_str(buf, sizeof(buf), err, errno);
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
+		archive, buf);
+	return 1;
+    }
+    if ((idx=zip_name_locate(za, name, 0)) < 0) {
+	printf("%s: unexpected error while looking for `%s': %s\n",
+	       prg, name, zip_strerror(za));
+	return 1;
+    }
+    if (zip_set_file_compression(za, idx, method, /* XXX: add flags * when supported */ 0) < 0) {
+	fprintf(stderr, "zip_set_file_compression with method `%d' on file %d failed: %s\n",
+		method, idx, zip_strerror(za));
+	return 1;
+    }
+    if (zip_close(za) == -1) {
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, archive, zip_strerror(za));
+	return 1;
+    }
+
+    return 0;
+}
diff --git a/regress/set_compression_deflate_to_deflate.test b/regress/set_compression_deflate_to_deflate.test
new file mode 100644
index 0000000..bbcb873
--- /dev/null
+++ b/regress/set_compression_deflate_to_deflate.test
@@ -0,0 +1,5 @@
+# change method from deflated to deflated (no change)
+program set_compression
+return 0
+args test.zip abac-repeat.txt 8
+file test.zip testdeflated.zip testdeflated.zip
diff --git a/regress/set_compression_deflate_to_store.test b/regress/set_compression_deflate_to_store.test
new file mode 100644
index 0000000..824e672
--- /dev/null
+++ b/regress/set_compression_deflate_to_store.test
@@ -0,0 +1,5 @@
+# change method from deflated to stored
+program set_compression
+return 0
+args test.zip abac-repeat.txt 0
+file test.zip testdeflated.zip teststored.zip
diff --git a/regress/set_compression_store_to_deflate.test b/regress/set_compression_store_to_deflate.test
new file mode 100644
index 0000000..c9476cc
--- /dev/null
+++ b/regress/set_compression_store_to_deflate.test
@@ -0,0 +1,5 @@
+# change method from stored to deflated
+program set_compression
+return 0
+args test.zip abac-repeat.txt 8
+file test.zip teststored.zip testdeflated.zip
diff --git a/regress/set_compression_store_to_store.test b/regress/set_compression_store_to_store.test
new file mode 100644
index 0000000..c5ea2af
--- /dev/null
+++ b/regress/set_compression_store_to_store.test
@@ -0,0 +1,5 @@
+# change method from stored to stored (no change)
+program set_compression
+return 0
+args test.zip abac-repeat.txt 0
+file test.zip teststored.zip teststored.zip
diff --git a/regress/set_compression_unknown.test b/regress/set_compression_unknown.test
new file mode 100644
index 0000000..6fd9976
--- /dev/null
+++ b/regress/set_compression_unknown.test
@@ -0,0 +1,6 @@
+# change method to unknown
+program set_compression
+return 1
+args test.zip abac-repeat.txt -99
+file test.zip teststored.zip teststored.zip
+stderr zip_set_file_compression with method `-99' on file 0 failed: Compression method not supported
diff --git a/regress/stat_index.c b/regress/stat_index.c
new file mode 100644
index 0000000..ad7f2b9
--- /dev/null
+++ b/regress/stat_index.c
@@ -0,0 +1,137 @@
+/*
+  stat_index.c -- stat entry in archive and print details
+  Copyright (C) 2012 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 <errno.h>
+#include <time.h>
+#ifndef HAVE_GETOPT
+#include "getopt.h"
+#endif
+
+#include "zip.h"
+
+const char *prg;
+
+const char *usage = "usage: %s [-grs] file index [index ...]\n";
+
+
+
+int
+main(int argc, char *argv[])
+{
+    const char *fname;
+    char buf[100];
+    struct zip *z;
+    int c, flags, ze;
+    zip_uint64_t count;
+    struct zip_stat sb;
+    int index;
+
+    flags = 0;
+    prg = argv[0];
+
+    while ((c=getopt(argc, argv, "grs")) != -1) {
+	switch (c) {
+	case 'g':
+	    flags = ZIP_FL_NAME_GUESS;
+	    break;
+	case 'r':
+	    flags = ZIP_FL_NAME_RAW;
+	    break;
+	case 's':
+	    flags = ZIP_FL_NAME_STRICT;
+	    break;
+
+	default:
+	    fprintf(stderr, usage, prg);
+	    return 1;
+	}
+    }
+    if (argc < optind+2) {
+	fprintf(stderr, usage, prg);
+	return 1;
+    }
+
+    fname = argv[optind++];
+    errno = 0;
+
+    if ((z=zip_open(fname, flags, &ze)) == NULL) {
+	zip_error_to_str(buf, sizeof(buf), ze, errno);
+	fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg,
+		fname, buf);
+	return 1;
+    }
+
+    while (optind < argc) {
+        index = atoi(argv[optind++]);
+
+	if (zip_stat_index(z, index, flags, &sb) < 0) {
+	    fprintf(stderr, "%s: zip_stat_index failed on `%d' failed: %s\n",
+		    prg, index, zip_strerror(z));
+	    return 1;
+	}
+
+	if (sb.valid & ZIP_STAT_NAME)
+	    printf("name: `%s'\n", sb.name);
+	if (sb.valid & ZIP_STAT_INDEX)
+	    printf("index: `%lld'\n", sb.index);
+	if (sb.valid & ZIP_STAT_SIZE)
+	    printf("size: `%lld'\n", sb.size);
+	if (sb.valid & ZIP_STAT_COMP_SIZE)
+	    printf("compressed size: `%lld'\n", sb.comp_size);
+	if (sb.valid & ZIP_STAT_MTIME) {
+	    char buf[50];
+	    struct tm *tpm;
+	    tpm = gmtime(&sb.mtime);
+	    strftime(buf, sizeof(buf), "%a %b %d %T %Z %Y", tpm);
+	    printf("mtime: `%s'\n", buf);
+	}
+	if (sb.valid & ZIP_STAT_CRC)
+	    printf("crc: `%0x'\n", sb.crc);
+	if (sb.valid & ZIP_STAT_COMP_METHOD)
+	    printf("compression method: `%lld'\n", sb.comp_method);
+	if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
+	    printf("encryption method: `%lld'\n", sb.encryption_method);
+	if (sb.valid & ZIP_STAT_FLAGS)
+	    printf("flags: `%lld'\n", sb.flags);
+	printf("\n");
+    }
+
+    if (zip_close(z) == -1) {
+	fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, fname, zip_strerror(z));
+	return 1;
+    }
+
+    return 0;
+}
diff --git a/regress/stat_index_cp437_guess.test b/regress/stat_index_cp437_guess.test
new file mode 100644
index 0000000..32c2d82
--- /dev/null
+++ b/regress/stat_index_cp437_guess.test
@@ -0,0 +1,149 @@
+# guess CP437 file names and autoconvert them
+program stat_index
+args test-cp437.zip 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+return 0
+file test-cp437.zip test-cp437.zip test-cp437.zip
+stdout name: `☺☻♥♦♣♠•○◘◙♂♀♪♫☼►'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:50 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `◄↕‼¶§▬↨↑↓→←∟↔▲▼ '
+stdout index: `1'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:54 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `!"#$%&'()*+,-./0'
+stdout index: `2'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:58 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `123456789:;<=>?@'
+stdout index: `3'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:04 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `ABCDEFGHIJKLMNOP'
+stdout index: `4'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `QRSTUVWXYZ[\\]^_`'
+stdout index: `5'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:12 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `abcdefghijklmnop'
+stdout index: `6'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:18 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `qrstuvwxyz{|}~~Ç'
+stdout index: `7'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:22 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `üéâäàåçêëèïîìÄÅÉ'
+stdout index: `8'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:26 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `æÆôöòûùÿÖÜ¢£¥₧ƒá'
+stdout index: `9'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:30 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `íóúñѪº¿⌐¬½¼¡«»░'
+stdout index: `10'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:36 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `▒▓│┤╡╢╖╕╣║╗╝╜╛┐└'
+stdout index: `11'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:40 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `┴┬├─┼╞╟╚╔╩╦╠═╬╧╨'
+stdout index: `12'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:44 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α'
+stdout index: `13'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:50 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `ßΓπΣσµτΦΘΩδ∞φε∩≡'
+stdout index: `14'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:54 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `±≥≤⌠⌡÷≈°∙·√ⁿ²■  '
+stdout index: `15'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:53:02 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/stat_index_cp437_raw.test b/regress/stat_index_cp437_raw.test
new file mode 100644
index 0000000..4ac895b
--- /dev/null
+++ b/regress/stat_index_cp437_raw.test
Binary files differ
diff --git a/regress/stat_index_cp437_strict.test b/regress/stat_index_cp437_strict.test
new file mode 100644
index 0000000..4caa47e
--- /dev/null
+++ b/regress/stat_index_cp437_strict.test
@@ -0,0 +1,149 @@
+# strictly follow ZIP spec and expect CP437 file names, and autoconvert them
+program stat_index
+args -s test-cp437.zip 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+return 0
+file test-cp437.zip test-cp437.zip test-cp437.zip
+stdout name: `☺☻♥♦♣♠•○◘◙♂♀♪♫☼►'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:50 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `◄↕‼¶§▬↨↑↓→←∟↔▲▼ '
+stdout index: `1'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:54 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `!"#$%&'()*+,-./0'
+stdout index: `2'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:51:58 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `123456789:;<=>?@'
+stdout index: `3'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:04 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `ABCDEFGHIJKLMNOP'
+stdout index: `4'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `QRSTUVWXYZ[\\]^_`'
+stdout index: `5'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:12 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `abcdefghijklmnop'
+stdout index: `6'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:18 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `qrstuvwxyz{|}~~Ç'
+stdout index: `7'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:22 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `üéâäàåçêëèïîìÄÅÉ'
+stdout index: `8'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:26 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `æÆôöòûùÿÖÜ¢£¥₧ƒá'
+stdout index: `9'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:30 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `íóúñѪº¿⌐¬½¼¡«»░'
+stdout index: `10'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:36 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `▒▓│┤╡╢╖╕╣║╗╝╜╛┐└'
+stdout index: `11'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:40 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `┴┬├─┼╞╟╚╔╩╦╠═╬╧╨'
+stdout index: `12'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:44 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α'
+stdout index: `13'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:50 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `ßΓπΣσµτΦΘΩδ∞φε∩≡'
+stdout index: `14'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:52:54 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
+stdout name: `±≥≤⌠⌡÷≈°∙·√ⁿ²■  '
+stdout index: `15'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 19:53:02 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/stat_index_utf8_guess.test b/regress/stat_index_utf8_guess.test
new file mode 100644
index 0000000..9b63ee7
--- /dev/null
+++ b/regress/stat_index_utf8_guess.test
@@ -0,0 +1,14 @@
+# guess UTF-8 file names
+program stat_index
+args test-utf8.zip 0
+return 0
+file test-utf8.zip test-utf8.zip test-utf8.zip
+stdout name: `ÄÖÜäöüßćçĉéèêëē'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 23:15:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/stat_index_utf8_raw.test b/regress/stat_index_utf8_raw.test
new file mode 100644
index 0000000..a69003a
--- /dev/null
+++ b/regress/stat_index_utf8_raw.test
@@ -0,0 +1,14 @@
+# print UTF-8 file names
+program stat_index
+args -r test-utf8.zip 0
+return 0
+file test-utf8.zip test-utf8.zip test-utf8.zip
+stdout name: `ÄÖÜäöüßćçĉéèêëē'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 23:15:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/stat_index_utf8_strict.test b/regress/stat_index_utf8_strict.test
new file mode 100644
index 0000000..e5a7df4
--- /dev/null
+++ b/regress/stat_index_utf8_strict.test
@@ -0,0 +1,15 @@
+# follow strict rules and convert UTF-8 as if it was CP437, but not
+# if the files are marked as having UTF-8 names
+program stat_index
+args -s test-utf8.zip 0
+return 0
+file test-utf8.zip test-utf8.zip test-utf8.zip
+stdout name: `ÄÖÜäöüßćçĉéèêëē'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 23:15:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/stat_index_utf8_unmarked_strict.test b/regress/stat_index_utf8_unmarked_strict.test
new file mode 100644
index 0000000..264a47d
--- /dev/null
+++ b/regress/stat_index_utf8_unmarked_strict.test
@@ -0,0 +1,15 @@
+# follow strict rules and convert UTF-8 as if it was CP437,
+# if not marked otherwise (in this case: not marked)
+program stat_index
+args -s test-utf8-unmarked.zip 0
+return 0
+file test-utf8-unmarked.zip test-utf8-unmarked.zip test-utf8-unmarked.zip
+stdout name: `ÄÖÜäöüßćçĉéèêëē'
+stdout index: `0'
+stdout size: `0'
+stdout compressed size: `0'
+stdout mtime: `Fri Feb 17 23:15:08 CET 2012'
+stdout crc: `0'
+stdout compression method: `0'
+stdout encryption method: `0'
+stdout 
diff --git a/regress/test-cp437-fc.zip b/regress/test-cp437-fc.zip
new file mode 100644
index 0000000..0c4f04d
--- /dev/null
+++ b/regress/test-cp437-fc.zip
Binary files differ
diff --git a/regress/test-cp437.zip b/regress/test-cp437.zip
new file mode 100644
index 0000000..066531e
--- /dev/null
+++ b/regress/test-cp437.zip
Binary files differ
diff --git a/regress/test-utf8-unmarked.zip b/regress/test-utf8-unmarked.zip
new file mode 100644
index 0000000..1bcb703
--- /dev/null
+++ b/regress/test-utf8-unmarked.zip
Binary files differ
diff --git a/regress/test-utf8.zip b/regress/test-utf8.zip
new file mode 100644
index 0000000..3045e20
--- /dev/null
+++ b/regress/test-utf8.zip
Binary files differ
diff --git a/regress/test2.zip b/regress/test2.zip
new file mode 100644
index 0000000..ff5e351
--- /dev/null
+++ b/regress/test2.zip
Binary files differ
diff --git a/regress/testcomment13.zip b/regress/testcomment13.zip
new file mode 100644
index 0000000..bd6e1c3
--- /dev/null
+++ b/regress/testcomment13.zip
Binary files differ
diff --git a/regress/testdeflated.zip b/regress/testdeflated.zip
new file mode 100644
index 0000000..c9ee5d2
--- /dev/null
+++ b/regress/testdeflated.zip
Binary files differ
diff --git a/regress/testempty.zip b/regress/testempty.zip
new file mode 100644
index 0000000..15cb0ec
--- /dev/null
+++ b/regress/testempty.zip
Binary files differ
diff --git a/regress/testextrabytes.zip b/regress/testextrabytes.zip
new file mode 100644
index 0000000..f2a3fb2
--- /dev/null
+++ b/regress/testextrabytes.zip
Binary files differ
diff --git a/regress/testfile-UTF8.zip b/regress/testfile-UTF8.zip
new file mode 100644
index 0000000..c09ede6
--- /dev/null
+++ b/regress/testfile-UTF8.zip
Binary files differ
diff --git a/regress/testfile.txt b/regress/testfile.txt
old mode 100644
new mode 100755
diff --git a/regress/testfile.zip b/regress/testfile.zip
index b46d298..b87dc48 100644
--- a/regress/testfile.zip
+++ b/regress/testfile.zip
Binary files differ
diff --git a/regress/teststored.zip b/regress/teststored.zip
index 04bf517..91cb1e6 100644
--- a/regress/teststored.zip
+++ b/regress/teststored.zip
Binary files differ
diff --git a/regress/torrent-already.test b/regress/torrent-already.test
index 8bd15b3..4369e71 100644
--- a/regress/torrent-already.test
+++ b/regress/torrent-already.test
@@ -1,4 +1,4 @@
-# add directories to zip
+# try converting archive to torrentzip that's already in that format
 program ../src/ziptorrent
 return 0
 args -v test.zip
diff --git a/regress/torrent-new.test b/regress/torrent-new.test
index 0224208..8bac8da 100644
--- a/regress/torrent-new.test
+++ b/regress/torrent-new.test
@@ -1,4 +1,4 @@
-# add directories to zip
+# convert archive to torrentzip format
 program ../src/ziptorrent
 return 0
 args -v test.zip
diff --git a/regress/tryopen.c b/regress/tryopen.c
index fcc280f..cab1460 100644
--- a/regress/tryopen.c
+++ b/regress/tryopen.c
@@ -44,7 +44,7 @@
 
 const char *prg;
 
-const char *usage = "usage: %s [-cen] file\n";
+const char *usage = "usage: %s [-cent] file\n";
 
 
 
@@ -53,12 +53,13 @@
 {
     const char *fname;
     struct zip *z;
-    int c, count, flags, ze;
+    int c, flags, ze;
+    zip_uint64_t count;
 
     flags = 0;
     prg = argv[0];
 
-    while ((c=getopt(argc, argv, "cen")) != -1) {
+    while ((c=getopt(argc, argv, "cent")) != -1) {
 	switch (c) {
 	case 'c':
 	    flags |= ZIP_CHECKCONS;
@@ -69,6 +70,9 @@
 	case 'n':
 	    flags |= ZIP_CREATE;
 	    break;
+	case 't':
+	    flags |= ZIP_TRUNCATE;
+	    break;
 
 	default:
 	    fprintf(stderr, usage, prg);
@@ -84,13 +88,15 @@
     errno = 0;
 
     if ((z=zip_open(fname, flags, &ze)) != NULL) {
-	count = zip_get_num_files(z);
-	printf("opening `%s' succeeded, %d entries\n", fname, count);
+	count = zip_get_num_entries(z, 0);
+	printf("opening `%s' succeeded, %lld entries\n", fname, count);
 	zip_close(z);
 	return 0;
     }
 
-    printf("opening `%s' returned error %d/%d\n",
-	   fname, ze, errno);
+    printf("opening `%s' returned error %d", fname, ze);
+    if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
+	printf("/%d", errno);
+    printf("\n");
     return 1;
 }
diff --git a/regress/zip64.zip b/regress/zip64.zip
new file mode 100644
index 0000000..c1ba76b
--- /dev/null
+++ b/regress/zip64.zip
Binary files differ
diff --git a/regress/ziptest.c b/regress/ziptest.c
deleted file mode 100644
index 7d37be5..0000000
--- a/regress/ziptest.c
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "zip.h"
-#include "error.h"
-
-
-int
-main(int argc, char *argv[])
-{
-#if 0
-    int i;
-#endif
-    struct zip *za, *destza;
-#if 0
-#define BUFSIZE 65536
-    struct zip_file *zf1, *zf2;
-    char buf1[BUFSIZE], buf2[BUFSIZE];
-#endif
-    
-#if 0
-    if (argc != 2) {
-	fprintf(stderr, "%s: call with one option: the zip-file to destroy"
-		"^H^H^H^H^H^H^Htest\n", argv[0]);
-	return 1;
-    }
-#endif
-    if (argc != 3) {
-	fprintf(stderr, "%s: call with two options: src dest\n", argv[0]);
-	return 1;
-    }
-
-    if ((za=zip_open(argv[1], ZIP_CHECKCONS))==NULL) {
-	fprintf(stderr, "%s: %s: can't open file: %s\n", argv[0], argv[1],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-
-    if ((destza=zip_open(argv[2], ZIP_CREATE))==NULL) {
-	fprintf(stderr, "%s: %s: can't open file: %s\n", argv[0], argv[2],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-
-#if 0
-    for (i=0; i<za->nentry; i++) {
-	printf("%8d %s\n", za->entry[i].uncomp_size, za->entry[i].fn);
-	zip_add_zip(destza, za->entry[i].fn, za, i, 0, 0);
-    }
-#endif
-
-    if (zip_add_zip(destza, NULL, NULL, za, 0, 0, 0) == -1)
-	fprintf(stderr, "%s: %s: can't add file to zip '%s': %s\n", argv[0],
-		za->entry[0].fn, argv[1], zip_err_str[zip_err]);
-
-#if 0
-    zf1= zf_open_index(za, 1);
-    if (!zf1) {
-	fprintf(stderr, "boese, boese\n");
-	exit(100);
-    }
-    
-    i = zf_read(zf1, buf1, 100);
-    if (i < 0)
-	fprintf(stderr, "read error: %s\n", zip_err_str[zf1->flags]);
-    else {
-	buf1[i] = 0;
-	printf("read %d bytes: '%s'\n", i, buf1);
-    }
-    zf2 = zf_open_index(za, 1);
-    i = zf_read(zf2, buf2, 200);
-    if (i < 0)
-	fprintf(stderr, "read error: %s\n", zip_err_str[zf2->flags]);
-    else {
-	buf2[i] = 0;
-	printf("read %d bytes: '%s'\n", i, buf2);
-    }
-    i = zf_read(zf1, buf1, 100);
-    if (i < 0)
-	fprintf(stderr, "read error: %s\n", zip_err_str[zf1->flags]);
-    else {
-	buf1[i] = 0;
-	printf("read %d bytes: '%s'\n", i, buf1);
-    }
-    zf_close(zf1);
-    zf_close(zf2);
-#endif
-    
-    if (zip_close(destza)!=0) {
-	fprintf(stderr, "%s: %s: can't close file: %s\n", argv[0], argv[2],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-
-    if (zip_close(za)!=0) {
-	fprintf(stderr, "%s: %s: can't close file: %s\n", argv[0], argv[1],
-		zip_err_str[zip_err]);
-	return 1;
-    }
-    
-    return 0;
-}
diff --git a/src/Makefile.am b/src/Makefile.am
index 7fa4b8e..dc13bbb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,10 +1,10 @@
 bin_PROGRAMS=zipcmp zipmerge ziptorrent
 
-zipcmp_CPPFLAGS=-I${top_srcdir}/lib
+zipcmp_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 zipcmp_LDADD=${top_builddir}/lib/libzip.la
-zipmerge_CPPFLAGS=-I${top_srcdir}/lib
+zipmerge_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 zipmerge_LDADD=${top_builddir}/lib/libzip.la
-ziptorrent_CPPFLAGS=-I${top_srcdir}/lib
+ziptorrent_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 ziptorrent_LDADD=${top_builddir}/lib/libzip.la
 
 EXTRA_DIST=	CMakeLists.txt getopt.c getopt.h
diff --git a/src/zipcmp.c b/src/zipcmp.c
index 75a3e4e..6e1d5d2 100644
--- a/src/zipcmp.c
+++ b/src/zipcmp.c
@@ -1,6 +1,6 @@
 /*
   zipcmp.c -- compare zip files
-  Copyright (C) 2003-2010 Dieter Baron and Thomas Klausner
+  Copyright (C) 2003-2012 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>
@@ -49,6 +49,7 @@
 #endif
 
 #include "zip.h"
+#include "zipint.h"
 
 struct entry {
     char *name;
@@ -78,7 +79,7 @@
 Report bugs to <libzip@nih.at>.\n";
 
 char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\
-Copyright (C) 2010 Dieter Baron and Thomas Klausner\n\
+Copyright (C) 2012 Dieter Baron and Thomas Klausner\n\
 " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n";
 
 #define OPTIONS "hViqtv"
@@ -171,23 +172,27 @@
 
 	n[i] = zip_get_num_files(za);
 
-	if ((e[i]=malloc(sizeof(*e[i]) * n[i])) == NULL) {
-	    fprintf(stderr, "%s: malloc failure\n", prg);
-	    exit(1);
-	}
+	if (n[i] == 0)
+	    e[i] = NULL;
+        else {
+	    if ((e[i]=malloc(sizeof(*e[i]) * n[i])) == NULL) {
+	        fprintf(stderr, "%s: malloc failure\n", prg);
+	        exit(1);
+	    }
 
-	for (j=0; j<n[i]; j++) {
-	    zip_stat_index(za, j, 0, &st);
-	    e[i][j].name = strdup(st.name);
-	    e[i][j].size = st.size;
-	    e[i][j].crc = st.crc;
-	    if (test_files)
-		test_file(za, j, st.size, st.crc);
-	}
+	    for (j=0; j<n[i]; j++) {
+	        zip_stat_index(za, j, 0, &st);
+	        e[i][j].name = strdup(st.name);
+	        e[i][j].size = st.size;
+	        e[i][j].crc = st.crc;
+	        if (test_files)
+		    test_file(za, j, st.size, st.crc);
+	    }
+	    qsort(e[i], n[i], sizeof(e[i][0]), entry_cmp);
+        }
 
 	zip_close(za);
 
-	qsort(e[i], n[i], sizeof(e[i][0]), entry_cmp);
     }
 
     switch (compare_list(zn, verbose,