API cleanup, be less strict with file name arguments.
diff --git a/NEWS b/NEWS
index 6519c3f..ea0ce92 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@
 
 * Added Zip64 support (large file support)
 * Added UTF-8 support for file names, file comments, and archive comments
+* Changed API for name and comment related functions for UTF-8 support
 * Added zip_discard()
 * Added ZIP_TRUNCATE for zip_open()
 * Added zip_set_file_compression()
@@ -16,7 +17,7 @@
 
 0.10 [2010/03/18]
 
-* Added zip_get_num_files(), deprecated zip_get_num_entries().
+* Added zip_get_num_entries(), deprecated zip_get_num_files().
 * Better windows support.
 * Support for traditional PKWARE encryption added.
 * Fix opening archives with more than 65535 entries.
diff --git a/TODO b/TODO
index 75b4e65..ef82ba5 100644
--- a/TODO
+++ b/TODO
@@ -9,14 +9,6 @@
 
 API Issues
 ==========
-! character encoding in file names and comments (allow non-UTF8)
-  Replacement functions with flags:
-  * zip_archive_set_comment
-  * zip_file_add
-  * zip_file_rename
-  * zip_file_set_comment
-! use this case to go over all function names and make them consistent
-  (e.g., zip_*_file_extra_* -> zip_file_*)
 ! clean up first version of extra field support
 * compression/crypt implementations: how to set error code on failure
 * compression/crypt error messages a la ZIP_ER_ZLIB (no detailed info passing)
@@ -25,14 +17,16 @@
 
 Features
 ========
-! read InfoZIP extra fields for UTF-8 file name/file comment
 ! Implement missing extra field functions
 ! Document extra field functions
 ! Document API changes
   . _set_name allows NULL (document)
   . old extra fields API removed
   . change in return value of get_comment: NULL if error, else pointer to empty array and len=0
-  . add ZIP_DISABLE_DEPRECATED and rename deprecated functions so they are only available when it's not set
+  . document ZIP_DISABLE_DEPRECATED (libzip man page)
+  . renames of zip_add, zip_rename, zip_replace, zip_add_dir, zip_{set,get}_file_comment
+  . NULL is now allowed for file names (zip_add, zip_add_dir, zip_rename)
+! add flag for zip_file_add that overwrites any existing entry with same name
 * do not compress if storing is smaller
 
 * I/O methods
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index b8ad48f..2ea8f73 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -58,6 +58,7 @@
   zip_add_entry.c
   zip_close.c
   zip_delete.c
+  zip_dir_add.c
   zip_dirent.c
   zip_discard.c
   zip_entry.c
@@ -72,9 +73,14 @@
   zip_extra_field_api.c
   zip_fclose.c
   zip_fdopen.c
+  zip_file_add.c
   zip_file_error_clear.c
   zip_file_error_get.c
+  zip_file_get_comment.c
   zip_file_get_offset.c
+  zip_file_rename.c
+  zip_file_replace.c
+  zip_file_set_comment.c
   zip_file_strerror.c
   zip_filerange_crc.c
   zip_fopen.c
diff --git a/lib/Makefile.am b/lib/Makefile.am
index de5c718..921a328 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -15,6 +15,7 @@
 	zip_add_entry.c \
 	zip_close.c \
 	zip_delete.c \
+	zip_dir_add.c \
 	zip_dirent.c \
 	zip_discard.c \
 	zip_entry.c \
@@ -29,9 +30,14 @@
 	zip_extra_field_api.c \
 	zip_fclose.c \
 	zip_fdopen.c \
+	zip_file_add.c \
 	zip_file_error_clear.c \
 	zip_file_error_get.c \
+	zip_file_get_comment.c \
 	zip_file_get_offset.c \
+	zip_file_rename.c \
+	zip_file_replace.c \
+	zip_file_set_comment.c \
 	zip_file_strerror.c \
 	zip_filerange_crc.c \
 	zip_fopen.c \
diff --git a/lib/zip.h b/lib/zip.h
index 4f00f68..c04c9ed 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -72,12 +72,14 @@
 #define ZIP_FL_UNCHANGED	8 /* use original data, ignoring changes */
 #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 */
+#define ZIP_FL_ENC_GUESS        0 /* guess string encoding (is default) */
+#define ZIP_FL_ENC_RAW         64 /* get unmodified string */
+#define ZIP_FL_ENC_STRICT     128 /* follow specification strictly */
 #define ZIP_FL_LOCAL	      256 /* in local header */
 #define ZIP_FL_CENTRAL	      512 /* in central directory */
 /*                           1024    reserved for internal use */
+#define ZIP_FL_ENC_UTF_8     2048 /* string is UTF-8 encoded */
+#define ZIP_FL_ENC_CP437     4096 /* string is CP437 encoded */
 
 /* archive global flags flags */
 
@@ -222,13 +224,22 @@
 
 
 
-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 *);
+#ifndef ZIP_DISABLE_DEPRECATED
+ZIP_EXTERN zip_int64_t zip_add(struct zip *, const char *, struct zip_source *); /* use zip_file_add */
+ZIP_EXTERN zip_int64_t zip_add_dir(struct zip *, const char *); /* use zip_dir_add */
+ZIP_EXTERN const char *zip_get_file_comment(struct zip *, zip_uint64_t, int *, int); /* use zip_file_get_comment */
+ZIP_EXTERN int zip_rename(struct zip *, zip_uint64_t, const char *); /* use zip_file_rename */
+ZIP_EXTERN int zip_replace(struct zip *, zip_uint64_t, struct zip_source *); /* use zip_file_replace */
+ZIP_EXTERN int zip_set_file_comment(struct zip *, zip_uint64_t, const char *, int); /* use zip_file_set_comment */
+#endif
+
+ZIP_EXTERN zip_int64_t zip_file_add(struct zip *, const char *, struct zip_source *, zip_flags_t);
+ZIP_EXTERN zip_int64_t zip_dir_add(struct zip *, const char *, zip_flags_t);
 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 int zip_delete_file_extra_field(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t);
-ZIP_EXTERN int zip_delete_file_extra_field_by_id(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t, zip_uint16_t);
+ZIP_EXTERN int zip_file_extra_field_delete(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_extra_field_delete_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN void zip_error_clear(struct zip *);
 ZIP_EXTERN void zip_error_get(struct zip *, int *, int *);
 ZIP_EXTERN int zip_error_get_sys_type(int);
@@ -239,51 +250,38 @@
 ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *);
 ZIP_EXTERN const char *zip_file_strerror(struct zip_file *);
 ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int);
-ZIP_EXTERN struct zip_file *zip_fopen_encrypted(struct zip *, const char *,
-						int, const char *);
+ZIP_EXTERN struct zip_file *zip_fopen_encrypted(struct zip *, const char *, int, const char *);
 ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, zip_uint64_t, int);
-ZIP_EXTERN struct zip_file *zip_fopen_index_encrypted(struct zip *,
-						      zip_uint64_t, int,
-						      const char *);
+ZIP_EXTERN struct zip_file *zip_fopen_index_encrypted(struct zip *, zip_uint64_t, int, const char *);
 ZIP_EXTERN zip_int64_t zip_fread(struct zip_file *, void *, zip_uint64_t);
 ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int);
 ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int);
-ZIP_EXTERN const char *zip_get_file_comment(struct zip *, zip_uint64_t,
-					    int *, int);
-ZIP_EXTERN const zip_uint8_t *zip_get_file_extra_field(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t, zip_uint16_t *, zip_uint16_t *);
-ZIP_EXTERN const zip_uint8_t *zip_get_file_extra_field_by_id(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *);
-ZIP_EXTERN zip_int16_t zip_get_file_num_extra_fields(struct zip *, zip_uint64_t, zip_flags_t);
-ZIP_EXTERN zip_int16_t zip_get_file_num_extra_fields_by_id(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t);
+ZIP_EXTERN const char *zip_file_get_comment(struct zip *, zip_uint64_t, zip_uint32_t *, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t *, zip_uint16_t *, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(struct zip *, zip_uint64_t, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN const char *zip_get_name(struct zip *, zip_uint64_t, int);
 ZIP_EXTERN zip_uint64_t zip_get_num_entries(struct zip *, int);
 ZIP_EXTERN int zip_get_num_files(struct zip *);  /* deprecated, use zip_get_num_entries instead */
 ZIP_EXTERN int zip_name_locate(struct zip *, const char *, int);
 ZIP_EXTERN struct zip *zip_open(const char *, int, int *);
-ZIP_EXTERN int zip_rename(struct zip *, zip_uint64_t, const char *);
-ZIP_EXTERN int zip_replace(struct zip *, zip_uint64_t, struct zip_source *);
+ZIP_EXTERN int zip_file_rename(struct zip *, zip_uint64_t, const char *, zip_flags_t);
+ZIP_EXTERN int zip_file_replace(struct zip *, zip_uint64_t, struct zip_source *, zip_flags_t);
 ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int);
 ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int);
 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_field(struct zip *, zip_uint64_t, zip_flags_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t);
-ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *,
-						zip_uint64_t, int);
-ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *,
-					      zip_uint64_t, zip_int64_t);
-ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *,
-					       zip_uint64_t, zip_int64_t);
+ZIP_EXTERN int zip_file_set_comment(struct zip *, zip_uint64_t, const char *, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_set_file_compression(struct zip *, zip_uint64_t, zip_int32_t, zip_uint32_t);
+ZIP_EXTERN int zip_file_extra_field_set(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, zip_uint64_t, int);
+ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, zip_uint64_t, zip_int64_t);
+ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, zip_uint64_t, zip_int64_t);
 ZIP_EXTERN void zip_source_free(struct zip_source *);
-ZIP_EXTERN struct zip_source *zip_source_function(struct zip *,
-						  zip_source_callback, void *);
-ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *,
-					     zip_uint64_t, int,
-					     zip_uint64_t, zip_int64_t);
+ZIP_EXTERN struct zip_source *zip_source_function(struct zip *, zip_source_callback, void *);
+ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *, zip_uint64_t, int, zip_uint64_t, zip_int64_t);
 ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *);
-ZIP_EXTERN int zip_stat_index(struct zip *, zip_uint64_t, int,
-			      struct zip_stat *);
+ZIP_EXTERN int zip_stat_index(struct zip *, zip_uint64_t, int, struct zip_stat *);
 ZIP_EXTERN void zip_stat_init(struct zip_stat *);
 ZIP_EXTERN const char *zip_strerror(struct zip *);
 ZIP_EXTERN int zip_unchange(struct zip *, zip_uint64_t);
diff --git a/lib/zip_add.c b/lib/zip_add.c
index 3c22ddc..b298af1 100644
--- a/lib/zip_add.c
+++ b/lib/zip_add.c
@@ -1,6 +1,6 @@
 /*
   zip_add.c -- add file via callback 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>
@@ -46,10 +46,5 @@
 ZIP_EXTERN zip_int64_t
 zip_add(struct zip *za, const char *name, struct zip_source *source)
 {
-    if (name == NULL || source == NULL) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-	
-    return _zip_replace(za, ZIP_UINT64_MAX, name, source);
+    return zip_file_add(za, name, source, 0);
 }
diff --git a/lib/zip_add_dir.c b/lib/zip_add_dir.c
index 28a8ad1..84834b5 100644
--- a/lib/zip_add_dir.c
+++ b/lib/zip_add_dir.c
@@ -1,6 +1,6 @@
 /*
   zip_add_dir.c -- add directory
-  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,44 +45,5 @@
 ZIP_EXTERN zip_int64_t
 zip_add_dir(struct zip *za, const char *name)
 {
-    int len;
-    zip_int64_t ret;
-    char *s;
-    struct zip_source *source;
-
-    if (ZIP_IS_RDONLY(za)) {
-	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
-	return -1;
-    }
-
-    if (name == NULL) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-
-    s = NULL;
-    len = strlen(name);
-
-    if (name[len-1] != '/') {
-	if ((s=(char *)malloc(len+2)) == NULL) {
-	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
-	    return -1;
-	}
-	strcpy(s, name);
-	s[len] = '/';
-	s[len+1] = '\0';
-    }
-
-    if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) {
-	free(s);
-	return -1;
-    }
-	
-    ret = _zip_replace(za, -1, s ? s : name, source);
-
-    free(s);
-    if (ret < 0)
-	zip_source_free(source);
-
-    return ret;
+    return zip_dir_add(za, name, 0);
 }
diff --git a/lib/zip_close.c b/lib/zip_close.c
index bd0d9b7..1ac9153 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -76,7 +76,6 @@
     struct zip_filelist *filelist;
     int reopen_on_error;
     int new_torrentzip;
-    enum zip_encoding_type com_enc, enc;
     int changed;
 
     reopen_on_error = 0;
@@ -166,15 +165,6 @@
 	if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
 	    _zip_dirent_torrent_normalize(entry->changes);
 
-	/* set general purpose bit flag for file name/comment encoding */
-	enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);
-	com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);
-	if ((enc == ZIP_ENCODING_UTF8_KNOWN  && com_enc == ZIP_ENCODING_ASCII) ||
-	    (enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN ) ||
-	    (enc == ZIP_ENCODING_UTF8_KNOWN  && com_enc == ZIP_ENCODING_UTF8_KNOWN ))
-	    de->bitflags |= ZIP_GPBF_ENCODING_UTF_8;
-	else
-	    de->bitflags &= ~ZIP_GPBF_ENCODING_UTF_8;
 
 	de->offset = ftello(out);
 
diff --git a/lib/zip_dir_add.c b/lib/zip_dir_add.c
new file mode 100644
index 0000000..57389c5
--- /dev/null
+++ b/lib/zip_dir_add.c
@@ -0,0 +1,88 @@
+/*
+  zip_dir_add.c -- add directory
+  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>
+
+  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"
+
+
+
+/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */
+
+ZIP_EXTERN zip_int64_t
+zip_dir_add(struct zip *za, const char *name, zip_flags_t flags)
+{
+    int len;
+    zip_int64_t ret;
+    char *s;
+    struct zip_source *source;
+
+    if (ZIP_IS_RDONLY(za)) {
+	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+	return -1;
+    }
+
+    if (name == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    s = NULL;
+    len = strlen(name);
+
+    if (name[len-1] != '/') {
+	if ((s=(char *)malloc(len+2)) == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+	    return -1;
+	}
+	strcpy(s, name);
+	s[len] = '/';
+	s[len+1] = '\0';
+    }
+
+    if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) {
+	free(s);
+	return -1;
+    }
+	
+    ret = _zip_file_replace(za, -1, s ? s : name, source, flags);
+
+    free(s);
+    if (ret < 0)
+	zip_source_free(source);
+
+    return ret;
+}
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 8b44a78..77cf4a3 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -44,6 +44,8 @@
 
 static time_t _zip_d2u_time(int, int);
 static struct zip_string *_zip_read_string(const unsigned char **, FILE *, int, int, struct zip_error *);
+static struct zip_string *_zip_dirent_process_ef_utf_8(struct zip_dirent *, zip_uint16_t, struct zip_string *);
+static struct zip_extra_field *_zip_ef_utf8(zip_uint16_t, struct zip_string *, struct zip_error *);
 
 
 
@@ -439,6 +441,8 @@
 	}
     }
 
+    zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename);
+    zde->comment = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment);
 
     /* Zip64 */
 
@@ -487,6 +491,38 @@
 
 
 
+static struct zip_string *
+_zip_dirent_process_ef_utf_8(struct zip_dirent *de, zip_uint16_t id, struct zip_string *str)
+{
+    zip_uint16_t ef_len;
+    zip_uint8_t string;
+    zip_uint32_t string_len;
+    zip_uint32_t ef_crc;
+
+    const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL);
+
+    if (ef == NULL || ef_len < 5 || ef[0] != 1)
+	return str;
+
+    ef++;
+    ef_crc = _zip_read4(&ef);
+
+    if (_zip_string_crc32(str) == ef_crc) {
+	struct zip_string *ef_str = _zip_string_new(ef, ef_len-5, ZIP_ENCODING_UTF8_KNOWN, NULL);
+
+	if (ef_str != NULL) {
+	    _zip_string_free(str);
+	    str = ef_str;
+	}
+    }
+    
+    de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, id, ZIP_EXTRA_FIELD_ALL, ZIP_EF_BOTH);
+
+    return str;
+}
+
+
+
 zip_int32_t
 _zip_dirent_size(FILE *f, zip_uint16_t flags, struct zip_error *error)
 {
@@ -583,90 +619,126 @@
 */
 
 int
-_zip_dirent_write(struct zip_dirent *zde, FILE *fp, int flags,
-		  struct zip_error *error)
+_zip_dirent_write(struct zip_dirent *de, FILE *fp, int flags, struct zip_error *error)
 {
     unsigned short dostime, dosdate;
     zip_uint16_t zip64_ef_size;
+    enum zip_encoding_type com_enc, name_enc;
+    struct zip_extra_field *ef;
+    zip_uint8_t ef_zip64[24], *ef_zip64_p;
+    int is_zip64;
 
-    zip64_ef_size = 0;
+    ef = NULL;
+
+    is_zip64 = 0;
 
     fwrite((flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
 
+    name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);
+    com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);
+
+    if ((name_enc == ZIP_ENCODING_UTF8_KNOWN  && com_enc == ZIP_ENCODING_ASCII) ||
+	(name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) ||
+	(name_enc == ZIP_ENCODING_UTF8_KNOWN  && com_enc == ZIP_ENCODING_UTF8_KNOWN))
+	de->bitflags |= ZIP_GPBF_ENCODING_UTF_8;
+    else {
+	de->bitflags &= ~ZIP_GPBF_ENCODING_UTF_8;
+	if (name_enc == ZIP_ENCODING_UTF8_KNOWN) {
+	    ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, error);
+	    if (ef == NULL)
+		return -1;
+	}
+	if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN){
+	    struct zip_extra_field *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, error);
+	    if (ef2 == NULL) {
+		_zip_ef_free(ef);
+		return -1;
+	    }
+	    ef2->next = ef;
+	    ef = ef2;
+	}
+    }
+
+    ef_zip64_p = ef_zip64;
+    if (flags & ZIP_FL_LOCAL) {
+	if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) {
+	    _zip_poke8(de->comp_size, &ef_zip64_p);
+	    _zip_poke8(de->uncomp_size, &ef_zip64_p);
+	}
+    }
+    else {
+	if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) {
+	    if (de->comp_size >= ZIP_UINT32_MAX)
+		_zip_poke8(de->comp_size, &ef_zip64_p);
+	    if (de->uncomp_size >= ZIP_UINT32_MAX)
+		_zip_poke8(de->uncomp_size, &ef_zip64_p);
+	    if (de->offset >= ZIP_UINT32_MAX)
+		_zip_poke8(de->offset, &ef_zip64_p);
+	}
+    }
+
+    if (ef_zip64_p != ef_zip64) {
+	struct zip_extra_field *ef64 = _zip_ef_new(ZIP_EF_ZIP64, ef_zip64_p-ef_zip64, ef_zip64, ZIP_EF_BOTH);
+	ef64->next = ef;
+	ef = ef64;
+	is_zip64 = 1;
+    }
 
     if ((flags & ZIP_FL_LOCAL) == 0)
-	_zip_write2(zde->version_madeby, fp);
-    _zip_write2(zde->version_needed, fp);    /* XXX: at least 4.5 if zip64 */
-    _zip_write2(zde->bitflags, fp);
-    _zip_write2(zde->comp_method, fp);
+	_zip_write2(de->version_madeby, fp);
+    _zip_write2(de->version_needed, fp);    /* XXX: at least 4.5 if zip64 */
+    _zip_write2(de->bitflags, fp);
+    _zip_write2(de->comp_method, fp);
 
-    _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
+    _zip_u2d_time(de->last_mod, &dostime, &dosdate);
     _zip_write2(dostime, fp);
     _zip_write2(dosdate, fp);
-    
-    _zip_write4(zde->crc, fp);
-    if (zde->comp_size < ZIP_UINT32_MAX)
-	_zip_write4(zde->comp_size, fp);
-    else {
-	_zip_write4(ZIP_UINT32_MAX, fp);
-	zip64_ef_size += 8;
-    }
-    if (zde->uncomp_size < ZIP_UINT32_MAX)
-	_zip_write4(zde->uncomp_size, fp);
-    else {
-	_zip_write4(ZIP_UINT32_MAX, fp);
-	zip64_ef_size += 8;
-    }
 
-    if (flags & ZIP_FL_LOCAL) {
-	if (zip64_ef_size > 0 || (flags & ZIP_FL_FORCE_ZIP64))
-	    zip64_ef_size = 16;
-    }
-    else if (zde->offset >= ZIP_UINT32_MAX)
-	zip64_ef_size += 8;
+    _zip_write4(de->crc, fp);
+    if (de->comp_size < ZIP_UINT32_MAX)
+	_zip_write4(de->comp_size, fp);
+    else
+	_zip_write4(ZIP_UINT32_MAX, fp);
+    if (de->uncomp_size < ZIP_UINT32_MAX)
+	_zip_write4(de->uncomp_size, fp);
+    else
+	_zip_write4(ZIP_UINT32_MAX, fp);
 
-    _zip_write2(_zip_string_length(zde->filename), fp);
-    _zip_write2(_zip_ef_size(zde->extra_fields, flags) + (zip64_ef_size ? (zip64_ef_size+4) : 0), fp);
+    _zip_write2(_zip_string_length(de->filename), fp);
+    _zip_write2(_zip_ef_size(de->extra_fields, flags) + _zip_ef_size(ef, ZIP_EF_BOTH), fp);
     
     if ((flags & ZIP_FL_LOCAL) == 0) {
-	_zip_write2(_zip_string_length(zde->comment), fp);
-	_zip_write2(zde->disk_number, fp);
-	_zip_write2(zde->int_attrib, fp);
-	_zip_write4(zde->ext_attrib, fp);
-	if (zde->offset < ZIP_UINT32_MAX)
-	    _zip_write4(zde->offset, fp);
+	_zip_write2(_zip_string_length(de->comment), fp);
+	_zip_write2(de->disk_number, fp);
+	_zip_write2(de->int_attrib, fp);
+	_zip_write4(de->ext_attrib, fp);
+	if (de->offset < ZIP_UINT32_MAX)
+	    _zip_write4(de->offset, fp);
 	else
 	    _zip_write4(ZIP_UINT32_MAX, fp);
     }
 
-    if (zde->filename)
-	_zip_string_write(zde->filename, fp);
+    if (de->filename)
+	_zip_string_write(de->filename, fp);
 
-    if (zde->extra_fields)
-	_zip_ef_write(zde->extra_fields, flags, fp);
-
-    if (zip64_ef_size > 0) {
-	_zip_write2(ZIP_EF_ZIP64, fp);
-	_zip_write2(zip64_ef_size, fp);
-	if ((flags & ZIP_EF_LOCAL) || zde->uncomp_size >= ZIP_UINT32_MAX)
-	    _zip_write8(zde->uncomp_size, fp);
-	if ((flags & ZIP_EF_LOCAL) || zde->comp_size >= ZIP_UINT32_MAX)
-	    _zip_write8(zde->comp_size, fp);
-	if (((flags & ZIP_EF_LOCAL) == 0) && zde->offset >= ZIP_UINT32_MAX)
-	    _zip_write8(zde->offset, fp);
-    }
+    if (ef)
+	_zip_ef_write(ef, ZIP_EF_BOTH, fp);
+    if (de->extra_fields)
+	_zip_ef_write(de->extra_fields, flags, fp);
 
     if ((flags & ZIP_FL_LOCAL) == 0) {
-	if (zde->comment)
-	    _zip_string_write(zde->comment, fp);
+	if (de->comment)
+	    _zip_string_write(de->comment, fp);
     }
 
+    _zip_ef_free(ef);
+
     if (ferror(fp)) {
 	_zip_error_set(error, ZIP_ER_WRITE, errno);
 	return -1;
     }
 
-    return zip64_ef_size > 0;
+    return is_zip64;
 }
 
 
@@ -694,6 +766,34 @@
 
 
 
+static struct zip_extra_field *
+_zip_ef_utf8(zip_uint16_t id, struct zip_string *str, struct zip_error *error)
+{
+    const zip_uint8_t *raw;
+    zip_uint8_t *data, *p;
+    zip_uint32_t len;
+    struct zip_extra_field *ef;
+
+    raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL);
+
+    if ((data=malloc(len+5)) == NULL) {
+	_zip_error_set(error, ZIP_ER_MEMORY, 0);
+	return NULL;
+    }
+
+    p = data;
+    *(p++) = 1;
+    _zip_poke4(_zip_string_crc32(str), &p);
+    memcpy(p, raw, len);
+    p += len;
+
+    ef = _zip_ef_new(id, p-data, data, ZIP_EF_BOTH);
+    free(data);
+    return ef;
+}
+
+
+
 struct zip_dirent *
 _zip_get_dirent(struct zip *za, zip_uint64_t idx, int flags, struct zip_error *error)
 {
@@ -810,7 +910,33 @@
     if ((raw=_zip_read_data(buf, fp, len, nulp, error)) == NULL)
 	return NULL;
 
-    return _zip_string_new(raw, len, error);
+    return _zip_string_new(raw, len, ZIP_FL_ENC_GUESS, error);
+}
+
+
+
+void
+_zip_poke4(zip_uint32_t i, zip_uint8_t **p)
+{
+    *((*p)++) = i&0xff;
+    *((*p)++) = (i>>8)&0xff;
+    *((*p)++) = (i>>16)&0xff;
+    *((*p)++) = (i>>24)&0xff;
+}
+
+
+
+void
+_zip_poke8(zip_uint64_t i, zip_uint8_t **p)
+{
+    *((*p)++) = i&0xff;
+    *((*p)++) = (i>>8)&0xff;
+    *((*p)++) = (i>>16)&0xff;
+    *((*p)++) = (i>>24)&0xff;
+    *((*p)++) = (i>>32)&0xff;
+    *((*p)++) = (i>>40)&0xff;
+    *((*p)++) = (i>>48)&0xff;
+    *((*p)++) = (i>>56)&0xff;
 }
 
 
diff --git a/lib/zip_extra_field_api.c b/lib/zip_extra_field_api.c
index 17bbd60..1c45dd9 100644
--- a/lib/zip_extra_field_api.c
+++ b/lib/zip_extra_field_api.c
@@ -38,7 +38,7 @@
 
 
 ZIP_EXTERN int
-zip_delete_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_idx)
+zip_file_extra_field_delete(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags)
 {
     /* XXX */
     return -1;
@@ -47,7 +47,7 @@
 
 
 ZIP_EXTERN int
-zip_delete_file_extra_field_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx)
+zip_file_extra_field_delete_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags)
 {
     /* XXX */
     return -1;
@@ -56,7 +56,7 @@
 
 
 ZIP_EXTERN const zip_uint8_t *
-zip_get_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp)
+zip_file_extra_field_get(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags)
 {
     static const zip_uint8_t empty[1];
 
@@ -101,7 +101,7 @@
 
 
 ZIP_EXTERN const zip_uint8_t *
-zip_get_file_extra_field_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp)
+zip_file_extra_field_get_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags)
 {
     struct zip_dirent *de;
 
@@ -121,7 +121,7 @@
 
 
 ZIP_EXTERN zip_int16_t
-zip_get_file_num_extra_fields(struct zip *za, zip_uint64_t idx, zip_uint32_t flags)
+zip_file_extra_fields_count(struct zip *za, zip_uint64_t idx, zip_flags_t flags)
 {
     struct zip_dirent *de;
     struct zip_extra_field *ef;
@@ -148,7 +148,7 @@
 
 
 ZIP_EXTERN zip_int16_t
-zip_get_file_num_extra_fields_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id)
+zip_file_extra_fields_count_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags)
 {
     struct zip_dirent *de;
     struct zip_extra_field *ef;
@@ -175,7 +175,7 @@
 
 
 ZIP_EXTERN int
-zip_set_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len)
+zip_file_extra_field_set(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags)
 {
     /* XXX: ZIP_ER_INVAL if ef_id == ZIP_EF_ZIP64 */
     /* XXX: size of ef + new <= ZIP_UINT16_MAX */
diff --git a/lib/zip_file_add.c b/lib/zip_file_add.c
new file mode 100644
index 0000000..995cb91
--- /dev/null
+++ b/lib/zip_file_add.c
@@ -0,0 +1,55 @@
+/*
+  zip_file_add.c -- add file via callback function
+  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>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include "zipint.h"
+
+
+/*
+  NOTE: Return type is signed so we can return -1 on error.
+        The index can not be larger than ZIP_INT64_MAX since the size
+        of the central directory cannot be larger than
+        ZIP_UINT64_MAX, and each entry is larger than 2 bytes.
+*/
+
+ZIP_EXTERN zip_int64_t
+zip_file_add(struct zip *za, const char *name, struct zip_source *source, zip_flags_t flags)
+{
+    if (name == NULL || source == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+	
+    return _zip_file_replace(za, ZIP_UINT64_MAX, name, source, flags);
+}
diff --git a/lib/zip_file_get_comment.c b/lib/zip_file_get_comment.c
new file mode 100644
index 0000000..e71e058
--- /dev/null
+++ b/lib/zip_file_get_comment.c
@@ -0,0 +1,57 @@
+/*
+  zip_file_get_comment.c -- get file comment
+  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>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN const char *
+zip_file_get_comment(struct zip *za, zip_uint64_t idx, zip_uint32_t *lenp, zip_flags_t flags)
+{
+    struct zip_dirent *de;
+    zip_uint32_t len;
+    const zip_uint8_t *str;
+
+    if ((de=_zip_get_dirent(za, idx, flags, NULL)) == NULL)
+	return NULL;
+
+    if ((str=_zip_string_get(de->comment, &len, flags, &za->error)) == NULL)
+	return NULL;
+
+    if (lenp)
+	*lenp = len;
+
+    return (const char *)str;
+}
diff --git a/lib/zip_file_rename.c b/lib/zip_file_rename.c
new file mode 100644
index 0000000..383a52a
--- /dev/null
+++ b/lib/zip_file_rename.c
@@ -0,0 +1,70 @@
+/*
+  zip_file_rename.c -- rename file in zip archive
+  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>
+
+  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 <string.h>
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN int
+zip_file_rename(struct zip *za, zip_uint64_t idx, const char *name, zip_flags_t flags)
+{
+    const char *old_name;
+    int old_is_dir, new_is_dir;
+    
+    if (idx >= za->nentry || (name != NULL && strlen(name) > ZIP_UINT16_MAX)) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    if (ZIP_IS_RDONLY(za)) {
+	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+	return -1;
+    }
+
+    if ((old_name=zip_get_name(za, idx, 0)) == NULL)
+	return -1;
+								    
+    new_is_dir = (name != NULL && name[strlen(name)-1] == '/');
+    old_is_dir = (old_name[strlen(old_name)-1] == '/');
+
+    if (new_is_dir != old_is_dir) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_set_name(za, idx, name, flags);
+}
diff --git a/lib/zip_file_replace.c b/lib/zip_file_replace.c
new file mode 100644
index 0000000..14da8ad
--- /dev/null
+++ b/lib/zip_file_replace.c
@@ -0,0 +1,93 @@
+/*
+  zip_file_replace.c -- replace file via callback function
+  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>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN int
+zip_file_replace(struct zip *za, zip_uint64_t idx, struct zip_source *source, zip_flags_t flags)
+{
+    if (idx >= za->nentry || source == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    if (_zip_file_replace(za, idx, NULL, source, flags) == -1)
+	return -1;
+
+    return 0;
+}
+
+
+
+
+/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */
+
+zip_int64_t
+_zip_file_replace(struct zip *za, zip_uint64_t idx, const char *name, struct zip_source *source, zip_flags_t flags)
+{
+    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) {
+	zip_int64_t i;
+	
+	/* create and use new entry, used by zip_add */
+	if ((i=_zip_add_entry(za)) < 0)
+	    return -1;
+	idx = i;
+    }
+    
+    if (name && _zip_set_name(za, idx, name, flags) != 0) {
+	if (za->nentry != za_nentry_prev) {
+	    _zip_entry_finalize(za->entry+idx);
+	    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);
+
+    za->entry[idx].source = source;
+
+    return idx;
+}
diff --git a/lib/zip_file_set_comment.c b/lib/zip_file_set_comment.c
new file mode 100644
index 0000000..16955ac
--- /dev/null
+++ b/lib/zip_file_set_comment.c
@@ -0,0 +1,102 @@
+/*
+  zip_file_set_comment.c -- set comment for file in archive
+  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>
+
+  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"
+
+
+
+ZIP_EXTERN int
+zip_file_set_comment(struct zip *za, zip_uint64_t idx,
+		     const char *comment, zip_uint16_t len, zip_flags_t flags)
+{
+    struct zip_entry *e;
+    struct zip_string *cstr;
+    struct zip_dirent *de;
+    int changed;
+
+    if ((de=_zip_get_dirent(za, idx, 0, NULL)) == NULL)
+	return -1;
+
+    if (ZIP_IS_RDONLY(za)) {
+	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+	return -1;
+    }
+
+    if (len > 0 && comment == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    if (len > 0) {
+	if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, flags, &za->error)) == NULL)
+	    return -1;
+	if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED)
+	    cstr->encoding = ZIP_ENCODING_UTF8_KNOWN;
+    }
+    else
+	cstr = NULL;
+
+    e = za->entry+idx;
+
+    if (e->changes) {
+	_zip_string_free(e->changes->comment);
+	e->changes->comment = NULL;
+	e->changes->changed &= ~ZIP_DIRENT_COMMENT;
+    }
+
+    if (e->orig && e->orig->comment)
+	changed = !_zip_string_equal(e->orig->comment, cstr);
+    else
+	changed = (cstr != NULL);
+	
+    if (changed) {
+	if (e->changes == NULL)
+	    e->changes = _zip_dirent_clone(e->orig);
+	e->changes->comment = cstr;
+	e->changes->changed |= ZIP_DIRENT_COMMENT;
+    }
+    else {
+	_zip_string_free(cstr);
+	if (e->changes && e->changes->changed == 0) {
+	    _zip_dirent_free(e->changes);
+	    e->changes = NULL;
+	}
+    }
+
+    return 0;
+}
diff --git a/lib/zip_get_file_comment.c b/lib/zip_get_file_comment.c
index a7a586a..8fb8460 100644
--- a/lib/zip_get_file_comment.c
+++ b/lib/zip_get_file_comment.c
@@ -40,18 +40,13 @@
 ZIP_EXTERN const char *
 zip_get_file_comment(struct zip *za, zip_uint64_t idx, int *lenp, int flags)
 {
-    struct zip_dirent *de;
     zip_uint32_t len;
-    const zip_uint8_t *str;
+    const char *s;
 
-    if ((de=_zip_get_dirent(za, idx, flags, NULL)) == NULL)
-	return NULL;
+    if ((s=zip_file_get_comment(za, idx, &len, flags)) != NULL) {
+	if (lenp)
+	    *lenp = len;
+    }
 
-    if ((str=_zip_string_get(de->comment, &len, flags, &za->error)) == NULL)
-	return NULL;
-
-    if (lenp)
-	*lenp = len;
-
-    return (const char *)str;
+    return s;
 }
diff --git a/lib/zip_open.c b/lib/zip_open.c
index c2ab512..c000381 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -228,7 +228,7 @@
     }
 
     if (comment_len) {
-	if ((cd->comment=_zip_string_new(eocd+EOCDLEN, comment_len, error)) == NULL) {
+	if ((cd->comment=_zip_string_new(eocd+EOCDLEN, comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
 	    _zip_cdir_free(cd);
 	    return NULL;
 	}
diff --git a/lib/zip_rename.c b/lib/zip_rename.c
index ea2e676..41f63b9 100644
--- a/lib/zip_rename.c
+++ b/lib/zip_rename.c
@@ -1,6 +1,6 @@
 /*
   zip_rename.c -- rename file in zip archive
-  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>
@@ -42,29 +42,5 @@
 ZIP_EXTERN int
 zip_rename(struct zip *za, zip_uint64_t idx, const char *name)
 {
-    const char *old_name;
-    int old_is_dir, new_is_dir;
-    
-    if (idx >= za->nentry || name == NULL || strlen(name) > ZIP_UINT16_MAX) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-
-    if (ZIP_IS_RDONLY(za)) {
-	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
-	return -1;
-    }
-
-    if ((old_name=zip_get_name(za, idx, 0)) == NULL)
-	return -1;
-								    
-    new_is_dir = (name[strlen(name)-1] == '/');
-    old_is_dir = (old_name[strlen(old_name)-1] == '/');
-
-    if (new_is_dir != old_is_dir) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-
-    return _zip_set_name(za, idx, name);
+    return zip_file_rename(za, idx, name, 0);
 }
diff --git a/lib/zip_replace.c b/lib/zip_replace.c
index 0d39306..d74952b 100644
--- a/lib/zip_replace.c
+++ b/lib/zip_replace.c
@@ -1,6 +1,6 @@
 /*
   zip_replace.c -- replace file via callback function
-  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>
@@ -40,55 +40,5 @@
 ZIP_EXTERN int
 zip_replace(struct zip *za, zip_uint64_t idx, struct zip_source *source)
 {
-    if (idx >= za->nentry || source == NULL) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-
-    if (_zip_replace(za, idx, NULL, source) == -1)
-	return -1;
-
-    return 0;
-}
-
-
-
-
-/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */
-
-zip_int64_t
-_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) {
-	zip_int64_t i;
-	
-	/* create and use new entry, used by zip_add */
-	if ((i=_zip_add_entry(za)) < 0)
-	    return -1;
-	idx = i;
-    }
-    
-    if (name && _zip_set_name(za, idx, name) != 0) {
-	if (za->nentry != za_nentry_prev) {
-	    _zip_entry_finalize(za->entry+idx);
-	    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);
-
-    za->entry[idx].source = source;
-
-    return idx;
+    return zip_file_replace(za, idx, source, 0);
 }
diff --git a/lib/zip_set_archive_comment.c b/lib/zip_set_archive_comment.c
index f71bea7..bf72983 100644
--- a/lib/zip_set_archive_comment.c
+++ b/lib/zip_set_archive_comment.c
@@ -56,7 +56,7 @@
     }
 
     if (len > 0) {
-	if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, &za->error)) == NULL)
+	if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, ZIP_FL_ENC_GUESS, &za->error)) == NULL)
 	    return -1;
 
 	if (_zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_CP437) {
diff --git a/lib/zip_set_file_comment.c b/lib/zip_set_file_comment.c
index 0621ad2..654c64f 100644
--- a/lib/zip_set_file_comment.c
+++ b/lib/zip_set_file_comment.c
@@ -41,77 +41,7 @@
 
 
 ZIP_EXTERN int
-zip_set_file_comment(struct zip *za, zip_uint64_t idx,
-		     const char *comment, int len)
+zip_set_file_comment(struct zip *za, zip_uint64_t idx, const char *comment, int len)
 {
-    struct zip_entry *e;
-    struct zip_string *cstr;
-    struct zip_dirent *de;
-    enum zip_encoding_type com_enc, name_enc;
-    int changed;
-
-    if ((de=_zip_get_dirent(za, idx, 0, NULL)) == NULL)
-	return -1;
-
-    if (ZIP_IS_RDONLY(za)) {
-	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
-	return -1;
-    }
-
-    if (len < 0 || len > MAXCOMLEN
-	|| (len > 0 && comment == NULL)) {
-	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	return -1;
-    }
-
-    if (len > 0) {
-	if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, &za->error)) == NULL)
-	    return -1;
-
-	if ((com_enc=_zip_guess_encoding(cstr, ZIP_ENCODING_UTF8_KNOWN)) == ZIP_ENCODING_ERROR) {
-	    _zip_string_free(cstr);
-	    _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	    return -1;
-	}
-    }
-    else {
-	cstr = NULL;
-	com_enc = ZIP_ENCODING_ASCII;
-    }
-
-    name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);
-
-    if (name_enc == ZIP_ENCODING_CP437 && com_enc == ZIP_ENCODING_UTF8_KNOWN) {
-	_zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0);
-	return -1;
-    }
-
-    e = za->entry+idx;
-
-    if (e->changes) {
-	_zip_string_free(e->changes->comment);
-	e->changes->comment = NULL;
-	e->changes->changed &= ~ZIP_DIRENT_COMMENT;
-    }
-
-    if (e->orig && e->orig->comment)
-	changed = !_zip_string_equal(e->orig->comment, cstr);
-    else
-	changed = (cstr != NULL);
-	
-    if (changed) {
-	if (e->changes == NULL)
-	    e->changes = _zip_dirent_clone(e->orig);
-	e->changes->comment = cstr;
-	e->changes->changed |= ZIP_DIRENT_COMMENT;
-    }
-    else {
-	_zip_string_free(cstr);
-	if (e->changes && e->changes->changed == 0) {
-	    _zip_dirent_free(e->changes);
-	    e->changes = NULL;
-	}
-    }
-
-    return 0;
+    return zip_file_set_comment(za, idx, comment, len, 0);
 }
diff --git a/lib/zip_set_name.c b/lib/zip_set_name.c
index 70a01d9..8acbec8 100644
--- a/lib/zip_set_name.c
+++ b/lib/zip_set_name.c
@@ -41,12 +41,10 @@
 
 
 int
-_zip_set_name(struct zip *za, zip_uint64_t idx, const char *name)
+_zip_set_name(struct zip *za, zip_uint64_t idx, const char *name, zip_flags_t flags)
 {
     struct zip_entry *e;
     struct zip_string *str;
-    struct zip_dirent *de;
-    enum zip_encoding_type com_enc, name_enc;
     int changed;
     int i;
 
@@ -61,20 +59,15 @@
     }
 
     if (name && strlen(name) > 0) {
-	if ((str=_zip_string_new((const zip_uint8_t *)name, strlen(name), &za->error)) == NULL)
+	if ((str=_zip_string_new((const zip_uint8_t *)name, strlen(name), flags, &za->error)) == NULL)
 	    return -1;
-
-	if ((name_enc=_zip_guess_encoding(str, ZIP_ENCODING_UTF8_KNOWN)) == ZIP_ENCODING_ERROR) {
-	    _zip_string_free(str);
-	    _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
-	    return -1;
-	}
+	if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED)
+	    str->encoding = ZIP_ENCODING_UTF8_KNOWN;
     }
-    else {
+    else
 	str = NULL;
-	name_enc = ZIP_ENCODING_ASCII;
-    }
 
+    /* XXX: encoding flags needed for CP437? */
     if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) {
 	_zip_string_free(str);
 	_zip_error_set(&za->error, ZIP_ER_EXISTS, 0);
@@ -87,20 +80,6 @@
 	return 0;
     }
 
-    de = _zip_get_dirent(za, idx, 0, NULL);
-
-    if (de)
-	com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);
-    else
-	com_enc = ZIP_ENCODING_ASCII;
-
-    if (com_enc == ZIP_ENCODING_CP437 && name_enc == ZIP_ENCODING_UTF8_KNOWN) {
-	_zip_string_free(str);
-	_zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0);
-	return -1;
-    }
-
-
     e = za->entry+idx;
 
     if (e->changes) {
diff --git a/lib/zip_string.c b/lib/zip_string.c
index b837ea8..d49e521 100644
--- a/lib/zip_string.c
+++ b/lib/zip_string.c
@@ -40,6 +40,21 @@
 
 
 
+zip_uint32_t
+_zip_string_crc32(const struct zip_string *s)
+{
+    zip_uint32_t crc;
+    
+    crc = crc32(0L, Z_NULL, 0);
+
+    if (s != NULL)    
+	crc = crc32(crc, s->raw, s->length);
+
+    return crc;
+}
+
+
+
 int
 _zip_string_equal(const struct zip_string *a, const struct zip_string *b)
 {
@@ -70,7 +85,7 @@
 
 
 const zip_uint8_t *
-_zip_string_get(struct zip_string *string, zip_uint32_t *lenp, int flags, struct zip_error *error)
+_zip_string_get(struct zip_string *string, zip_uint32_t *lenp, zip_flags_t flags, struct zip_error *error)
 {
     static const zip_uint8_t empty[1] = "";
 
@@ -80,12 +95,12 @@
 	return empty;
     }
 
-    if ((flags & ZIP_FL_NAME_RAW) == 0) {
+    if ((flags & ZIP_FL_ENC_RAW) == 0) {
 	/* start guessing */
 	if (string->encoding == ZIP_ENCODING_UNKNOWN)
 	    _zip_guess_encoding(string, ZIP_ENCODING_UNKNOWN);
 
-	if (((flags & ZIP_FL_NAME_STRICT)
+	if (((flags & ZIP_FL_ENC_STRICT)
 	     && string->encoding != ZIP_ENCODING_ASCII && string->encoding != ZIP_ENCODING_UTF8_KNOWN)
 	    || (string->encoding == ZIP_ENCODING_CP437)) {
 	    if (string->converted == NULL) {
@@ -118,13 +133,29 @@
 
 
 struct zip_string *
-_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, struct zip_error *error)
+_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, struct zip_error *error)
 {
     struct zip_string *s;
+    enum zip_encoding_type expected_encoding;
     
     if (length == 0)
 	return NULL;
 
+    switch (flags & ZIP_FL_ENCODING_ALL) {
+    case ZIP_FL_ENC_GUESS:
+	expected_encoding = ZIP_ENCODING_UNKNOWN;
+	break;
+    case ZIP_FL_ENC_UTF_8:
+	expected_encoding = ZIP_ENCODING_UTF8_KNOWN;
+	break;
+    case ZIP_FL_ENC_CP437:
+	expected_encoding = ZIP_ENCODING_CP437;
+	break;
+    default:
+	_zip_error_set(error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+	
     if ((s=malloc(sizeof(*s))) == NULL) {
 	_zip_error_set(error, ZIP_ER_MEMORY, 0);
 	return NULL;
@@ -142,6 +173,14 @@
     s->converted = NULL;
     s->converted_length = 0;
 
+    if (expected_encoding != ZIP_ENCODING_UNKNOWN) {
+	if (_zip_guess_encoding(s, expected_encoding) == ZIP_ENCODING_ERROR) {
+	    _zip_string_free(s);
+	    _zip_error_set(error, ZIP_ER_INVAL, 0);
+	    return NULL;
+	}
+    }
+    
     return s;
 }
 
diff --git a/lib/zipint.h b/lib/zipint.h
index b9f26a7..44c5baf 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -42,6 +42,8 @@
 #include <io.h>
 #endif
 
+#define ZIP_DISABLE_DEPRECATED
+
 #include "zip.h"
 #include "config.h"
 
@@ -116,7 +118,9 @@
 #define CDBUFSIZE       (MAXCOMLEN+EOCDLEN+EOCD64LOCLEN)
 #define BUFSIZE		8192
 
-#define ZIP_EF_ZIP64	0x0001
+#define ZIP_EF_UTF_8_COMMENT	0x6375
+#define ZIP_EF_UTF_8_NAME	0x7075
+#define ZIP_EF_ZIP64		0x0001
 
 
 
@@ -199,6 +203,8 @@
 
 #define ZIP_FL_FORCE_ZIP64	1024  /* force zip64 extra field (_zip_dirent_write) */
 
+#define ZIP_FL_ENCODING_ALL	(ZIP_FL_ENC_GUESS|ZIP_FL_ENC_CP437|ZIP_FL_ENC_UTF_8)
+
 
 /* encoding type */
 enum zip_encoding_type {
@@ -331,7 +337,7 @@
 struct zip_string {
     zip_uint8_t *raw;			/* raw string */
     zip_uint16_t length;		/* length of raw string */
-    unsigned short encoding; 		/* autorecognized encoding */
+    enum zip_encoding_type encoding; 	/* autorecognized encoding */
     zip_uint8_t *converted;     	/* autoconverted string */
     zip_uint32_t converted_length;	/* length of converted */
 };
@@ -428,9 +434,10 @@
 
 int _zip_string_equal(const struct zip_string *, const struct zip_string *);
 void _zip_string_free(struct zip_string *);
-const zip_uint8_t *_zip_string_get(struct zip_string *, zip_uint32_t *, int, struct zip_error *);
+zip_uint32_t _zip_string_crc32(const struct zip_string *);
+const zip_uint8_t *_zip_string_get(struct zip_string *, zip_uint32_t *, zip_flags_t, struct zip_error *);
 zip_uint16_t _zip_string_length(const struct zip_string *);
-struct zip_string *_zip_string_new(const zip_uint8_t *, zip_uint16_t, struct zip_error *);
+struct zip_string *_zip_string_new(const zip_uint8_t *, zip_uint16_t, zip_flags_t, struct zip_error *);
 void _zip_string_write(const struct zip_string *, FILE *);
 
 int _zip_changed(struct zip *, int *);
@@ -443,13 +450,14 @@
 zip_uint32_t _zip_read4(const unsigned char **);
 zip_uint64_t _zip_read8(const unsigned char **);
 zip_uint8_t *_zip_read_data(const unsigned char **, FILE *, int, int, struct zip_error *);
-zip_int64_t _zip_replace(struct zip *, zip_uint64_t, const char *,
-			 struct zip_source *);
-int _zip_set_name(struct zip *, zip_uint64_t, const char *);
+zip_int64_t _zip_file_replace(struct zip *, zip_uint64_t, const char *, struct zip_source *, zip_flags_t);
+int _zip_set_name(struct zip *, zip_uint64_t, const char *, zip_flags_t);
 void _zip_u2d_time(time_t, zip_uint16_t *, zip_uint16_t *);
 int _zip_unchange(struct zip *, zip_uint64_t, int);
 void _zip_unchange_data(struct zip_entry *);
 
+void _zip_poke4(zip_uint32_t, zip_uint8_t **);
+void _zip_poke8(zip_uint64_t, zip_uint8_t **);
 void _zip_write2(zip_uint16_t, FILE *);
 void _zip_write4(zip_uint32_t, FILE *);
 void _zip_write8(zip_uint64_t, FILE *);
diff --git a/regress/Makefile.am b/regress/Makefile.am
index 457b6e3..4391354 100644
--- a/regress/Makefile.am
+++ b/regress/Makefile.am
@@ -31,7 +31,9 @@
 	test.zip \
 	test2.zip \
 	test-cp437.zip \
+	test-cp437-comment-utf-8.zip \
 	test-cp437-fc.zip \
+	test-cp437-fc-utf-8-filename.zip \
 	test-utf8.zip \
 	test-utf8-unmarked.zip \
 	testbuffer.zip \
@@ -46,6 +48,7 @@
 	testextrabytes.zip \
 	testfile.txt \
 	testfile.zip \
+	testfile-cp437.zip \
 	testfile-UTF8.zip \
 	testnottorrent.zip \
 	teststdin.zip \
diff --git a/regress/file_comment_encmismatch.test b/regress/file_comment_encmismatch.test
index 8685cdb..8d6dc98 100644
--- a/regress/file_comment_encmismatch.test
+++ b/regress/file_comment_encmismatch.test
@@ -1,6 +1,5 @@
-# set file comment to UTF-8 for CP437 encoded filename (fails)
+# set file comment to UTF-8 for CP437 encoded filename (adds InfoZIP extra field)
 program modify
-return 1
-args testfile   set_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
+return 0
+args testfile.zip   set_file_comment 0 ÄÖÜßäöü
+file testfile.zip test-cp437.zip test-cp437-comment-utf-8.zip
diff --git a/regress/rename_cp437.test b/regress/rename_cp437.test
index 6865b7e..5445608 100644
--- a/regress/rename_cp437.test
+++ b/regress/rename_cp437.test
@@ -1,6 +1,5 @@
 # rename file to CP437 name in zip archive (fails)
 program modify
-return 1
+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
+file testfile.zip testfile.zip testfile-cp437.zip
diff --git a/regress/rename_utf8_encmismatch.test b/regress/rename_utf8_encmismatch.test
index 60c44f4..12cc537 100644
--- a/regress/rename_utf8_encmismatch.test
+++ b/regress/rename_utf8_encmismatch.test
@@ -1,6 +1,5 @@
-# rename file to UTF-8 name in zip archive with CP437 comment (fails)
+# rename file to UTF-8 name in zip archive with CP437 comment (sets InfoZIP UTF-8 Name Extension)
 program modify
-return 1
+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
+file testfile test-cp437-fc.zip test-cp437-fc-utf-8-filename.zip
diff --git a/regress/stat_index.c b/regress/stat_index.c
index 4f323c1..14c8116 100644
--- a/regress/stat_index.c
+++ b/regress/stat_index.c
@@ -66,13 +66,13 @@
     while ((c=getopt(argc, argv, "grs")) != -1) {
 	switch (c) {
 	case 'g':
-	    flags = ZIP_FL_NAME_GUESS;
+	    flags = ZIP_FL_ENC_GUESS;
 	    break;
 	case 'r':
-	    flags = ZIP_FL_NAME_RAW;
+	    flags = ZIP_FL_ENC_RAW;
 	    break;
 	case 's':
-	    flags = ZIP_FL_NAME_STRICT;
+	    flags = ZIP_FL_ENC_STRICT;
 	    break;
 
 	default:
diff --git a/regress/test-cp437-comment-utf-8.zip b/regress/test-cp437-comment-utf-8.zip
new file mode 100644
index 0000000..04fbaac
--- /dev/null
+++ b/regress/test-cp437-comment-utf-8.zip
Binary files differ
diff --git a/regress/test-cp437-fc-utf-8-filename.zip b/regress/test-cp437-fc-utf-8-filename.zip
new file mode 100644
index 0000000..7aeb809
--- /dev/null
+++ b/regress/test-cp437-fc-utf-8-filename.zip
Binary files differ
diff --git a/regress/testfile-cp437.zip b/regress/testfile-cp437.zip
new file mode 100644
index 0000000..169a903
--- /dev/null
+++ b/regress/testfile-cp437.zip
Binary files differ
diff --git a/src/zipcmp.c b/src/zipcmp.c
index 18eabd5..30f44d7 100644
--- a/src/zipcmp.c
+++ b/src/zipcmp.c
@@ -343,8 +343,8 @@
     int i;
     zip_uint16_t len;
 
-    n_local = zip_get_file_num_extra_fields(za, idx, ZIP_FL_LOCAL);
-    n_central = zip_get_file_num_extra_fields(za, idx, ZIP_FL_CENTRAL);
+    n_local = zip_file_extra_fields_count(za, idx, ZIP_FL_LOCAL);
+    n_central = zip_file_extra_fields_count(za, idx, ZIP_FL_CENTRAL);
     e->n_extra_fields = n_local + n_central;
     
     if ((e->extra_fields=malloc(sizeof(e->extra_fields[0])*e->n_extra_fields)) == NULL)
@@ -352,13 +352,13 @@
 
     for (i=0; i<n_local; i++) {
 	e->extra_fields[i].name = e->name;
-	if ((e->extra_fields[i].data=zip_get_file_extra_field(za, idx, ZIP_FL_LOCAL, i, &e->extra_fields[i].id, &e->extra_fields[i].size)) == NULL)
+	if ((e->extra_fields[i].data=zip_file_extra_field_get(za, idx, i, &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_LOCAL)) == NULL)
 	    return -1;
 	e->extra_fields[i].flags = ZIP_FL_LOCAL;
     }
     for (; i<e->n_extra_fields; i++) {
 	e->extra_fields[i].name = e->name;
-	if ((e->extra_fields[i].data=zip_get_file_extra_field(za, idx, ZIP_FL_CENTRAL, i-n_local, &e->extra_fields[i].id, &e->extra_fields[i].size)) == NULL)
+	if ((e->extra_fields[i].data=zip_file_extra_field_get(za, idx, i-n_local, &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_CENTRAL)) == NULL)
 	    return -1;
 	e->extra_fields[i].flags = ZIP_FL_CENTRAL;
     }