Merge no-meta branch

--HG--
branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 53612c8..f7441a9 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,28 +12,27 @@
 	zip_add_zip.c \
 	zip_close.c \
 	zip_delete.c \
+	zip_dirent.c \
 	zip_err_str.c \
 	zip_error.c \
 	zip_error_str.c \
 	zip_error_strerror.c \
+	zip_error_sys_type.c \
 	zip_fclose.c \
 	zip_file_get_error.c \
+	zip_file_get_offset.c \
 	zip_file_strerror.c \
 	zip_fopen.c \
 	zip_fopen_index.c \
 	zip_fread.c \
 	zip_free.c \
 	zip_free_entry.c \
-	zip_free_meta.c \
 	zip_get_error.c \
-	zip_get_meta.c \
 	zip_get_num_files.c \
 	zip_get_name.c \
-	zip_merge_meta.c \
 	zip_name_locate.c \
 	zip_new.c \
 	zip_new_entry.c \
-	zip_new_meta.c \
 	zip_open.c \
 	zip_rename.c \
 	zip_replace.c \
diff --git a/lib/zip.h b/lib/zip.h
index 6853136..d97f489 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -2,7 +2,7 @@
 #define _HAD_ZIP_H
 
 /*
-  $NiH: zip.h,v 1.34 2003/10/05 16:05:22 dillo Exp $
+  $NiH: zip.h,v 1.35.4.6 2004/04/14 09:21:33 dillo Exp $
 
   zip.h -- exported declarations.
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -43,21 +43,25 @@
 #include <zlib.h>
 #include <time.h>
 
-enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED,
-		 ZIP_ST_ADDED, ZIP_ST_RENAMED };
-enum zip_cmd { ZIP_CMD_INIT, ZIP_CMD_READ, ZIP_CMD_META, ZIP_CMD_CLOSE };
-
 /* flags for zip_open */
+
 #define ZIP_CREATE           1
 #define ZIP_EXCL             2
 #define ZIP_CHECKCONS        4
 
-/* flags for zip_name_locate */
-#define ZIP_NAME_NOCASE		1
-#define ZIP_NAME_NODIR		2
 
-int zip_err; /* global variable for errors returned by the low-level
-		library */
+/* flags for zip_name_locate, zip_fopen, zip_stat, ... */
+
+#define ZIP_FL_NOCASE		1 /* ignore case on name lookup */
+#define ZIP_FL_NODIR		2 /* ignore directory component */
+#define ZIP_FL_COMPRESSED	4 /* read compressed data (XXX: rename) */
+#define ZIP_FL_UNCHANGED	8 /* use original data, ignoring changes */
+
+/* flags for zip_add and zip_replace */
+
+#define ZIP_CH_ISCOMP	1	/* data returned by ch_func is compressed */
+
+/* libzip error codes */
 
 #define ZERR_OK               0  /* N No error */
 #define ZERR_MULTIDISK        1  /* N Multi-disk zip archives not supported */
@@ -82,33 +86,47 @@
 #define ZERR_INTERNAL        20  /* N Internal error */
 #define ZERR_INCONS	     21  /* N Zip archive inconsistent */
 
+
+/* type of system error value */
+
 #define ZIP_ET_NONE	      0  /* sys_err unused */
 #define ZIP_ET_SYS	      1  /* sys_err is errno */
 #define ZIP_ET_ZIP	      2  /* sys_err is zlib error code */
 
-/* zip file */
+/* compression methods */
 
-typedef int (*zip_read_func)(void *state, void *data,
-			     int len, enum zip_cmd cmd);
+#define ZIP_CM_DEFAULT	      -1  /* better of deflate or store */
+#define ZIP_CM_STORE	       0  /* stored (uncompressed) */
+#define ZIP_CM_SHRINK	       1  /* shrunk */
+#define ZIP_CM_REDUCE_1	       2  /* reduced with factor 1 */
+#define ZIP_CM_REDUCE_2	       3  /* reduced with factor 2 */
+#define ZIP_CM_REDUCE_3	       4  /* reduced with factor 3 */
+#define ZIP_CM_REDUCE_4	       5  /* reduced with factor 4 */
+#define ZIP_CM_IMPLODE	       6  /* imploded */
+#define ZIP_CM_DEFLATE	       8  /* deflated */
+#define ZIP_CM_DEFLATE64       9  /* deflate64 */
+#define ZIP_CM_PKWARE_IMPLODE 10  /* PKWARE imploding */
 
-struct zip_meta {
-    unsigned short version_made, version_need, bitflags, comp_method,
-	disknrstart, int_attr;
-    time_t last_mod;
-    unsigned int crc, comp_size, uncomp_size, ext_attr, local_offset;
-    unsigned short ef_len, lef_len, fc_len;
-    unsigned char *ef, *lef, *fc;
+
+
+enum zip_cmd {
+    ZIP_CMD_INIT,	/* prepare for reading */
+    ZIP_CMD_READ, 	/* read data */
+    ZIP_CMD_CLOSE,	/* close and cleanup */
+    ZIP_CMD_STAT	/* for compressed data */
 };
 
+typedef ssize_t (*zip_read_func)(void *state, void *data,
+				 size_t len, enum zip_cmd cmd);
+
 struct zip_stat {
     const char *name;			/* name of the file */
     int index;				/* index within archive */
     unsigned int crc;			/* crc of file data */
-    unsigned int size;			/* size of file (uncompressed) */
     time_t mtime;			/* modification time */
-    unsigned int comp_size;		/* size of file (compressed) */
+    off_t size;				/* size of file (uncompressed) */
+    off_t comp_size;			/* size of file (compressed) */
     unsigned short comp_method;		/* compression method used */
-    /* unsigned short bitflags; */
 };
 
 struct zip;
@@ -116,47 +134,35 @@
 
 
 
-int zip_add(struct zip *, const char *, struct zip_meta *,
-	    zip_read_func, void *, int);
-int zip_add_data(struct zip *, const char *, struct zip_meta *,
-		 const char *, int, int);
-int zip_add_file(struct zip *, const char *, struct zip_meta *,
-		 const char *, int, int);
-int zip_add_filep(struct zip *, const char *, struct zip_meta *,
-		 FILE *, int, int);
-int zip_add_zip(struct zip *, const char *, struct zip_meta *,
-		struct zip *, int, int, int);
+int zip_add(struct zip *, const char *, zip_read_func, void *, int);
+int zip_add_data(struct zip *, const char *, const void *, off_t, int);
+int zip_add_file(struct zip *, const char *, const char *, off_t, off_t);
+int zip_add_filep(struct zip *, const char *, FILE *, off_t, off_t);
+int zip_add_zip(struct zip *, const char *, struct zip *, int, int,
+		off_t, off_t);
 int zip_close(struct zip *);
 int zip_delete(struct zip *, int);
-int zip_error_str(char *, int, int, int);
+int zip_error_str(char *, size_t, int, int);
 int zip_error_sys_type(int);
 int zip_fclose(struct zip_file *);
 void zip_file_get_error(struct zip_file *, int *, int *);
 const char *zip_file_strerror(struct zip_file *);
 struct zip_file *zip_fopen(struct zip *, const char *, int);
-struct zip_file *zip_fopen_index(struct zip *, int);
-int zip_fread(struct zip_file *, char *, int);
-void zip_free_meta(struct zip_meta *);
+struct zip_file *zip_fopen_index(struct zip *, int, int);
+ssize_t zip_fread(struct zip_file *, void *, size_t);
 void zip_get_error(struct zip *, int *, int *);
-struct zip_meta *zip_get_meta(struct zip *, int);
 const char *zip_get_name(struct zip *, int);
 int zip_get_num_files(struct zip *);
 int zip_name_locate(struct zip *, const char *, int);
-struct zip_meta *zip_new_meta(void);
 struct zip *zip_open(const char *, int, int *);
 int zip_rename(struct zip *, int, const char *);
-int zip_replace(struct zip *, int, const char *, struct zip_meta *,
-		zip_read_func, void *, int);
-int zip_replace_data(struct zip *, int, const char *, struct zip_meta *,
-		     const char *, int, int);
-int zip_replace_file(struct zip *, int, const char *, struct zip_meta *,
-		     const char *, int, int);
-int zip_replace_filep(struct zip *, int, const char *, struct zip_meta *,
-		     FILE *, int, int);
-int zip_replace_zip(struct zip *, int, const char *, struct zip_meta *,
-		    struct zip *, int, int, int);
+int zip_replace(struct zip *, int, zip_read_func, void *, int);
+int zip_replace_data(struct zip *, int, const void *, off_t, int);
+int zip_replace_file(struct zip *, int, const char *, off_t, off_t);
+int zip_replace_filep(struct zip *, int, FILE *, off_t, off_t);
+int zip_replace_zip(struct zip *, int, struct zip *, int, int, off_t, off_t);
 int zip_stat(struct zip *, const char *, int, struct zip_stat *);
-int zip_stat_index(struct zip *, int, struct zip_stat *);
+int zip_stat_index(struct zip *, int, int, struct zip_stat *);
 const char *zip_strerror(struct zip *);
 int zip_unchange(struct zip *, int);
 int zip_unchange_all(struct zip *);
diff --git a/lib/zip_add.c b/lib/zip_add.c
index 8f0c54c..9ebc7b0 100644
--- a/lib/zip_add.c
+++ b/lib/zip_add.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_add.c,v 1.8 2003/10/01 09:50:59 dillo Exp $
+  $NiH: zip_add.c,v 1.9.4.1 2004/03/20 09:54:03 dillo Exp $
 
   zip_add.c -- add file via callback function
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,13 @@
 
 
 int
-zip_add(struct zip *zf, const char *name, struct zip_meta *meta,
-	zip_read_func fn, void *state, int comp)
+zip_add(struct zip *zf, const char *name,
+	zip_read_func fn, void *state, int flags)
 {
-    return zip_replace(zf, -1, name, meta, fn, state, comp);
+    if (name == NULL) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+	
+    return _zip_replace(zf, -1, name, fn, state, flags);
 }
diff --git a/lib/zip_add_data.c b/lib/zip_add_data.c
index 7e53e75..d9fdd2c 100644
--- a/lib/zip_add_data.c
+++ b/lib/zip_add_data.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_add_data.c,v 1.5 2003/10/01 09:50:59 dillo Exp $
+  $NiH: zip_add_data.c,v 1.6.4.1 2004/03/20 09:54:03 dillo Exp $
 
   zip_add_data.c -- add file from buffer
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,13 @@
 
 
 int
-zip_add_data(struct zip *zf, const char *name, struct zip_meta *meta,
-	     const char *data, int len, int freep)
+zip_add_data(struct zip *zf, const char *name,
+	     const void *data, off_t len, int freep)
 {
-    return zip_replace_data(zf, -1, name, meta, data, len, freep);
+    if (name == NULL) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace_data(zf, -1, name, data, len, freep);
 }
diff --git a/lib/zip_add_file.c b/lib/zip_add_file.c
index cf45214..8a845b5 100644
--- a/lib/zip_add_file.c
+++ b/lib/zip_add_file.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_add_file.c,v 1.6 2003/10/01 09:50:59 dillo Exp $
+  $NiH: zip_add_file.c,v 1.7.4.1 2004/03/20 09:54:04 dillo Exp $
 
   zip_add_file.c -- add file from file system
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,13 @@
 
 
 int
-zip_add_file(struct zip *zf, const char *name, struct zip_meta *meta,
-	     const char *fname, int start, int len)
+zip_add_file(struct zip *zf, const char *name,
+	     const char *fname, off_t start, off_t len)
 {
-    return zip_replace_file(zf, -1, name, meta, fname, start, len);
+    if (name == NULL) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace_file(zf, -1, name, fname, start, len);
 }
diff --git a/lib/zip_add_filep.c b/lib/zip_add_filep.c
index d942e16..c4e0acd 100644
--- a/lib/zip_add_filep.c
+++ b/lib/zip_add_filep.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_add_filep.c,v 1.5 2003/10/01 09:51:00 dillo Exp $
+  $NiH: zip_add_filep.c,v 1.6.4.1 2004/03/20 09:54:04 dillo Exp $
 
   zip_add_filep.c -- add file from FILE*
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,13 @@
 
 
 int
-zip_add_filep(struct zip *zf, const char *name, struct zip_meta *meta,
-	      FILE *file, int start, int len)
+zip_add_filep(struct zip *zf, const char *name,
+	      FILE *file, off_t start, off_t len)
 {
-    return zip_replace_filep(zf, -1, name, meta, file, start, len);
+    if (name == NULL) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace_filep(zf, -1, name, file, start, len);
 }
diff --git a/lib/zip_add_zip.c b/lib/zip_add_zip.c
index 260a4d9..44468fa 100644
--- a/lib/zip_add_zip.c
+++ b/lib/zip_add_zip.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_add_zip.c,v 1.6 2003/10/01 09:51:00 dillo Exp $
+  $NiH: zip_add_zip.c,v 1.7.4.2 2004/04/14 09:21:33 dillo Exp $
 
   zip_add_zip.c -- add file from zip file
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,13 @@
 
 
 int
-zip_add_zip(struct zip *zf, const char *name, struct zip_meta *meta,
-	    struct zip *srczf, int srcidx, int start, int len)
+zip_add_zip(struct zip *zf, const char *name,
+	    struct zip *srczf, int srcidx, int flags, off_t start, off_t len)
 {
-    return zip_replace_zip(zf, -1, name, meta, srczf, srcidx, start, len);
+    if (name == NULL) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace_zip(zf, -1, name, srczf, srcidx, flags, start, len);
 }
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 43e7bd5..244aba4 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_close.c,v 1.36 2003/10/06 16:37:40 dillo Exp $
+  $NiH: zip_close.c,v 1.37.4.9 2004/04/13 19:47:58 dillo Exp $
 
   zip_close.c -- close zip archive and update changes
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -46,656 +46,390 @@
 #include "zip.h"
 #include "zipint.h"
 
-static int _zip_entry_copy(struct zip *dest, struct zip *src,
-			  int entry_no, struct zip_meta *meta);
-static int _zip_entry_add(struct zip *dest, struct zip_entry *se);
-static int _zip_writecdir(struct zip *zfp);
-static void _zip_write2(FILE *fp, int i);
-static void _zip_write4(FILE *fp, int i);
-static void _zip_writestr(FILE *fp, char *str, int len);
-static int _zip_writecdentry(FILE *fp, struct zip_entry *zfe, int localp);
-static struct zip_entry *_zip_create_entry(struct zip *dest, 
-			                   struct zip_entry *src_entry,
-			                   char *name, struct zip_meta *meta);
-static void _zip_u2d_time(time_t time, int *ddate, int *dtime);
-static int _zip_fwrite(char *b, int s, int n, FILE *f);
+static int add_data(struct zip *, int, struct zip_dirent *, FILE *);
+static int add_data_comp(zip_read_func, void *, struct zip_dirent *, FILE *,
+			 struct zip_error *);
+static int add_data_uncomp(zip_read_func, void *, struct zip_dirent *, FILE *,
+			   struct zip_error *);
+static int copy_data(FILE *, off_t, FILE *, struct zip_error *);
 
 
 
-/* zip_close:
-   Tries to commit all changes and close the zipfile; if it fails,
-   zip_err (and errno) are set and *zf is unchanged, except for
-   problems in _zip_free. */ 
-
 int
-zip_close(struct zip *zf)
+zip_close(struct zip *za)
 {
-    int i, count, tfd, ret, survivors;
+    int changed, survivors;
+    int i, j, count, tfd, ret, error;
     char *temp;
     FILE *tfp;
-    struct zip *tzf;
     mode_t mask;
+    struct zip_cdir *cd;
+    struct zip_dirent de;
 
-    if (zf->changes == 0) {
-	_zip_free(zf);
-	return 0;
+    changed = survivors = 0;
+    for (i=0; i<za->nentry; i++) {
+	if (za->entry[i].state != ZIP_ST_UNCHANGED)
+	    changed = 1;
+	if (za->entry[i].state != ZIP_ST_DELETED)
+	    survivors++;
     }
 
-    /* look if there really are any changes */
-    count = survivors = 0;
-    for (i=0; i<zf->nentry; i++) {
-	if (zf->entry[i].state != ZIP_ST_UNCHANGED)
-	    count = 1;
-	if (zf->entry[i].state != ZIP_ST_DELETED)
-	    survivors = 1;
-	if (survivors && count)
-	    break;
-    }
-
-    /* no changes, all has been unchanged */
-    if (count == 0) {
-	_zip_free(zf);
+    if (!changed) {
+	_zip_free(za);
 	return 0;
     }
 
     /* don't create zip files with no entries */
     if (survivors == 0) {
 	ret = 0;
-	if (zf->zn)
-	    ret = remove(zf->zn);
-	_zip_free(zf);
-	/* XXX: inconsistent: zf freed, returned -1 */
+	if (za->zn)
+	    ret = remove(za->zn);
+	_zip_free(za);
+	/* XXX: inconsistent: za freed, returned -1 */
 	return ret;
     }	       
 	
-    temp = (char *)malloc(strlen(zf->zn)+8);
-    if (!temp) {
-	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
+    if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL)
+	return -1;
+
+    if ((temp=malloc(strlen(za->zn)+8)) == NULL) {
+	_zip_error_set(&za->error, ZERR_MEMORY, 0);
+	_zip_cdir_free(cd);
 	return -1;
     }
 
-    sprintf(temp, "%s.XXXXXX", zf->zn);
+    sprintf(temp, "%s.XXXXXX", za->zn);
 
-    tfd = mkstemp(temp);
-    if (tfd == -1) {
-	_zip_error_set(&zf->error, ZERR_TMPOPEN, errno);
+    if ((tfd=mkstemp(temp)) == -1) {
+	_zip_error_set(&za->error, ZERR_TMPOPEN, errno);
+	_zip_cdir_free(cd);
 	free(temp);
 	return -1;
     }
     
     if ((tfp=fdopen(tfd, "r+b")) == NULL) {
-	_zip_error_set(&zf->error, ZERR_TMPOPEN, errno);
+	_zip_error_set(&za->error, ZERR_TMPOPEN, errno);
+	_zip_cdir_free(cd);
 	close(tfd);
 	remove(temp);
 	free(temp);
 	return -1;
     }
 
-    if ((tzf=_zip_new(&zf->error.zip_err)) == NULL) {
+    error = 0;
+    for (i=j=0; i<za->nentry; i++) {
+	if (za->entry[i].state == ZIP_ST_DELETED)
+	    continue;
+
+	if (ZIP_ENTRY_DATA_CHANGED(za->entry+i)) {
+	    _zip_dirent_init(&de);
+	    memcpy(cd->entry+j, &de, sizeof(cd->entry[i]));
+	    if (za->entry[i].ch_filename == NULL) {
+		if (za->entry[i].state == ZIP_ST_REPLACED) {
+		    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;
+		}
+		else {
+		    de.filename = strdup("-");
+		    de.filename_len = 1;
+		    cd->entry[j].filename = "-";
+		    cd->entry[j].filename_len = de.filename_len;
+		}
+	    }
+	}
+	else {
+	    if (fseek(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) {
+		_zip_error_set(&za->error, ZERR_SEEK, errno);
+		error = 1;
+		break;
+	    }
+	    if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) {
+		error = 1;
+		break;
+	    }
+	    memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[i]));
+	}
+
+	if (za->entry[i].ch_filename) {
+	    free(de.filename);
+	    de.filename = strdup(za->entry[i].ch_filename);
+	    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].offset = ftell(tfp);
+
+	if (ZIP_ENTRY_DATA_CHANGED(za->entry+i)) {
+	    de.last_mod = za->entry[i].ch_mtime;
+	    if (add_data(za, i, &de, tfp) < 0) {
+		error -1;
+		break;
+	    }
+	    cd->entry[j].comp_method = de.comp_method;
+	    cd->entry[j].comp_size = de.comp_size;
+	    cd->entry[j].uncomp_size = de.uncomp_size;
+	    cd->entry[j].crc = de.crc;
+	}
+	else {
+	    if (_zip_dirent_write(&de, tfp, 1, &za->error) < 0) {
+		error = 1;
+		break;
+	    }
+	    /* we just read the local dirent, file is at correct position */
+	    if (copy_data(za->zp, de.uncomp_size, tfp, &za->error) < 0) {
+		error = 1;
+		break;
+	    }
+	}
+
+	j++;
+
+	_zip_dirent_finalize(&de);
+    }
+
+    if (!error) {
+	if (_zip_cdir_write(cd, tfp, &za->error) < 0)
+	    error = 1;
+    }
+    
+    /* pointers in cd are owned by za */
+    cd->nentry = 0;
+    _zip_cdir_free(cd);
+
+    if (error) {
+	_zip_dirent_finalize(&de);
 	fclose(tfp);
 	remove(temp);
 	free(temp);
 	return -1;
     }
-    tzf->zp = tfp;
-    tzf->zn = temp;
-    tzf->comlen = zf->comlen;
-    if ((tzf->com=(unsigned char *)_zip_memdup(zf->com, zf->comlen)) == NULL) {
-	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
-	_zip_free(tzf);
+
+    if (fclose(tfp) != 0) {
+	/* XXX: handle fclose(tfp) error */
+	remove(temp);
+	free(temp);
 	return -1;
     }
-
-    count = 0;
-    if (zf->entry) {
-	for (i=0; i<zf->nentry; i++) {
-	    switch (zf->entry[i].state) {
-	    case ZIP_ST_UNCHANGED:
-	    case ZIP_ST_RENAMED:
-		if (_zip_local_header_read(zf, i) < 0) {
-		    remove(tzf->zn);
-		    _zip_free(tzf);
-		    return -1;
-		}
-		if (_zip_entry_copy(tzf, zf, i, zf->entry[i].ch_meta)) {
-		    /* zip_err set by _zip_entry_copy */
-		    remove(tzf->zn);
-		    _zip_free(tzf);
-		    return -1;
-		}
-		break;
-	    case ZIP_ST_DELETED:
-		break;
-	    case ZIP_ST_REPLACED:
-	    case ZIP_ST_ADDED:
-		if (_zip_entry_add(tzf, zf->entry+i)) {
-		    /* zip_err set by _zip_entry_add */
-		    remove(tzf->zn);
-		    _zip_free(tzf);
-		    return -1;
-		}
-		break;
-	    default:
-		/* can't happen */
-		break;
-	    }
-	}
-    }
-
-    _zip_writecdir(tzf);
     
-    if (fclose(tzf->zp)==0) {
-	tzf->zp = NULL;
-	if (rename(tzf->zn, zf->zn) != 0) {
-	    _zip_error_set(&zf->error, ZERR_RENAME, errno);
-	    remove(tzf->zn);
-	    _zip_free(tzf);
-	    return -1;
-	}
-	if (zf->zp) {
-	    fclose(zf->zp);
-	    zf->zp = NULL;
-	}
-	mask = umask(0);
-	umask(mask);
-	chmod(zf->zn, 0666&~mask);
+    if (rename(temp, za->zn) != 0) {
+	_zip_error_set(&za->error, ZERR_RENAME, errno);
+	remove(temp);
+	free(temp);
+	return -1;
     }
-    /* XXX: handle fclose(tzf->fn) error */
+    if (za->zp) {
+	fclose(za->zp);
+	za->zp = NULL;
+    }
+    mask = umask(0);
+    umask(mask);
+    chmod(za->zn, 0666&~mask);
 
-    _zip_free(zf);
-    _zip_free(tzf);
-
+    _zip_free(za);
+    
     return 0;
 }
 
 
 
 static int
-_zip_entry_copy(struct zip *dest, struct zip *src, int entry_no,
-		struct zip_meta *meta)
+add_data(struct zip *za, int idx, struct zip_dirent *de, FILE *ft)
 {
-    char buf[BUFSIZE];
-    unsigned int len, remainder;
-    struct zip_entry *ze;
-
-    ze = _zip_create_entry(dest, src->entry+entry_no, NULL, meta);
-    if (!ze)
-	return -1;
-
-    if (_zip_writecdentry(dest->zp, ze, 1) != 0) {
-	_zip_error_set(&src->error, ZERR_WRITE, errno);
-	return -1;
-    }
-
-    if (fseek(src->zp, src->entry[entry_no].meta->local_offset
-	      + LENTRYSIZE + src->entry[entry_no].meta->lef_len
-	      + src->entry[entry_no].file_fnlen, SEEK_SET) != 0) {
-	_zip_error_set(&src->error, ZERR_SEEK, errno);
-	return -1;
-    }
-
+    off_t offstart, offend;
+    zip_read_func rf;
+    void *ud;
     
-    remainder = src->entry[entry_no].meta->comp_size;
-    len = BUFSIZE;
-    while (remainder) {
-	if (len > remainder)
-	    len = remainder;
-	if (fread(buf, 1, len, src->zp)!=len) {
-	    _zip_error_set(&src->error, ZERR_READ, errno);
+    rf = za->entry[idx].ch_func;
+    ud = za->entry[idx].ch_data;
+
+    if (rf(ud, NULL, 0, ZIP_CMD_INIT) < 0) {
+	/* XXX: set error */
+	return -1;
+    }
+
+    offstart = ftell(ft);
+
+    if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
+	return -1;
+
+    if (za->entry[idx].ch_flags & ZIP_CH_ISCOMP) {
+	if (add_data_comp(rf, ud, de, ft, &za->error) < 0)
 	    return -1;
-	}
-	if (fwrite(buf, 1, len, dest->zp)!=len) {
-	    _zip_error_set(&src->error, ZERR_WRITE, errno);
+    }
+    else {
+	if (add_data_uncomp(rf, ud, de, ft, &za->error) < 0)
 	    return -1;
-	}
-	remainder -= len;
     }
 
-    return 0;
-}
-
-
-
-static int
-_zip_entry_add(struct zip *zf, struct zip_entry *se)
-{
-    z_stream zstr;
-    char b1[BUFSIZE], b2[BUFSIZE];
-    int n, size, crc, ret;
-    int flush, end, idx;
-    struct zip_meta *meta;
-
-    if (_zip_create_entry(zf, NULL, se->fn, se->ch_meta) == NULL)
-	return -1;
-    
-    --zf->nentry;
-    idx = zf->nentry;
-
-    zf->entry[idx].meta->local_offset = ftell(zf->zp);
-
-    if (se->ch_func(se->ch_data, NULL, 0, ZIP_CMD_INIT) != 0)
-	return -1;
-
-    if (_zip_writecdentry(zf->zp, zf->entry+idx, 1) != 0) {
-	zip_err = ZERR_WRITE;
+#if 0
+    /* XXX: this is also called in _zip_free */
+    if (rf(ud, NULL, 0, ZIP_CMD_CLOSE) < 0) {
+	/* XXX: set error */
 	return -1;
     }
-
-    if ((meta=zip_new_meta()) < 0)
-	return -1;
-
-    size = 0;
-    
-    if ((se->ch_comp == 0) || (se->ch_meta
-			       && (se->ch_meta->comp_method == 0))) {
-	/* we have to compress */
-	if (se->ch_meta && ((se->ch_meta->comp_method > 0)
-			    && (se->ch_meta->comp_method != 8))) {
-	    /* unknown compression method */
-	    zip_err = ZERR_INVAL;
-	    return -1;
-	}
-	zstr.zalloc = Z_NULL;
-	zstr.zfree = Z_NULL;
-	zstr.opaque = NULL;
-	zstr.avail_in = 0;
-	zstr.avail_out = 0;
-
-	/* -15: undocumented feature of zlib to _not_ write a zlib header */
-	deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 9,
-		     Z_DEFAULT_STRATEGY);
-
-	zstr.next_out = b2;
-	zstr.avail_out = BUFSIZE;
-	zstr.avail_in = 0;
-	flush = 0;
-	crc = crc32(0, NULL, 0);
-
-	end = 0;
-	while (!end) {
-	    if (zstr.avail_in == 0 && !flush) {
-		if ((n=se->ch_func(se->ch_data, b1, BUFSIZE,
-				     ZIP_CMD_READ)) < 0)
-		    return -1;
-		zstr.next_in = b1;
-		zstr.avail_in = n;
-		size += n;
-		crc = crc32(crc, b1, n);
-
-		if (n == 0)
-		    flush = Z_FINISH;
-	    }
-
-	    ret = deflate(&zstr, flush);
-	    if (ret != Z_OK && ret != Z_STREAM_END) {
-		zip_err = ZERR_ZLIB;
-		return -1;
-	    }
-	    
-	    if (zstr.avail_out != BUFSIZE) {
-		if (_zip_fwrite(b2, 1, BUFSIZE-zstr.avail_out, zf->zp) < 0)
-		    return -1;
-		zstr.next_out = b2;
-		zstr.avail_out = BUFSIZE;
-	    }
-
-	    if (ret == Z_STREAM_END) {
-		if (se->ch_func(se->ch_data, meta, 0, ZIP_CMD_META) < 0)
-		    return -1;
-		meta->comp_method = meta->version_need = -1;
-		meta->crc = crc;
-		meta->uncomp_size = size;
-		meta->comp_size = zstr.total_out;
-
-		deflateEnd(&zstr);
-		end = 1;
-	    }
-	}
-
-    }
-    else { /* we get compressed data */
-	while ((n=se->ch_func(se->ch_data, b1, BUFSIZE, ZIP_CMD_READ)) > 0) {
-	    size += n;
-	    if (_zip_fwrite(b1, 1, n, zf->zp) < 0)
-		return -1;
-	}
-	if (n < 0)
-	    return -1;
-	if (se->ch_func(se->ch_data, meta, 0, ZIP_CMD_META) < 0)
-	    return -1;
-	meta->comp_size = size;
-    }
-
-    se->ch_func(se->ch_data, NULL, 0, ZIP_CMD_CLOSE);
-    free(se->ch_data);
-    se->ch_func = NULL;
-    se->ch_data = NULL;
-
-    if (fseek(zf->zp, zf->entry[idx].meta->local_offset, SEEK_SET) < 0) {
-	zip_err = ZERR_SEEK;
-	return -1;
-    }
-
-    meta->local_offset = -1;
-    _zip_merge_meta_fix(zf->entry[idx].meta, meta);
-    if (se->ch_meta) {
-	se->ch_meta->local_offset =  se->ch_meta->comp_method
-	    = se->ch_meta->uncomp_size = se->ch_meta->comp_size
-	    = se->ch_meta->crc = -1;
-	_zip_merge_meta_fix(zf->entry[idx].meta, se->ch_meta);
-    }
-    zip_free_meta(meta);
-
-    if (_zip_writecdentry(zf->zp, zf->entry+idx, 1) != 0) {
-	zip_err = ZERR_WRITE;
-	return -1;
-    }
-
-    if (fseek(zf->zp, 0, SEEK_END) < 0) {
-	zip_err = ZERR_SEEK;
-	return -1;
-    }
-    
-    zf->nentry++;
-    return 0;
-}
-
-
-
-static int
-_zip_fwrite(char *b, int s, int n, FILE *f)
-{
-    int ret, writ;
-
-    writ = 0;
-
-    while (writ<n) {
-	if ((ret=fwrite(b, s, n-writ, f)) < 0) {
-	    zip_err = ZERR_WRITE;
-	    return ret;
-	}
-	writ += ret;
-    }
-
-    return writ;
-}
-
-
-
-static int
-_zip_writecdir(struct zip *zfp)
-{
-    int i;
-    long cd_offset, cd_size;
-
-    cd_offset = ftell(zfp->zp);
-
-    for (i=0; i<zfp->nentry; i++) {
-	if (_zip_writecdentry(zfp->zp, zfp->entry+i, 0) != 0) {
-	    zip_err = ZERR_WRITE;
-	    return -1;
-	}
-    }
-
-    cd_size = ftell(zfp->zp) - cd_offset;
-    
-    clearerr(zfp->zp);
-    fprintf(zfp->zp, EOCD_MAGIC);
-    fprintf(zfp->zp, "%c%c%c%c", 0, 0, 0, 0);
-    _zip_write2(zfp->zp, zfp->nentry);
-    _zip_write2(zfp->zp, zfp->nentry);
-    _zip_write4(zfp->zp, cd_size);
-    _zip_write4(zfp->zp, cd_offset);
-    _zip_write2(zfp->zp, zfp->comlen);
-    _zip_writestr(zfp->zp, zfp->com, zfp->comlen);
-
-    return 0;
-}
-
-
-
-static void
-_zip_write2(FILE *fp, int i)
-{
-    putc(i&0xff, fp);
-    putc((i>>8)&0xff, fp);
-
-    return;
-}
-
-
-
-static void
-_zip_write4(FILE *fp, int i)
-{
-    putc(i&0xff, fp);
-    putc((i>>8)&0xff, fp);
-    putc((i>>16)&0xff, fp);
-    putc((i>>24)&0xff, fp);
-    
-    return;
-}
-
-
-
-static void
-_zip_writestr(FILE *fp, char *str, int len)
-{
-#if WIZ
-    int i;
-    for (i=0; i<len; i++)
-	putc(str[i], fp);
-#else
-    fwrite(str, 1, len, fp);
 #endif
-    
-    return;
-}
 
-
+    offend = ftell(ft);
 
-/* _zip_writecdentry:
-   if localp, writes local header for zfe to zf->zp,
-   else write central directory entry for zfe to zf->zp.
-   if after writing ferror(fp), return -1, else return 0.*/
-   
-static int
-_zip_writecdentry(FILE *fp, struct zip_entry *zfe, int localp)
-{
-    int ltime, ldate;
-
-    fprintf(fp, "%s", localp?LOCAL_MAGIC:CENTRAL_MAGIC);
-    
-    if (!localp)
-	_zip_write2(fp, zfe->meta->version_made);
-    _zip_write2(fp, zfe->meta->version_need);
-    _zip_write2(fp, zfe->meta->bitflags);
-    _zip_write2(fp, zfe->meta->comp_method);
-    _zip_u2d_time(zfe->meta->last_mod, &ldate, &ltime);
-    _zip_write2(fp, ltime);
-    _zip_write2(fp, ldate);
-
-    _zip_write4(fp, zfe->meta->crc);
-    _zip_write4(fp, zfe->meta->comp_size);
-    _zip_write4(fp, zfe->meta->uncomp_size);
-
-    _zip_write2(fp, strlen(zfe->fn));
-    if (localp)
-	_zip_write2(fp, zfe->meta->lef_len);
-    else {
-	_zip_write2(fp, zfe->meta->ef_len);
-	_zip_write2(fp, zfe->meta->fc_len);
-	_zip_write2(fp, zfe->meta->disknrstart);
-	_zip_write2(fp, zfe->meta->int_attr);
-	_zip_write4(fp, zfe->meta->ext_attr);
-	_zip_write4(fp, zfe->meta->local_offset);
+    if (fseek(ft, offstart, SEEK_SET) < 0) {
+	_zip_error_set(&za->error, ZERR_SEEK, errno);
+	return -1;
     }
     
-    _zip_writestr(fp, zfe->fn, strlen(zfe->fn));
-    if (localp) {
-	if (zfe->meta->lef_len)
-	    _zip_writestr(fp, zfe->meta->lef, zfe->meta->lef_len);
-    }
-    else {
-	if (zfe->meta->ef_len)
-	    _zip_writestr(fp, zfe->meta->ef, zfe->meta->ef_len);
-	if (zfe->meta->fc_len)
-	    _zip_writestr(fp, zfe->meta->fc, zfe->meta->fc_len);
-    }
-
-    if (ferror(fp))
+    if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
 	return -1;
     
+    if (fseek(ft, offend, SEEK_SET) < 0) {
+	_zip_error_set(&za->error, ZERR_SEEK, errno);
+	return -1;
+    }
+
     return 0;
 }
 
 
 
-static struct zip_entry *
-_zip_create_entry(struct zip *dest, struct zip_entry *se,
-		  char *name, struct zip_meta *meta)
+static int
+add_data_comp(zip_read_func rf, void *ud, struct zip_dirent *de, FILE *ft,
+	      struct zip_error *error)
 {
-    struct zip_entry *de;
+    char buf[8192];
+    ssize_t n;
+    struct zip_stat st;
 
-    if (!dest)
-	return NULL;
-    
-    if ((de=_zip_new_entry(dest)) == NULL)
-	return NULL;
-
-    if (!se) {
-	/* set default values for central directory entry */
-	de->meta->version_made = 20;
-	de->meta->version_need = 20;
-	/* maximum compression */
-	de->meta->bitflags = 2;
-	/* deflate algorithm */
-	de->meta->comp_method = 8;
-	de->meta->last_mod = time(NULL)+1;
-	de->meta->fc_len = 0;
-	de->meta->ef_len = 0;
-	de->meta->lef_len = 0;
-	de->meta->disknrstart = 0;
-	/* binary data */
-	de->meta->int_attr = 0;
-	/* init CRC-32, compressed and uncompressed size
-	   XXX: will be updated later */
-	de->meta->crc = crc32(0, 0, 0);
-	de->meta->comp_size = 0;
-	de->meta->uncomp_size = 0;
-	de->meta->ext_attr = 0;
-	de->meta->ef = NULL;
-	de->meta->lef = NULL;
-	de->meta->fc = NULL;
-    } else {
-	/* copy values from original zf_entry */
-	de->meta->version_made = se->meta->version_made;
-	de->meta->version_need = se->meta->version_need;
-	de->meta->bitflags = se->meta->bitflags;
-	de->meta->comp_method = se->meta->comp_method;
-	de->meta->last_mod = se->meta->last_mod;
-	de->meta->disknrstart = se->meta->disknrstart;
-	de->meta->int_attr = se->meta->int_attr;
-	de->meta->crc = se->meta->crc;
-	de->meta->comp_size = se->meta->comp_size;
-	de->meta->uncomp_size = se->meta->uncomp_size;
-	de->meta->ext_attr = se->meta->ext_attr;
-	if (se->meta->ef_len != (unsigned short)-1 && se->meta->ef) {
-	    de->meta->ef_len = se->meta->ef_len;
-	    de->meta->ef = (char *)_zip_memdup(se->meta->ef,
-					       se->meta->ef_len);
-	}
-	else {
-	    de->meta->ef_len = 0;
-	    de->meta->ef = NULL;
-	}
-	if (se->meta->lef_len != (unsigned short)-1 && se->meta->lef) {
-	    de->meta->lef_len = se->meta->lef_len;
-	    de->meta->lef = (char *)_zip_memdup(se->meta->lef,
-						se->meta->lef_len);
-	}
-	else {
-	    de->meta->lef_len = 0;
-	    de->meta->lef = NULL;
-	}
-	if (se->meta->fc_len != (unsigned short)-1 && se->meta->fc) {
-	    de->meta->fc_len = se->meta->fc_len;
-	    de->meta->fc = (char *)_zip_memdup(se->meta->fc,
-					       se->meta->fc_len);
-	}
-	else {
-	    de->meta->fc_len = 0;
-	    de->meta->fc = NULL;
-	}
+    if (rf(ud, &st, sizeof(st), ZIP_CMD_STAT) < 0) {
+	/* XXX: set error */
+	return -1;
     }
+
+    de->comp_size = 0;
+    while ((n=rf(ud, buf, sizeof(buf), ZIP_CMD_READ)) > 0) {
+	if (fwrite(buf, 1, n, ft) != n) {
+	    _zip_error_set(error, ZERR_WRITE, errno);
+	    return -1;
+	}
 	
-    de->meta->local_offset = ftell(dest->zp);
-
-    if (name)
-	de->fn = strdup(name);
-    else if (se && se->fn)
-	de->fn = strdup(se->fn);
-    else {
-	de->fn = strdup("-");
+	de->comp_size += n;
     }
+    if (n < 0) {
+	/* XXX: set error */
+	return -1;
+    }	
 
-    if (!de->fn) {
-	dest->nentry--;
-	zip_err = ZERR_MEMORY;
-	return NULL;
-    }
+    de->comp_method = st.comp_method;
+    /* de->last_mod = st.mtime; */
+    de->crc = st.crc;
+    de->uncomp_size = st.size;
 
-    if (_zip_merge_meta(de->meta, meta) < 0) {
-	dest->nentry--;
-	return NULL;
-    }
-
-    return de;
+    return 0;
 }
 
 
 
-static void
-_zip_u2d_time(time_t time, int *ddate, int *dtime)
+static int
+add_data_uncomp(zip_read_func rf, void *ud, struct zip_dirent *de, FILE *ft,
+		struct zip_error *error)
 {
-    struct tm *tm;
+    char b1[8192], b2[8192];
+    int end, flush, ret;
+    ssize_t n;
+    z_stream zstr;
 
-    tm = localtime(&time);
-    *ddate = ((tm->tm_year+1900-1980)<<9)+ ((tm->tm_mon+1)<<5)
-	+ tm->tm_mday;
-    *dtime = ((tm->tm_hour)<<11)+ ((tm->tm_min)<<5)
-	+ ((tm->tm_sec)>>1);
+    /* ZIP_CMD_STAT for mtime? */
 
-    return;
+    de->comp_method = ZIP_CM_DEFLATE;
+    de->comp_size = de->uncomp_size = 0;
+    de->crc = crc32(0, NULL, 0);
+
+    zstr.zalloc = Z_NULL;
+    zstr.zfree = Z_NULL;
+    zstr.opaque = NULL;
+    zstr.avail_in = 0;
+    zstr.avail_out = 0;
+
+    /* -15: undocumented feature of zlib to _not_ write a zlib header */
+    deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 9,
+		 Z_DEFAULT_STRATEGY);
+
+    zstr.next_out = b2;
+    zstr.avail_out = sizeof(b2);
+    zstr.avail_in = 0;
+
+    flush = 0;
+    end = 0;
+    while (!end) {
+	if (zstr.avail_in == 0 && !flush) {
+	    if ((n=rf(ud, b1, sizeof(b1), ZIP_CMD_READ)) < 0) {
+		/* XXX: set error */
+		deflateEnd(&zstr);
+		return -1;
+	    }
+	    if (n > 0) {
+		zstr.avail_in = n;
+		zstr.next_in = b1;
+		de->uncomp_size += n;
+		de->crc = crc32(de->crc, b1, n);
+	    }
+	    else
+		flush = Z_FINISH;
+	}
+
+	ret = deflate(&zstr, flush);
+	if (ret != Z_OK && ret != Z_STREAM_END) {
+	    _zip_error_set(error, ZERR_ZLIB, ret);
+	    return -1;
+	}
+	
+	if (zstr.avail_out != sizeof(b2)) {
+	    n = sizeof(b2) - zstr.avail_out;
+	    
+	    if (fwrite(b2, 1, n, ft) != n) {
+		_zip_error_set(error, ZERR_WRITE, errno);
+		return -1;
+	    }
+	
+	    zstr.next_out = b2;
+	    zstr.avail_out = sizeof(b2);
+	    de->comp_size += n;
+	}
+
+	if (ret == Z_STREAM_END) {
+	    deflateEnd(&zstr);
+	    end = 1;
+	}
+    }
+
+    return 0;
 }
 
 
 
-int
-_zip_local_header_read(struct zip *zf, int idx)
+static int
+copy_data(FILE *fs, off_t len, FILE *ft, struct zip_error *error)
 {
-    struct zip_entry *ze;
-    
-    if (zf->entry[idx].meta->lef_len != 0)
+    char buf[8192];
+    int n, nn;
+
+    if (len == 0)
 	return 0;
 
-    if ((ze=_zip_new_entry(NULL)) == NULL) {
-	zip_err = ZERR_MEMORY;
-	return -1;
+    while (len > 0) {
+	nn = len > sizeof(buf) ? sizeof(buf) : len;
+	if ((n=fread(buf, 1, nn, fs)) < 0) {
+	    _zip_error_set(error, ZERR_READ, errno);
+	    return -1;
+	}
+
+	if (fwrite(buf, 1, n, ft) != n) {
+	    _zip_error_set(error, ZERR_WRITE, errno);
+	    return -1;
+	}
+	
+	len -= n;
     }
 
-    if (fseek(zf->zp, zf->entry[idx].meta->local_offset, SEEK_SET) < 0) {
-	zip_err = ZERR_SEEK;
-	return -1;
-    }
-
-    if (_zip_readcdentry(zf->zp, ze, NULL, 0, 1, 1) < 0)
-	return -1;
-
-    zf->entry[idx].meta->lef_len = ze->meta->lef_len;
-    zf->entry[idx].meta->lef = ze->meta->lef;
-    ze->meta->lef = NULL;
-    _zip_free_entry(ze);
-
     return 0;
 }
diff --git a/lib/zip_delete.c b/lib/zip_delete.c
index c430788..8913ec9 100644
--- a/lib/zip_delete.c
+++ b/lib/zip_delete.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_delete.c,v 1.10 2003/10/03 08:34:11 dillo Exp $
+  $NiH: zip_delete.c,v 1.11.4.1 2004/03/20 09:54:05 dillo Exp $
 
   zip_delete.c -- delete file from zip archive
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -51,7 +51,6 @@
     if (zip_unchange(zf, idx) != 0)
 	return -1;
 
-    zf->changes = 1;
     zf->entry[idx].state = ZIP_ST_DELETED;
 
     return 0;
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
new file mode 100644
index 0000000..6335053
--- /dev/null
+++ b/lib/zip_dirent.c
@@ -0,0 +1,531 @@
+/*
+  $NiH: zip_dirent.c,v 1.1.2.10 2004/04/13 19:47:58 dillo Exp $
+
+  zip_dirent.c -- read directory entry (local or central), clean dirent
+  Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <nih@giga.or.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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "zip.h"
+#include "zipint.h"
+
+static time_t _zip_d2u_time(int, int);
+static char *_zip_readfpstr(FILE *, int, int, struct zip_error *);
+static char *_zip_readstr(unsigned char **, int, int, struct zip_error *);
+static void _zip_u2d_time(time_t, int *, int *);
+static void _zip_write2(unsigned short, FILE *);
+static void _zip_write4(unsigned int, FILE *);
+
+
+
+void
+_zip_cdir_free(struct zip_cdir *cd)
+{
+    int i;
+
+    if (!cd)
+	return;
+
+    for (i=0; i<cd->nentry; i++)
+	_zip_dirent_finalize(cd->entry+i);
+    free(cd->comment);
+    free(cd->entry);
+    free(cd);
+}
+
+
+
+struct zip_cdir *
+_zip_cdir_new(int nentry, struct zip_error *error)
+{
+    struct zip_cdir *cd;
+    
+    if ((cd=malloc(sizeof(*cd))) == NULL) {
+	_zip_error_set(error, ZERR_MEMORY, 0);
+	return NULL;
+    }
+
+    if ((cd->entry=malloc(sizeof(*(cd->entry))*nentry)) == NULL) {
+	_zip_error_set(error, ZERR_MEMORY, 0);
+	free(cd);
+	return NULL;
+    }
+
+    /* entries must be initialized by caller */
+
+    cd->nentry = nentry;
+    cd->size = cd->offset = 0;
+    cd->comment = NULL;
+    cd->comment_len = 0;
+
+    return cd;
+}
+
+
+
+int
+_zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
+{
+    int i;
+
+    cd->offset = ftell(fp);
+
+    for (i=0; i<cd->nentry; i++) {
+	if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0)
+	    return -1;
+    }
+
+    cd->size = ftell(fp) - cd->offset;
+    
+    /* clearerr(fp); */
+    fwrite(EOCD_MAGIC, 1, 4, fp);
+    _zip_write4(0, fp);
+    _zip_write2(cd->nentry, fp);
+    _zip_write2(cd->nentry, fp);
+    _zip_write4(cd->size, fp);
+    _zip_write4(cd->offset, fp);
+    _zip_write2(cd->comment_len, fp);
+    fwrite(cd->comment, 1, cd->comment_len, fp);
+
+    if (ferror(fp)) {
+	_zip_error_set(error, ZERR_WRITE, errno);
+	return -1;
+    }
+
+    return 0;
+}
+
+
+
+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;
+}
+
+
+
+void
+_zip_dirent_init(struct zip_dirent *de)
+{
+    de->version_madeby = 0; /* XXX */
+    de->version_needed = 0; /* XXX */
+    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;
+}
+
+
+
+/* _zip_dirent_read(zde, fp, bufp, left, localp, error):
+   Fills the zip directory entry zde.
+
+   If bufp is non-NULL, data is taken from there and bufp is advanced
+   by the amount of data used; no more than left bytes are used.
+   Otherwise data is read from fp as needed.
+
+   If localp != 0, it reads a local header instead of a central
+   directory entry.
+
+   Returns 0 if successful. On error, error is filled in and -1 is
+   returned.
+*/
+
+int
+_zip_dirent_read(struct zip_dirent *zde, FILE *fp,
+		 unsigned char **bufp, int left, int localp,
+		 struct zip_error *error)
+{
+    unsigned char buf[CDENTRYSIZE];
+    unsigned char *cur;
+    unsigned short dostime, dosdate;
+    int size;
+
+    if (localp)
+	size = LENTRYSIZE;
+    else
+	size = CDENTRYSIZE;
+    
+    if (bufp) {
+	/* use data from buffer */
+	cur = *bufp;
+	if (left < size) {
+	    _zip_error_set(error, ZERR_NOZIP, 0);
+	    return -1;
+	}
+    }
+    else {
+	/* read entry from disk */
+	if ((fread(buf, 1, size, fp)<size)) {
+	    _zip_error_set(error, ZERR_READ, errno);
+	    return -1;
+	}
+	left = size;
+	cur = buf;
+    }
+
+    if (memcmp(cur, (localp ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
+	/* XXX: zip_err = ZERR_NOZIP; */
+	return -1;
+    }
+    cur += 4;
+
+    
+    /* convert buffercontents to zip_dirent */
+    
+    if (!localp)
+	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);
+    
+    /* convert to time_t */
+    dostime = _zip_read2(&cur);
+    dosdate = _zip_read2(&cur);
+    zde->last_mod = _zip_d2u_time(dostime, dosdate);
+    
+    zde->crc = _zip_read4(&cur);
+    zde->comp_size = _zip_read4(&cur);
+    zde->uncomp_size = _zip_read4(&cur);
+    
+    zde->filename_len = _zip_read2(&cur);
+    zde->extrafield_len = _zip_read2(&cur);
+    
+    if (localp) {
+	zde->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->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;
+
+    if (bufp) {
+	if (left < CDENTRYSIZE + (zde->filename_len+zde->extrafield_len
+				  +zde->comment_len)) {
+	    _zip_error_set(error, ZERR_NOZIP, 0);
+	    return -1;
+	}
+
+	if (zde->filename_len) {
+	    zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
+	    if (!zde->filename)
+		    return -1;
+	}
+
+	if (zde->extrafield_len) {
+	    zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
+					   error);
+	    if (!zde->extrafield)
+		return -1;
+	}
+
+	if (zde->comment_len) {
+	    zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
+	    if (!zde->comment)
+		return -1;
+	}
+    }
+    else {
+	if (zde->filename_len) {
+	    zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
+	    if (!zde->filename)
+		    return -1;
+	}
+
+	if (zde->extrafield_len) {
+	    zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
+					     error);
+	    if (!zde->extrafield)
+		return -1;
+	}
+
+	if (zde->comment_len) {
+	    zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
+	    if (!zde->comment)
+		return -1;
+	}
+    }
+
+    if (bufp)
+      *bufp = cur;
+
+    return 0;
+}
+
+
+
+/* _zip_dirent_write(zde, fp, localp, error):
+   Writes zip directory entry zde to file fp.
+
+   If localp != 0, it writes a local header instead of a central
+   directory entry.
+
+   Returns 0 if successful. On error, error is filled in and -1 is
+   returned.
+*/
+
+int
+_zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp,
+		  struct zip_error *error)
+{
+    int dostime, dosdate;
+
+    fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
+
+    if (!localp)
+	_zip_write2(zde->version_madeby, fp);
+    _zip_write2(zde->version_needed, fp);
+    _zip_write2(zde->bitflags, fp);
+    _zip_write2(zde->comp_method, fp);
+
+    _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
+    _zip_write2(dostime, fp);
+    _zip_write2(dosdate, fp);
+    
+    _zip_write4(zde->crc, fp);
+    _zip_write4(zde->comp_size, fp);
+    _zip_write4(zde->uncomp_size, fp);
+    
+    _zip_write2(zde->filename_len, fp);
+    _zip_write2(zde->extrafield_len, fp);
+    
+    if (!localp) {
+	_zip_write2(zde->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 (zde->extrafield_len)
+	fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
+
+    if (!localp) {
+	if (zde->comment_len)
+	    fwrite(zde->comment, 1, zde->comment_len, fp);
+    }
+
+    if (ferror(fp)) {
+	_zip_error_set(error, ZERR_WRITE, errno);
+	return -1;
+    }
+
+    return 0;
+}
+
+
+
+static time_t
+_zip_d2u_time(int dtime, int ddate)
+{
+    struct tm *tm;
+    time_t now;
+
+    now = time(NULL);
+    tm = localtime(&now);
+    
+    tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
+    tm->tm_mon = ((ddate>>5)&15) - 1;
+    tm->tm_mday = ddate&31;
+
+    tm->tm_hour = (dtime>>11)&31;
+    tm->tm_min = (dtime>>5)&63;
+    tm->tm_sec = (dtime<<1)&62;
+
+    return mktime(tm);
+}
+
+
+
+unsigned short
+_zip_read2(unsigned char **a)
+{
+    unsigned short ret;
+
+    ret = (*a)[0]+((*a)[1]<<8);
+    *a += 2;
+
+    return ret;
+}
+
+
+
+unsigned int
+_zip_read4(unsigned char **a)
+{
+    unsigned int ret;
+
+    ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
+    *a += 4;
+
+    return ret;
+}
+
+
+
+static char *
+_zip_readfpstr(FILE *fp, int len, int nulp, struct zip_error *error)
+{
+    char *r, *o;
+
+    r = (char *)malloc(nulp?len+1:len);
+    if (!r) {
+	_zip_error_set(error, ZERR_MEMORY, 0);
+	return NULL;
+    }
+
+    if (fread(r, 1, len, fp)<len) {
+	free(r);
+	_zip_error_set(error, ZERR_READ, errno);
+	return NULL;
+    }
+
+    if (nulp) {
+	/* elephant */
+	/* XXX: what does this do? */
+	r[len] = 0;
+	o = r-1;
+	while (((o=memchr(o+1, 0, r+len-(o+1))) < r+len) && o)
+	       *o = ' ';
+    }
+    
+    return r;
+}
+
+
+
+static char *
+_zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error)
+{
+    char *r, *o;
+
+    r = (char *)malloc(nulp?len+1:len);
+    if (!r) {
+	_zip_error_set(error, ZERR_MEMORY, 0);
+	return NULL;
+    }
+    
+    memcpy(r, *buf, len);
+    *buf += len;
+
+    if (nulp) {
+	/* elephant */
+	/* XXX: what does this do? */
+	r[len] = 0;
+	o = r-1;
+	while (((o=memchr(o+1, 0, r+len-(o+1))) < r+len) && o)
+	       *o = ' ';
+    }
+
+    return r;
+}
+
+
+
+static void
+_zip_write2(unsigned short i, FILE *fp)
+{
+    putc(i&0xff, fp);
+    putc((i>>8)&0xff, fp);
+
+    return;
+}
+
+
+
+static void
+_zip_write4(unsigned int i, FILE *fp)
+{
+    putc(i&0xff, fp);
+    putc((i>>8)&0xff, fp);
+    putc((i>>16)&0xff, fp);
+    putc((i>>24)&0xff, fp);
+    
+    return;
+}
+
+
+
+static void
+_zip_u2d_time(time_t time, int *dtime, int *ddate)
+{
+    struct tm *tm;
+
+    tm = localtime(&time);
+    *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5)
+	+ tm->tm_mday;
+    *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5)
+	+ ((tm->tm_sec)>>1);
+
+    return;
+}
diff --git a/lib/zip_error.c b/lib/zip_error.c
index 3d5c3e1..99a2f77 100644
--- a/lib/zip_error.c
+++ b/lib/zip_error.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_error.c,v 1.2 2003/10/06 02:50:05 dillo Exp $
+  $NiH: zip_error.c,v 1.3.4.1 2004/03/23 16:07:21 dillo Exp $
 
   zip_error.c -- struct zip_error helper functions
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -85,6 +85,8 @@
 void
 _zip_error_set(struct zip_error *err, int ze, int se)
 {
-    err->zip_err = ze;
-    err->sys_err = se;
+    if (err) {
+	err->zip_err = ze;
+	err->sys_err = se;
+    }
 }
diff --git a/lib/zip_error_str.c b/lib/zip_error_str.c
index 548b2c0..dfe4db3 100644
--- a/lib/zip_error_str.c
+++ b/lib/zip_error_str.c
@@ -1,5 +1,5 @@
 /*
-  $NiH$
+  $NiH: zip_error_str.c,v 1.1.4.1 2004/03/20 09:54:05 dillo Exp $
 
   zip_error_str.c -- get string representation of zip error code
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -46,7 +46,7 @@
 
 
 int
-zip_error_str(char *buf, int len, int ze, int se)
+zip_error_str(char *buf, size_t len, int ze, int se)
 {
     const char *zs, *ss;
 
diff --git a/lib/zip_fclose.c b/lib/zip_fclose.c
index 2bca2a6..6fd1ed8 100644
--- a/lib/zip_fclose.c
+++ b/lib/zip_fclose.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_fclose.c,v 1.7 2003/10/02 14:13:29 dillo Exp $
+  $NiH: zip_fclose.c,v 1.8.4.1 2004/04/13 19:47:58 dillo Exp $
 
   zip_fclose.c -- close file in zip archive
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -61,10 +61,10 @@
     }
 
     /* if EOF, compare CRC */
-    if (zff->flags == -1)
+    if (zff->flags & ZIP_ZF_EOF)
 	ret = (zff->crc_orig == zff->crc);
     else
-	ret = zff->flags;
+	ret = zff->error.zip_err;
 
     free(zff);
     return ret;
diff --git a/lib/zip_free_meta.c b/lib/zip_file_get_offset.c
similarity index 62%
rename from lib/zip_free_meta.c
rename to lib/zip_file_get_offset.c
index 5733ed5..2d25c3d 100644
--- a/lib/zip_free_meta.c
+++ b/lib/zip_file_get_offset.c
@@ -1,8 +1,8 @@
 /*
-  $NiH: zip_free_meta.c,v 1.7 2003/03/16 10:21:39 wiz Exp $
+  $NiH: zip_file_get_offset.c,v 1.1.2.2 2004/04/06 20:27:22 dillo Exp $
 
-  zip_free_meta.c -- free struct zip_meta
-  Copyright (C) 1999 Dieter Baron and Thomas Klausner
+  zip_file_get_offset.c -- get offset of file data in archive.
+  Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
 
   This file is part of libzip, a library to manipulate ZIP archives.
   The authors can be contacted at <nih@giga.or.at>
@@ -35,20 +35,44 @@
 
 
 
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include "zip.h"
+#include "zipint.h"
 
-void
-zip_free_meta(struct zip_meta *meta)
+
+
+/* _zip_file_get_offset(za, ze):
+   Returns the offset of the file data for entry ze.
+
+   On error, fills in za->error and returns 0.
+*/
+
+unsigned int
+_zip_file_get_offset(struct zip *za, int idx)
 {
-    if (!meta)
-	return;
-    
-    free(meta->ef);
-    free(meta->lef);
-    free(meta->fc);
+    struct zip_dirent de;
+    unsigned int offset;
 
-    free(meta);
-    
-    return;
+    offset = za->cdir->entry[idx].offset;
+
+    if (fseek(za->zp, offset, SEEK_SET) != 0) {
+	_zip_error_set(&za->error, ZERR_SEEK, errno);
+	return 0;
+    }
+
+    if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0)
+	return 0;
+
+    offset += LENTRYSIZE + de.filename_len + de.extrafield_len;
+
+    _zip_dirent_finalize(&de);
+
+    return offset;
 }
diff --git a/lib/zip_fopen.c b/lib/zip_fopen.c
index 3c31bce..3e542cd 100644
--- a/lib/zip_fopen.c
+++ b/lib/zip_fopen.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_fopen.c,v 1.7 2003/10/03 08:34:11 dillo Exp $
+  $NiH: zip_fopen.c,v 1.8.4.1 2004/04/08 16:53:07 dillo Exp $
 
   zip_fopen.c -- open file in zip archvie for reading
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -48,5 +48,5 @@
     if ((idx=zip_name_locate(za, fname, flags)) < 0)
 	return NULL;
 
-    return zip_fopen_index(za, idx);
+    return zip_fopen_index(za, idx, flags);
 }
diff --git a/lib/zip_fopen_index.c b/lib/zip_fopen_index.c
index 193d9b2..c24af9f 100644
--- a/lib/zip_fopen_index.c
+++ b/lib/zip_fopen_index.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_fopen_index.c,v 1.14 2003/10/06 16:37:41 dillo Exp $
+  $NiH: zip_fopen_index.c,v 1.15.4.10 2004/04/14 09:21:33 dillo Exp $
 
   zip_fopen_index.c -- open file in zip archive for reading by index
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -47,10 +47,10 @@
 
 
 struct zip_file *
-zip_fopen_index(struct zip *zf, int fileno)
+zip_fopen_index(struct zip *zf, int fileno, int flags)
 {
-    unsigned char buf[4];
     int len, ret;
+    int zfflags;
     struct zip_file *zff;
 
     if ((fileno < 0) || (fileno >= zf->nentry)) {
@@ -58,78 +58,71 @@
 	return NULL;
     }
 
-#if 0
-    if (zf->entry[fileno].state != ZIP_ST_UNCHANGED
-	&& zf->entry[fileno].state != ZIP_ST_RENAMED) {
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+	&& ZIP_ENTRY_DATA_CHANGED(zf->entry+fileno)) {
 	_zip_error_set(&zf->error, ZERR_CHANGED, 0);
 	return NULL;
     }
-#endif
 
-    if ((zf->entry[fileno].meta->comp_method != 0)
-	&& (zf->entry[fileno].meta->comp_method != 8)) {
-	_zip_error_set(&zf->error, ZERR_COMPNOTSUPP, 0);
-	return NULL;
+    if ((flags & ZIP_FL_COMPRESSED)
+	|| (zf->cdir->entry[fileno].comp_method == ZIP_CM_STORE))
+	zfflags = ZIP_ZF_COMP;
+    else {
+	if (zf->cdir->entry[fileno].comp_method != ZIP_CM_DEFLATE) {
+	    _zip_error_set(&zf->error, ZERR_COMPNOTSUPP, 0);
+	    return NULL;
+	}
+	zfflags = 0;
     }
 
     zff = _zip_file_new(zf);
 
-    zff->name = zf->entry[fileno].fn;
-    zff->method = zf->entry[fileno].meta->comp_method;
-    zff->bytes_left = zf->entry[fileno].meta->uncomp_size;
-    zff->cbytes_left = zf->entry[fileno].meta->comp_size;
-    zff->crc_orig = zf->entry[fileno].meta->crc;
+    zff->flags = zfflags;
+    /* zff->name = zf->cdir->entry[fileno].filename; */
+    zff->method = zf->cdir->entry[fileno].comp_method;
+    zff->bytes_left = zf->cdir->entry[fileno].uncomp_size;
+    zff->cbytes_left = zf->cdir->entry[fileno].comp_size;
+    zff->crc_orig = zf->cdir->entry[fileno].crc;
 
-    /* go to start of actual data */
-    if (fseek(zf->zp, zf->entry[fileno].meta->local_offset+LENTRYSIZE-4,
-	      SEEK_SET) < 0) {
-	_zip_error_set(&zf->error, ZERR_SEEK, errno);
-	zip_fclose(zff);
-	return NULL;
-    }
-    len = fread(buf, 1, 4, zf->zp);
-    if (len != 4) {
-	_zip_error_set(&zf->error, ZERR_READ, errno);
+    if ((zff->fpos=_zip_file_get_offset(zf, fileno)) == 0) {
 	zip_fclose(zff);
 	return NULL;
     }
     
-    zff->fpos = zf->entry[fileno].meta->local_offset+LENTRYSIZE;
-    zff->fpos += (buf[3]<<8)+buf[2]+(buf[1]<<8)+buf[0];
+    if (zff->flags & ZIP_ZF_COMP)
+	zff->bytes_left = zff->cbytes_left;
+    else {
+	/* XXX: don't use BUFSIZE */
+	if ((zff->buffer=(char *)malloc(BUFSIZE)) == NULL) {
+	    _zip_error_set(&zf->error, ZERR_MEMORY, 0);
+	    zip_fclose(zff);
+	    return NULL;
+	}
+
+	len = _zip_file_fillbuf(zff->buffer, BUFSIZE, zff);
+	if (len <= 0) {
+	    _zip_error_copy(&zf->error, &zff->error);
+	    zip_fclose(zff);
+	return NULL;
+	}
+
+	if ((zff->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) {
+	    _zip_error_set(&zf->error, ZERR_MEMORY, 0);
+	    zip_fclose(zff);
+	    return NULL;
+	}
+	zff->zstr->zalloc = Z_NULL;
+	zff->zstr->zfree = Z_NULL;
+	zff->zstr->opaque = NULL;
+	zff->zstr->next_in = zff->buffer;
+	zff->zstr->avail_in = len;
 	
-    if ((zf->entry[fileno].meta->comp_method == 0)
-	|| (zff->bytes_left == 0))
-	return zff;
-    
-    if ((zff->buffer=(char *)malloc(BUFSIZE)) == NULL) {
-	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
-	zip_fclose(zff);
-	return NULL;
-    }
-
-    len = _zip_file_fillbuf (zff->buffer, BUFSIZE, zff);
-    if (len <= 0) {
-	_zip_error_copy(&zf->error, &zff->error);
-	zip_fclose(zff);
-	return NULL;
-    }
-
-    if ((zff->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) {
-	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
-	zip_fclose(zff);
-	return NULL;
-    }
-    zff->zstr->zalloc = Z_NULL;
-    zff->zstr->zfree = Z_NULL;
-    zff->zstr->opaque = NULL;
-    zff->zstr->next_in = zff->buffer;
-    zff->zstr->avail_in = len;
-
-    /* negative value to tell zlib that there is no header */
-    if ((ret=inflateInit2(zff->zstr, -MAX_WBITS)) != Z_OK) {
-	_zip_error_set(&zf->error, ZERR_ZLIB, ret);
-	zip_fclose(zff);
-	return NULL;
+	/* negative value to tell zlib that there is no header */
+	if ((ret=inflateInit2(zff->zstr, -MAX_WBITS)) != Z_OK) {
+	    _zip_error_set(&zf->error, ZERR_ZLIB, ret);
+	    zip_fclose(zff);
+	    return NULL;
+	}
     }
     
     return zff;
@@ -138,17 +131,18 @@
 
 
 int
-_zip_file_fillbuf(char *buf, int buflen, struct zip_file *zff)
+_zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zff)
 {
     int i, j;
 
-    if (zff->flags != 0)
+    if (zff->error.zip_err != ZERR_OK)
 	return -1;
-    if (zff->cbytes_left <= 0 || buflen <= 0)
+
+    if ((zff->flags & ZIP_ZF_EOF) || zff->cbytes_left <= 0 || buflen <= 0)
 	return 0;
     
     if (fseek(zff->zf->zp, zff->fpos, SEEK_SET) < 0) {
-	zff->flags = ZERR_SEEK;
+	_zip_error_set(&zff->error, ZERR_SEEK, errno);
 	return -1;
     }
     if (buflen < zff->cbytes_left)
@@ -158,11 +152,11 @@
 
     j = fread(buf, 1, i, zff->zf->zp);
     if (j == 0) {
-	zff->flags = ZERR_EOF;
+	_zip_error_set(&zff->error, ZERR_EOF, 0);
 	j = -1;
     }
     else if (j < 0)
-	zff->flags = ZERR_READ;
+	_zip_error_set(&zff->error, ZERR_READ, errno);
     else {
 	zff->fpos += j;
 	zff->cbytes_left -= j;
@@ -200,6 +194,7 @@
     zf->file[zf->nfile++] = zff;
 
     zff->zf = zf;
+    _zip_error_init(&zff->error);
     zff->flags = 0;
     zff->crc = crc32(0L, Z_NULL, 0);
     zff->crc_orig = 0;
diff --git a/lib/zip_fread.c b/lib/zip_fread.c
index 7950dc9..1e21326 100644
--- a/lib/zip_fread.c
+++ b/lib/zip_fread.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_fread.c,v 1.7 2003/03/16 10:21:39 wiz Exp $
+  $NiH: zip_fread.c,v 1.8.4.3 2004/04/13 19:47:59 dillo Exp $
 
   zip_fread.c -- read from file
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -40,30 +40,30 @@
 
 
 
-int
-zip_fread(struct zip_file *zff, char *outbuf, int toread)
+ssize_t
+zip_fread(struct zip_file *zff, void *outbuf, size_t toread)
 {
     int len, out_before, ret;
 
     if (!zff)
 	return -1;
 
-    if ((zff->flags == -1) || (toread == 0))
-	return 0;
-
-    if (zff->flags != 0)
+    if (zff->error.zip_err != 0)
 	return -1;
 
+    if ((zff->flags & ZIP_ZF_EOF) || (toread == 0))
+	return 0;
+
     if (zff->bytes_left == 0) {
-	zff->flags = -1;
+	zff->flags |= ZIP_ZF_EOF;
 	if (zff->crc != zff->crc_orig) {
-	    zff->flags = ZERR_CRC;
+	    _zip_error_set(&zff->error, ZERR_CRC, 0);
 	    return -1;
 	}
 	return 0;
     }
     
-    if (zff->method == 0) {
+    if (zff->flags & ZIP_ZF_COMP) {
 	ret = _zip_file_fillbuf(outbuf, toread, zff);
 	if (ret > 0) {
 	    zff->crc = crc32(zff->crc, outbuf, ret);
@@ -90,16 +90,15 @@
 	    if (len >= zff->bytes_left || len >= toread) {
 		zff->crc = crc32(zff->crc, outbuf, len);
 		zff->bytes_left -= len;
-	        return(len);
+	        return len;
 	    }
 	    break;
 
 	case Z_BUF_ERROR:
 	    if (zff->zstr->avail_in == 0) {
-		/* read some more bytes */
 		len = _zip_file_fillbuf(zff->buffer, BUFSIZE, zff);
 		if (len == 0) {
-		    zff->flags = ZERR_INCONS;
+		    _zip_error_set(&zff->error, ZERR_INCONS, 0);
 		    return -1;
 		}
 		else if (len < 0)
@@ -108,13 +107,12 @@
 		zff->zstr->avail_in = len;
 		continue;
 	    }
-	    zff->flags = ZERR_ZLIB;
-	    return -1;
+	    /* fallthrough */
 	case Z_NEED_DICT:
 	case Z_DATA_ERROR:
 	case Z_STREAM_ERROR:
 	case Z_MEM_ERROR:
-	    zff->flags = ZERR_ZLIB;
+	    _zip_error_set(&zff->error, ZERR_ZLIB, ret);
 	    return -1;
 	}
     }
diff --git a/lib/zip_free.c b/lib/zip_free.c
index e927466..38d8947 100644
--- a/lib/zip_free.c
+++ b/lib/zip_free.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_free.c,v 1.7 2003/10/06 16:37:41 dillo Exp $
+  $NiH: zip_free.c,v 1.8.4.2 2004/04/08 16:55:36 dillo Exp $
 
   zip_free.c -- free struct zip
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -59,8 +59,7 @@
     if (zf->zp)
 	fclose(zf->zp);
 
-    if (zf->com)
-	free(zf->com);
+    _zip_cdir_free(zf->cdir);
 
     if (zf->entry) {
 	for (i=0; i<zf->nentry; i++) {
@@ -72,7 +71,6 @@
     for (i=0; i<zf->nfile; i++) {
 	zf->file[i]->flags = ZERR_ZIPCLOSED;
 	zf->file[i]->zf = NULL;
-	zf->file[i]->name = NULL;
     }
 
     free(zf->file);
diff --git a/lib/zip_free_entry.c b/lib/zip_free_entry.c
index b725525..259befb 100644
--- a/lib/zip_free_entry.c
+++ b/lib/zip_free_entry.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_free_entry.c,v 1.8 2003/10/01 09:51:00 dillo Exp $
+  $NiH: zip_free_entry.c,v 1.9.4.3 2004/04/06 20:30:05 dillo Exp $
 
   zip_free_entry.c -- free struct zip_entry
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -49,15 +49,10 @@
 
     ret = 0;
     
-    free(ze->fn);
-    free(ze->fn_old);
+    free(ze->ch_filename);
     
-    zip_free_meta(ze->meta);
-    zip_free_meta(ze->ch_meta);
     if (ze->ch_func)
 	ret = ze->ch_func(ze->ch_data, NULL, 0, ZIP_CMD_CLOSE);
-    
-    free(ze->ch_data);
 
     return ret;
 }
diff --git a/lib/zip_get_name.c b/lib/zip_get_name.c
index d9a88d7..b3672c9 100644
--- a/lib/zip_get_name.c
+++ b/lib/zip_get_name.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_get_name.c,v 1.5 2003/10/02 14:13:30 dillo Exp $
+  $NiH: zip_get_name.c,v 1.6.4.1 2004/04/06 20:30:05 dillo Exp $
 
   zip_get_name.c -- get filename for a file in zip file
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -48,5 +48,8 @@
 	return NULL;
     }
 
-    return zf->entry[idx].fn;
+    if (zf->entry[idx].ch_filename)
+	return zf->entry[idx].ch_filename;
+
+    return zf->cdir->entry[idx].filename;
 }
diff --git a/lib/zip_merge_meta.c b/lib/zip_merge_meta.c
deleted file mode 100644
index 9c101c4..0000000
--- a/lib/zip_merge_meta.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-  $NiH: zip_merge_meta.c,v 1.7 2003/03/16 10:21:40 wiz Exp $
-
-  zip_merge_meta.c -- merge two meta information structures
-  Copyright (C) 1999 Dieter Baron and Thomas Klausner
-
-  This file is part of libzip, a library to manipulate ZIP archives.
-  The authors can be contacted at <nih@giga.or.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 "zip.h"
-#include "zipint.h"
-
-int
-_zip_merge_meta_fix(struct zip_meta *dest, struct zip_meta *src)
-{
-    if (!src)
-	return 0;
-    if (!dest) {
-	zip_err = ZERR_INTERNAL;
-	return -1;
-    }
-    
-    if (src->version_made != (unsigned short)-1)
-	dest->version_made = src->version_made;
-    if (src->version_need != (unsigned short)-1)
-	dest->version_need = src->version_need;
-    if (src->bitflags != (unsigned short)-1)
-	dest->bitflags = src->bitflags;
-    if (src->comp_method != (unsigned short)-1)
-	dest->comp_method = src->comp_method;
-    if (src->disknrstart != (unsigned short)-1)
-	dest->disknrstart = src->disknrstart;
-    if (src->int_attr != (unsigned short)-1)
-	dest->int_attr = src->int_attr;
-    
-    if (src->crc != (unsigned int)-1)
-	dest->crc = src->crc;
-    if (src->uncomp_size != (unsigned int)-1)
-	dest->uncomp_size = src->uncomp_size;
-    if (src->comp_size != (unsigned int)-1)
-	dest->comp_size = src->comp_size;
-    if (src->ext_attr != (unsigned int)-1)
-	dest->ext_attr = src->ext_attr;
-    if (src->local_offset != (unsigned int)-1)
-	dest->local_offset = src->local_offset;
-
-    if (src->last_mod != 0)
-	dest->last_mod = src->last_mod;
-    
-    return 0;
-}
-
-
-
-int
-_zip_merge_meta(struct zip_meta *dest, struct zip_meta *src)
-{
-    if (!src)
-	return 0;
-    if (!dest) {
-	zip_err = ZERR_INTERNAL;
-	return -1;
-    }
-
-    _zip_merge_meta_fix(dest, src);
-    
-    if ((src->ef_len != (unsigned short)-1) && src->ef) {
-	free(dest->ef);
-	dest->ef = _zip_memdup(src->ef, src->ef_len);
-	if (!dest->ef) {
-	    zip_err = ZERR_MEMORY;
-	    return -1;
-	}
-	dest->ef_len = src->ef_len;
-    }
-
-    if ((src->lef_len != (unsigned short)-1) && src->lef) {
-	free(dest->lef);
-	dest->lef = _zip_memdup(src->lef, src->lef_len);
-	if (!dest->lef) {
-	    zip_err = ZERR_MEMORY;
-	    return -1;
-	}
-	dest->lef_len = src->lef_len;
-    }
-
-    if ((src->fc_len != (unsigned short)-1) && src->fc) {
-	free(dest->fc);
-	dest->fc = _zip_memdup(src->fc, src->fc_len);
-	if (!dest->fc) {
-	    zip_err = ZERR_MEMORY;
-	    return -1;
-	}
-	dest->fc_len = src->fc_len;
-    }
-
-    return 0;
-}
diff --git a/lib/zip_name_locate.c b/lib/zip_name_locate.c
index eb7c9a9..07010dc 100644
--- a/lib/zip_name_locate.c
+++ b/lib/zip_name_locate.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_name_locate.c,v 1.8 2003/10/02 14:13:30 dillo Exp $
+  $NiH: zip_name_locate.c,v 1.9.4.3 2004/04/14 13:58:52 dillo Exp $
 
   zip_name_locate.c -- get index by name
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -46,19 +46,25 @@
 zip_name_locate(struct zip *za, const char *fname, int flags)
 {
     int (*cmp)();
-    const char *fn;
+    const char *fn, *p;
     int i;
 
-    cmp = (flags & ZIP_NAME_NOCASE) ? strcmp : strcasecmp;
+    if (fname == NULL) {
+	_zip_error_set(&za->error, ZERR_INVAL, 0);
+	return -1;
+    }
+    
+    cmp = (flags & ZIP_FL_NOCASE) ? strcmp : strcasecmp;
+
+    /* XXX: honour ZIP_FL_UNCHANGED */
 
     for (i=0; i<za->nentry; i++) {
-	if (flags & ZIP_NAME_NODIR) {
+	fn = zip_get_name(za, i);
+	if (flags & ZIP_FL_NODIR) {
 	    /* XXX: handle '\' */
-	    if ((fn=strrchr(za->entry[i].fn, '/')) == NULL)
-		fn = za->entry[i].fn;
+	    if ((p=strrchr(fn, '/')) != NULL)
+		fn = p;
 	}
-	else 
-	    fn = za->entry[i].fn;
 
 	if (cmp(fname, fn) == 0)
 	    return i;
diff --git a/lib/zip_new.c b/lib/zip_new.c
index 0c34f30..9129c20 100644
--- a/lib/zip_new.c
+++ b/lib/zip_new.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_new.c,v 1.5 2003/10/02 14:13:31 dillo Exp $
+  $NiH: zip_new.c,v 1.6.4.3 2004/04/06 20:30:05 dillo Exp $
 
   zip_new.c -- create and init struct zip
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -46,25 +46,23 @@
    the new struct. */
 
 struct zip *
-_zip_new(int *errp)
+_zip_new(struct zip_error *error)
 {
-    struct zip *zf;
+    struct zip *za;
 
-    zf = (struct zip *)malloc(sizeof(struct zip));
-    if (!zf) {
-	if (errp)
-	    *errp = ZERR_MEMORY;
+    za = (struct zip *)malloc(sizeof(struct zip));
+    if (!za) {
+	_zip_error_set(error, ZERR_MEMORY, 0);
 	return NULL;
     }
 
-    zf->zn = NULL;
-    zf->zp = NULL;
-    zf->comlen = zf->changes = 0;
-    zf->nentry = zf->nentry_alloc = zf->cd_size = zf->cd_offset = 0;
-    zf->nfile = zf->nfile_alloc = 0;
-    zf->com = NULL;
-    zf->entry = NULL;
-    zf->file = NULL;
+    za->zn = NULL;
+    za->zp = NULL;
+    za->nentry = za->nentry_alloc = 0;
+    za->nfile = za->nfile_alloc = 0;
+    za->cdir = NULL;
+    za->entry = NULL;
+    za->file = NULL;
     
-    return zf;
+    return za;
 }
diff --git a/lib/zip_new_entry.c b/lib/zip_new_entry.c
index c006e45..0c59f51 100644
--- a/lib/zip_new_entry.c
+++ b/lib/zip_new_entry.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_new_entry.c,v 1.6 2003/10/01 09:51:00 dillo Exp $
+  $NiH: zip_new_entry.c,v 1.7.4.4 2004/04/07 12:08:22 dillo Exp $
 
   zip_new_entry.c -- create and init struct zip_entry
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -49,32 +49,31 @@
     if (!zf) {
 	ze = (struct zip_entry *)malloc(sizeof(struct zip_entry));
 	if (!ze) {
-	    zip_err = ZERR_MEMORY;
+	    _zip_error_set(&zf->error, ZERR_MEMORY, 0);
 	    return NULL;
 	}
-    } else {
+    }
+    else {
 	if (zf->nentry >= zf->nentry_alloc-1) {
 	    zf->nentry_alloc += 16;
 	    zf->entry = (struct zip_entry *)realloc(zf->entry,
 						    sizeof(struct zip_entry)
 						    * zf->nentry_alloc);
 	    if (!zf->entry) {
-		zip_err = ZERR_MEMORY;
+		_zip_error_set(&zf->error, ZERR_MEMORY, 0);
 		return NULL;
 	    }
 	}
 	ze = zf->entry+zf->nentry;
     }
-    if ((ze->meta = zip_new_meta()) == NULL)
-	return NULL;
 
-    ze->fn = ze->fn_old = NULL;
     ze->state = ZIP_ST_UNCHANGED;
 
+    ze->ch_filename = NULL;
     ze->ch_func = NULL;
     ze->ch_data = NULL;
-    ze->ch_comp = -1;
-    ze->ch_meta = NULL;
+    ze->ch_flags = 0;
+    ze->ch_mtime = -1;
 
     if (zf)
 	zf->nentry++;
diff --git a/lib/zip_new_meta.c b/lib/zip_new_meta.c
deleted file mode 100644
index a2c5e5b..0000000
--- a/lib/zip_new_meta.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-  $NiH: zip_new_meta.c,v 1.5 2003/03/16 10:21:40 wiz Exp $
-
-  zip_new_meta.c -- create and init struct zip_meta
-  Copyright (C) 1999 Dieter Baron and Thomas Klausner
-
-  This file is part of libzip, a library to manipulate ZIP archives.
-  The authors can be contacted at <nih@giga.or.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 "zip.h"
-
-struct zip_meta *
-zip_new_meta(void)
-{
-    struct zip_meta *meta;
-    
-    if ((meta=(struct zip_meta *)malloc(sizeof(struct zip_meta)))==NULL) {
-	zip_err = ZERR_MEMORY;
-	return NULL;
-    }
-
-    meta->version_made = meta->version_need = meta->bitflags = -1;
-    meta->comp_method = meta->disknrstart = meta->int_attr = -1;
-    meta->crc = meta->comp_size = meta->uncomp_size = -1;
-    meta->ext_attr = meta->local_offset = -1;
-    meta->ef_len = meta->lef_len = meta->fc_len = -1;
-
-    meta->last_mod = 0;
-    meta->ef = meta->lef = meta->fc = NULL;
-
-    return meta;
-}
diff --git a/lib/zip_open.c b/lib/zip_open.c
index 163ef28..4341258 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_open.c,v 1.18 2003/10/06 16:37:41 dillo Exp $
+  $NiH: zip_open.c,v 1.19.4.6 2004/04/13 19:47:59 dillo Exp $
 
   zip_open.c -- open zip archive
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -46,69 +46,63 @@
 #include "zip.h"
 #include "zipint.h"
 
-static void set_error(int *errp, int err);
-static struct zip *_zip_readcdir(FILE *fp, unsigned char *buf,
-			   unsigned char *eocd, int buflen, int *errp);
-static int _zip_read2(unsigned char **a);
-static int _zip_read4(unsigned char **a);
-static char *_zip_readstr(unsigned char **buf, int len, int nulp);
-static char *_zip_readfpstr(FILE *fp, int len, int nulp);
-static int _zip_checkcons(FILE *fp, struct zip *zf);
-static int _zip_headercomp(struct zip_entry *h1, int local1p,
-			   struct zip_entry *h2, int local2p);
-static unsigned char *_zip_memmem(const unsigned char *big, int biglen,
-				  const unsigned char *little, int littlelen);
-static time_t _zip_d2u_time(int dtime, int ddate);
+static void set_error(int *, struct zip_error *, int);
+static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
+static int _zip_headercomp(struct zip_dirent *, int,
+			   struct zip_dirent *, int);
+static unsigned char *_zip_memmem(const unsigned char *, int,
+				  const unsigned char *, int);
+static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *,
+				 int, struct zip_error *);
 
 
 
-/* zip_open:
-   Tries to open the file 'fn' as a zipfile. If flags & ZIP_CHECKCONS,
-   also does some consistency checks (comparing local headers to
-   central directory entries). If flags & ZIP_CREATE, make a new file
-   (if flags & ZIP_EXCL, error if already existing).  Returns a
-   zipfile struct, or NULL if unsuccessful, setting zip_err. */
-
 struct zip *
-zip_open(const char *fn, int flags, int *errp)
+zip_open(const char *fn, int flags, int *zep)
 {
     FILE *fp;
     unsigned char *buf, *match;
     int a, i, buflen, best;
-    struct zip *cdir, *cdirnew;
+    struct zip *za;
+    struct zip_cdir *cdir, *cdirnew;
     long len;
     struct stat st;
+    struct zip_error error, err2;
 
     if (fn == NULL) {
-	set_error(errp, ZERR_INVAL);
+	set_error(zep, NULL, ZERR_INVAL);
 	return NULL;
     }
     
     if (stat(fn, &st) != 0) {
 	if (flags & ZIP_CREATE) {
-	    if ((cdir=_zip_new(errp)) == NULL)
-		return NULL;
-	    
-	    cdir->zn = strdup(fn);
-	    if (!cdir->zn) {
-		_zip_free(cdir);
-		set_error(errp, ZERR_MEMORY);
+	    if ((za=_zip_new(&error)) == NULL) {
+		set_error(zep, &error, 0);
 		return NULL;
 	    }
-	    return cdir;
-	} else {
-	    set_error(errp, ZERR_NOENT);
+	    
+	    za->zn = strdup(fn);
+	    if (!za->zn) {
+		_zip_free(za);
+		set_error(zep, NULL, ZERR_MEMORY);
+		return NULL;
+	    }
+	    return za;
+	}
+	else {
+	    set_error(zep, NULL, ZERR_OPEN);
 	    return NULL;
 	}
-    } else if ((flags & ZIP_EXCL)) {
-	set_error(errp, ZERR_EXISTS);
+    }
+    else if ((flags & ZIP_EXCL)) {
+	set_error(zep, NULL, ZERR_EXISTS);
 	return NULL;
     }
     /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
        just like open() */
     
-    if ((fp=fopen(fn, "rb"))==NULL) {
-	set_error(errp, ZERR_OPEN);
+    if ((fp=fopen(fn, "rb")) == NULL) {
+	set_error(zep, NULL, ZERR_OPEN);
 	return NULL;
     }
     
@@ -118,15 +112,14 @@
     i = fseek(fp, -(len < BUFSIZE ? len : BUFSIZE), SEEK_END);
     if (i == -1 && errno != EFBIG) {
 	/* seek before start of file on my machine */
-	set_error(errp, ZERR_SEEK);
+	set_error(zep, NULL, ZERR_SEEK);
 	fclose(fp);
 	return NULL;
     }
 
-    /* XXX: why not allocate statically? */
-    buf = (unsigned char *)malloc(BUFSIZE);
-    if (!buf) {
-	set_error(errp, ZERR_MEMORY);
+    /* 64k is too much for stack */
+    if ((buf=(unsigned char *)malloc(BUFSIZE)) == NULL) {
+	set_error(zep, NULL, ZERR_MEMORY);
 	fclose(fp);
 	return NULL;
     }
@@ -135,7 +128,7 @@
     buflen = fread(buf, 1, BUFSIZE, fp);
 
     if (ferror(fp)) {
-	set_error(errp, ZERR_READ);
+	set_error(zep, NULL, ZERR_READ);
 	free(buf);
 	fclose(fp);
 	return NULL;
@@ -149,62 +142,83 @@
 	/* found match -- check, if good */
 	/* to avoid finding the same match all over again */
 	match++;
-	if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, errp)) == NULL)
+	if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, &err2)) == NULL)
 	    continue;	    
 
 	if (cdir) {
 	    if (best <= 0)
-		best = _zip_checkcons(fp, cdir);
-	    a = _zip_checkcons(fp, cdirnew);
+		best = _zip_checkcons(fp, cdir, &err2);
+	    a = _zip_checkcons(fp, cdirnew, &err2);
 	    if (best < a) {
-		_zip_free(cdir);
+		_zip_cdir_free(cdir);
 		cdir = cdirnew;
 		best = a;
 	    }
 	    else
-		_zip_free(cdirnew);
+		_zip_cdir_free(cdirnew);
 	}
 	else {
 	    cdir = cdirnew;
 	    if (flags & ZIP_CHECKCONS)
-		best = _zip_checkcons(fp, cdir);
+		best = _zip_checkcons(fp, cdir, &err2);
 	    else
 		best = 0;
 	}
 	cdirnew = NULL;
     }
 
+    free(buf);
+    
     if (best < 0) {
 	/* no consistent eocd found */
-	set_error(errp, ZERR_NOZIP);
-	free(buf);
-	_zip_free(cdir);
+	set_error(zep, NULL, ZERR_NOZIP);
+	_zip_cdir_free(cdir);
 	fclose(fp);
 	return NULL;
     }
 
-    free(buf);
-
-    cdir->zn = strdup(fn);
-    if (!cdir->zn) {
-	set_error(errp, ZERR_MEMORY);
-	_zip_free(cdir);
+    if ((za=_zip_new(&error)) == NULL) {
+	set_error(zep, &error, 0);
+	_zip_cdir_free(cdir);
 	fclose(fp);
 	return NULL;
     }
 
-    cdir->zp = fp;
+    za->zp = fp;
+    za->cdir = cdir;
     
-    return cdir;
+    if ((za->zn=strdup(fn)) == NULL) {
+	set_error(zep, NULL, ZERR_MEMORY);
+	_zip_free(za);
+	return NULL;
+    }
+
+    if ((za->entry=malloc(sizeof(*(za->entry))*cdir->nentry)) == NULL) {
+	set_error(zep, NULL, ZERR_MEMORY);
+	_zip_free(za);
+	return NULL;
+    }
+    for (i=0; i<cdir->nentry; i++)
+	_zip_new_entry(za);
+
+    return za;
 }
 
 
 
 static void
-set_error(int *errp, int err)
+set_error(int *zep, struct zip_error *err, int ze)
 {
-    if (errp)
-	*errp = err;
+    int se;
+
+    if (err) {
+	_zip_error_get(err, &ze, &se);
+	if (zip_error_sys_type(ze) == ZIP_ET_SYS)
+	    errno = se;
+    }
+
+    if (zep)
+	*zep = ze;
 }
 
 
@@ -212,357 +226,95 @@
 /* _zip_readcdir:
    tries to find a valid end-of-central-directory at the beginning of
    buf, and then the corresponding central directory entries.
-   Returns a struct zip which contains the central directory 
+   Returns a struct zip_cdir which contains the central directory 
    entries, or NULL if unsuccessful. */
 
-static struct zip *
+static struct zip_cdir *
 _zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen,
-	      int *errp)
+	      struct zip_error *error)
 {
-    struct zip *zf;
-    unsigned char *cdp;
-    int i, comlen, readp;
-    int entries;
+    struct zip_cdir *cd;
+    unsigned char *cdp, **bufp;
+    int i, comlen, nentry;
 
     comlen = buf + buflen - eocd - EOCDLEN;
     if (comlen < 0) {
 	/* not enough bytes left for comment */
-	set_error(errp, ZERR_NOZIP);
+	_zip_error_set(error, ZERR_NOZIP, 0);
 	return NULL;
     }
 
     /* check for end-of-central-dir magic */
     if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
-	set_error(errp, ZERR_NOZIP);
+	_zip_error_set(error, ZERR_NOZIP, 0);
 	return NULL;
     }
 
     if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
-	set_error(errp, ZERR_MULTIDISK);
+	_zip_error_set(error, ZERR_MULTIDISK, 0);
 	return NULL;
     }
 
-    if ((zf=_zip_new(errp)) == NULL)
-	return NULL;
-
     cdp = eocd + 8;
     /* number of cdir-entries on this disk */
     i = _zip_read2(&cdp);
     /* number of cdir-entries */
-    entries = _zip_read2(&cdp);
-    zf->cd_size = _zip_read4(&cdp);
-    zf->cd_offset = _zip_read4(&cdp);
-    zf->comlen = _zip_read2(&cdp);
-    zf->entry = NULL;
+    nentry = _zip_read2(&cdp);
+
+    if ((cd=_zip_cdir_new(nentry, error)) == NULL)
+	return NULL;
+
+    cd->size = _zip_read4(&cdp);
+    cd->offset = _zip_read4(&cdp);
+    cd->comment = NULL;
+    cd->comment_len = _zip_read2(&cdp);
 
     /* XXX: some zip files are broken; their internal comment length
        says 0, but they have 1 or 2 comment bytes */
-    if (((zf->comlen != comlen) && (zf->comlen != comlen-1) &&
-	 (zf->comlen != comlen-2)) || (entries != i)) {
+    if ((comlen-cd->comment_len < 0) || (comlen-cd->comment_len > 2)
+	|| (cd->nentry != i)) {
 	/* comment size wrong -- too few or too many left after central dir */
 	/* or number of cdir-entries on this disk != number of cdir-entries */
-	set_error(errp, ZERR_NOZIP);
-	_zip_free(zf);
+	_zip_error_set(error, ZERR_NOZIP, 0);
+	free(cd);
 	return NULL;
     }
 
-    zf->com = (unsigned char *)_zip_memdup(eocd+EOCDLEN, zf->comlen);
+    if (cd->comment_len)
+	cd->comment = _zip_memdup(eocd+EOCDLEN, cd->comment_len);
 
     cdp = eocd;
-    if (zf->cd_size < eocd-buf) {
+    if (cd->size < eocd-buf) {
 	/* if buffer already read in, use it */
-	readp = 0;
-	cdp = eocd - zf->cd_size;
+	cdp = eocd - cd->size;
+	bufp = &cdp;
     }
     else {
 	/* go to start of cdir and read it entry by entry */
-	readp = 1;
+	bufp = NULL;
 	clearerr(fp);
-	fseek(fp, -(zf->cd_size+zf->comlen+EOCDLEN), SEEK_END);
-	if (ferror(fp) || (ftell(fp) != zf->cd_offset)) {
+	fseek(fp, -(cd->size+cd->comment_len+EOCDLEN), SEEK_END);
+	if (ferror(fp) || (ftell(fp) != cd->offset)) {
 	    /* seek error or offset of cdir wrong */
 	    if (ferror(fp))
-		set_error(errp, ZERR_SEEK);
+		_zip_error_set(error, ZERR_SEEK, errno);
 	    else
-		set_error(errp, ZERR_NOZIP);
-	    _zip_free(zf);
+		_zip_error_set(error, ZERR_NOZIP, 0);
+	    free(cd);
 	    return NULL;
 	}
     }
 
-    zf->entry = (struct zip_entry *)malloc(sizeof(struct zip_entry)
-					   *entries);
-    if (!zf->entry) {
-	set_error(errp, ZERR_MEMORY);
-	_zip_free(zf);
-	return NULL;
-    }
-
-    zf->nentry_alloc = entries;
-
-    for (i=0; i<entries; i++) {
-	if (_zip_new_entry(zf) == NULL) {
-	    /* shouldn't happen, since space already has been malloc'd */
-	    _zip_error_get(&zf->error, errp, NULL);
-	    _zip_free(zf);
+    for (i=0; i<cd->nentry; i++) {
+	if ((_zip_dirent_read(cd->entry+i, fp, bufp, eocd-cdp, 0,
+			      error)) < 0) {
+	    cd->nentry = i;
+	    _zip_cdir_free(cd);
 	    return NULL;
 	}
     }
     
-    for (i=0; i<zf->nentry; i++) {
-	if ((_zip_readcdentry(fp, zf->entry+i, &cdp, eocd-cdp,
-			      readp, 0)) < 0) {
-	    _zip_free(zf);
-	    return NULL;
-	}
-    }
-    
-    return zf;
-}
-
-
-
-/* _zip_readcdentry:
-   fills the zipfile entry zfe with data from the buffer *cdpp, not reading
-   more than 'left' bytes from it; if readp != 0, it also reads more data
-   from fp, if necessary. If localp != 0, it reads a local header instead
-   of a central directory entry. Returns 0 if successful, -1 if not,
-   advancing *cdpp for each byte read. */
-
-int
-_zip_readcdentry(FILE *fp, struct zip_entry *zfe, unsigned char **cdpp, 
-		 int left, int readp, int localp)
-{
-    unsigned char buf[CDENTRYSIZE];
-    unsigned char *cur;
-    unsigned short dostime, dosdate;
-    int size;
-
-    if (localp)
-	size = LENTRYSIZE;
-    else
-	size = CDENTRYSIZE;
-    
-    if (readp) {
-	/* read entry from disk */
-	if ((fread(buf, 1, size, fp)<size)) {
-	    zip_err = ZERR_READ;
-	    return -1;
-	}
-	left = size;
-	cur = buf;
-    }
-    else {
-	cur = *cdpp;
-	if (left < size) {
-	    zip_err = ZERR_NOZIP;
-	    return -1;
-	}
-    }
-
-    if (localp) {
-	if (memcmp(cur, LOCAL_MAGIC, 4)!=0) {
-	    zip_err = ZERR_NOZIP;
-	    return -1;
-	}
-    }
-    else
-	if (memcmp(cur, CENTRAL_MAGIC, 4)!=0) {
-	    zip_err = ZERR_NOZIP;
-	    return -1;
-	}
-
-    cur += 4;
-
-    /* convert buffercontents to zf_entry */
-    if (!localp)
-	zfe->meta->version_made = _zip_read2(&cur);
-    else
-	zfe->meta->version_made = 0;
-    zfe->meta->version_need = _zip_read2(&cur);
-    zfe->meta->bitflags = _zip_read2(&cur);
-    zfe->meta->comp_method = _zip_read2(&cur);
-    /* convert to time_t */
-    dostime = _zip_read2(&cur);
-    dosdate = _zip_read2(&cur);
-
-    zfe->meta->last_mod = _zip_d2u_time(dostime, dosdate);
-    
-    zfe->meta->crc = _zip_read4(&cur);
-    zfe->meta->comp_size = _zip_read4(&cur);
-    zfe->meta->uncomp_size = _zip_read4(&cur);
-    
-    zfe->file_fnlen = _zip_read2(&cur);
-    if (localp) {
-	zfe->meta->ef_len = 0;
-	zfe->meta->lef_len = _zip_read2(&cur);
-	zfe->meta->fc_len = zfe->meta->disknrstart = zfe->meta->int_attr = 0;
-	zfe->meta->ext_attr = zfe->meta->local_offset = 0;
-    } else {
-	zfe->meta->ef_len = _zip_read2(&cur);
-	zfe->meta->lef_len = 0;
-	zfe->meta->fc_len = _zip_read2(&cur);
-	zfe->meta->disknrstart = _zip_read2(&cur);
-	zfe->meta->int_attr = _zip_read2(&cur);
-
-	zfe->meta->ext_attr = _zip_read4(&cur);
-	zfe->meta->local_offset = _zip_read4(&cur);
-    }
-
-    if (left < CDENTRYSIZE+zfe->file_fnlen+zfe->meta->ef_len
-	+zfe->meta->lef_len+zfe->meta->fc_len) {
-	if (readp) {
-	    if (zfe->file_fnlen)
-		zfe->fn = _zip_readfpstr(fp, zfe->file_fnlen, 1);
-	    else
-		zfe->fn = strdup("");
-
-	    if (!zfe->fn) {
-		zip_err = ZERR_MEMORY;
-		return -1;
-	    }
-
-	    /* only set for local headers */
-	    if (zfe->meta->lef_len) {
-		zfe->meta->lef = _zip_readfpstr(fp, zfe->meta->lef_len, 0);
-		if (!zfe->meta->lef)
-		    return -1;
-	    }
-
-	    /* only set for central directory entries */
-	    if (zfe->meta->ef_len) {
-		zfe->meta->ef = _zip_readfpstr(fp, zfe->meta->ef_len, 0);
-		if (!zfe->meta->ef)
-		    return -1;
-	    }
-
-	    /* only set for central directory entries */
-	    if (zfe->meta->fc_len) {
-		zfe->meta->fc = _zip_readfpstr(fp, zfe->meta->fc_len, 0);
-		if (!zfe->meta->fc)
-		    return -1;
-	    }
-	}
-	else {
-	    /* can't get more bytes if not allowed to read */
-	    zip_err = ZERR_NOZIP;
-	    return -1;
-	}
-    }
-    else {
-        if (zfe->file_fnlen) {
-	    zfe->fn = _zip_readstr(&cur, zfe->file_fnlen, 1);
-	    if (!zfe->fn)
-		return -1;
-	}
-
-	/* only set for local headers */
-	if (zfe->meta->lef_len) {
-	    zfe->meta->lef = _zip_readstr(&cur, zfe->meta->lef_len, 0);
-	    if (!zfe->meta->lef)
-		return -1;
-	}
-
-	/* only set for central directory entries */
-	if (zfe->meta->ef_len) {
-	    zfe->meta->ef = _zip_readstr(&cur, zfe->meta->ef_len, 0);
-	    if (!zfe->meta->ef)
-		return -1;
-	}
-
-	/* only set for central directory entries */
-        if (zfe->meta->fc_len) {
-	    zfe->meta->fc = _zip_readstr(&cur, zfe->meta->fc_len, 0);
-	    if (!zfe->meta->fc)
-		return -1;
-	}
-    }
-    if (!readp)
-      *cdpp = cur;
-
-    return 0;
-}
-
-
-
-static int
-_zip_read2(unsigned char **a)
-{
-    int ret;
-
-    ret = (*a)[0]+((*a)[1]<<8);
-    *a += 2;
-
-    return ret;
-}
-
-
-
-static int
-_zip_read4(unsigned char **a)
-{
-    int ret;
-
-    ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
-    *a += 4;
-
-    return ret;
-}
-
-
-
-static char *
-_zip_readstr(unsigned char **buf, int len, int nulp)
-{
-    char *r, *o;
-
-    r = (char *)malloc(nulp?len+1:len);
-    if (!r) {
-	zip_err = ZERR_MEMORY;
-	return NULL;
-    }
-    
-    memcpy(r, *buf, len);
-    *buf += len;
-
-    if (nulp) {
-	/* elephant */
-	r[len] = 0;
-	o = r-1;
-	while (((o=memchr(o+1, 0, r+len-(o+1))) < r+len) && o)
-	       *o = ' ';
-    }
-
-    return r;
-}
-
-
-
-static char *
-_zip_readfpstr(FILE *fp, int len, int nulp)
-{
-    char *r, *o;
-
-    r = (char *)malloc(nulp?len+1:len);
-    if (!r) {
-	zip_err = ZERR_MEMORY;
-	return NULL;
-    }
-
-    if (fread(r, 1, len, fp)<len) {
-	free(r);
-	return NULL;
-    }
-
-    if (nulp) {
-	/* elephant */
-	r[len] = 0;
-	o = r-1;
-	while (((o=memchr(o+1, 0, r+len-(o+1))) < r+len) && o)
-	       *o = ' ';
-    }
-    
-    return r;
+    return cd;
 }
 
 
@@ -574,60 +326,51 @@
    difference between the lowest and the highest fileposition reached */
 
 static int
-_zip_checkcons(FILE *fp, struct zip *zf)
+_zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
 {
     int min, max, i, j;
-    struct zip_entry *temp;
+    struct zip_dirent temp;
     unsigned char *buf;
 
     buf = NULL;
-    if (zf->nentry) {
-	max = zf->entry[0].meta->local_offset;
-	min = zf->entry[0].meta->local_offset;
+    if (cd->nentry) {
+	max = cd->entry[0].offset;
+	min = cd->entry[0].offset;
     }
 
-    if ((temp=_zip_new_entry(NULL))==NULL)
-	return -1;
-    
-    for (i=0; i<zf->nentry; i++) {
-	if (zf->entry[i].meta->local_offset < min)
-	    min = zf->entry[i].meta->local_offset;
+    for (i=0; i<cd->nentry; i++) {
+	if (cd->entry[i].offset < min)
+	    min = cd->entry[i].offset;
 	if (min < 0) {
-	    zip_err = ZERR_NOZIP;
-	    _zip_free_entry(temp);
+	    _zip_error_set(error, ZERR_NOZIP, 0);
 	    return -1;
 	}
 	
-	j = zf->entry[i].meta->local_offset + zf->entry[i].meta->comp_size
-	    + zf->entry[i].file_fnlen + zf->entry[i].meta->ef_len
-	    + zf->entry[i].meta->fc_len + LENTRYSIZE;
+	j = cd->entry[i].offset + cd->entry[i].comp_size
+	    + cd->entry[i].filename_len + LENTRYSIZE;
 	if (j > max)
 	    max = j;
-	if (max > zf->cd_offset) {
-	    zip_err = ZERR_NOZIP;
-	    _zip_free_entry(temp);
+	if (max > cd->offset) {
+	    _zip_error_set(error, ZERR_NOZIP, 0);
 	    return -1;
 	}
 	
-	if (fseek(fp, zf->entry[i].meta->local_offset, SEEK_SET) != 0) {
-	    zip_err = ZERR_SEEK;
-	    _zip_free_entry(temp);
+	if (fseek(fp, cd->entry[i].offset, SEEK_SET) != 0) {
+	    _zip_error_set(error, ZERR_SEEK, 0);
 	    return -1;
 	}
 	
-	if (_zip_readcdentry(fp, temp, &buf, 0, 1, 1) == -1) {
-	    _zip_free_entry(temp);
+	if (_zip_dirent_read(&temp, fp, NULL, 0, 1, error) == -1)
 	    return -1;
-	}
 	
-	if (_zip_headercomp(zf->entry+i, 0, temp, 1) != 0) {
-	    zip_err = ZERR_NOZIP;
-	    _zip_free_entry(temp);
+	if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
+	    _zip_error_set(error, ZERR_NOZIP, 0);
+	    _zip_dirent_finalize(&temp);
 	    return -1;
 	}
+	_zip_dirent_finalize(&temp);
     }
 
-    _zip_free_entry(temp);
     return max - min;
 }
 
@@ -639,42 +382,45 @@
    are identical, -1 if not. */
 
 static int
-_zip_headercomp(struct zip_entry *h1, int local1p, struct zip_entry *h2,
+_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
 	   int local2p)
 {
-    if ((h1->meta->version_need != h2->meta->version_need)
+    if ((h1->version_needed != h2->version_needed)
 #if 0
 	/* some zip-files have different values in local
 	   and global headers for the bitflags */
-	|| (h1->meta->bitflags != h2->meta->bitflags)
+	|| (h1->bitflags != h2->bitflags)
 #endif
-	|| (h1->meta->comp_method != h2->meta->comp_method)
-	|| (h1->meta->last_mod != h2->meta->last_mod)
-	|| (h1->meta->crc != h2->meta->crc)
-	|| (h1->meta->comp_size != h2->meta->comp_size)
-	|| (h1->meta->uncomp_size != h2->meta->uncomp_size)
-	|| !h1->fn
-	|| !h2->fn
-	|| strcmp(h1->fn, h2->fn))
+	|| (h1->comp_method != h2->comp_method)
+	|| (h1->last_mod != h2->last_mod)
+	|| (h1->crc != h2->crc)
+	|| (h1->comp_size != h2->comp_size)
+	|| (h1->uncomp_size != h2->uncomp_size)
+	|| (h1->filename_len != h2->filename_len)
+	|| !h1->filename || !h2->filename
+	|| strcmp(h1->filename, h2->filename))
 	return -1;
 
-    /* if they are different type, nothing more to check */
-    if (local1p != local2p)
+    if ((local1p == local2p)
+	&& ((h1->extrafield_len != h2->extrafield_len)
+	    || (h1->extrafield_len && h2->extrafield
+		&& memcmp(h1->extrafield, h2->extrafield,
+			  h1->extrafield_len))))
+	return -1;
+
+    /* if either is local, nothing more to check */
+    if (local1p || local2p)
 	return 0;
 
-    if ((h1->meta->version_made != h2->meta->version_made)
-	|| (h1->meta->disknrstart != h2->meta->disknrstart)
-	|| (h1->meta->int_attr != h2->meta->int_attr)
-	|| (h1->meta->ext_attr != h2->meta->ext_attr)
-	|| (h1->meta->local_offset != h2->meta->local_offset)
-	|| (h1->meta->ef_len != h2->meta->ef_len)
-	|| (h1->meta->ef_len && memcmp(h1->meta->ef, h2->meta->ef,
-				       h1->meta->ef_len))
-	|| (h1->meta->fc_len != h2->meta->fc_len)
-	|| (h1->meta->fc_len && memcmp(h1->meta->fc, h2->meta->fc,
-				       h1->meta->fc_len))) {
+    if ((h1->version_madeby != h2->version_madeby)
+	|| (h1->disk_number != h2->disk_number)
+	|| (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)))
 	return -1;
-    }
 
     return 0;
 }
@@ -707,7 +453,7 @@
 
     ret = malloc(len);
     if (!ret) {
-	zip_err = ZERR_MEMORY;
+	/* XXX: zip_err = ZERR_MEMORY; */
 	return NULL;
     }
 
@@ -715,25 +461,3 @@
 
     return ret;
 }
-
-
-
-static time_t
-_zip_d2u_time(int dtime, int ddate)
-{
-    struct tm *tm;
-    time_t now;
-
-    now = time(NULL);
-    tm = localtime(&now);
-    
-    tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
-    tm->tm_mon = ((ddate>>5)&15) - 1;
-    tm->tm_mday = ddate&31;
-
-    tm->tm_hour = (dtime>>11)&31;
-    tm->tm_min = (dtime>>5)&63;
-    tm->tm_sec = (dtime<<1)&62;
-
-    return mktime(tm);
-}
diff --git a/lib/zip_rename.c b/lib/zip_rename.c
index e9c1f9b..258f289 100644
--- a/lib/zip_rename.c
+++ b/lib/zip_rename.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_rename.c,v 1.9 2003/10/03 23:25:31 dillo Exp $
+  $NiH: zip_rename.c,v 1.10.4.1 2004/03/20 09:54:07 dillo Exp $
 
   zip_rename.c -- rename file in zip archive
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -48,11 +48,10 @@
 	return -1;
     }
 
+    /* XXX: move this to _zip_set_name */
     if (zf->entry[idx].state == ZIP_ST_UNCHANGED) 
 	zf->entry[idx].state = ZIP_ST_RENAMED;
     
-    zf->changes = 1;
-
     _zip_set_name(zf, idx, name);
 
     return 0;
diff --git a/lib/zip_replace.c b/lib/zip_replace.c
index eed4d58..347c337 100644
--- a/lib/zip_replace.c
+++ b/lib/zip_replace.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace.c,v 1.10 2003/10/01 09:51:01 dillo Exp $
+  $NiH: zip_replace.c,v 1.11.4.3 2004/04/10 23:52:15 dillo Exp $
 
   zip_replace.c -- replace file via callback function
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,8 +41,22 @@
 
 
 int
-zip_replace(struct zip *zf, int idx, const char *name, struct zip_meta *meta,
-	    zip_read_func fn, void *state, int comp)
+zip_replace(struct zip *zf, int idx, zip_read_func fn, void *state, int flags)
+{
+    if (idx < 0 || idx >= zf->nentry) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace(zf, idx, NULL, fn, state, flags);
+}
+
+
+
+
+int
+_zip_replace(struct zip *zf, int idx, const char *name,
+	     zip_read_func fn, void *state, int flags)
 {
     if (idx == -1) {
 	if (_zip_new_entry(zf) == NULL)
@@ -51,25 +65,17 @@
 	idx = zf->nentry - 1;
     }
     
-    if (idx < 0 || idx >= zf->nentry) {
-	zip_err = ZERR_INVAL;
-	return -1;
-    }
-
     if (_zip_unchange_data(zf->entry+idx) != 0)
 	return -1;
 
     if (_zip_set_name(zf, idx, name) != 0)
 	return -1;
     
-    zf->changes = 1;
-    zf->entry[idx].state = ZIP_ST_REPLACED;
-    if (zf->entry[idx].ch_meta)
-	zip_free_meta(zf->entry[idx].ch_meta);
-    zf->entry[idx].ch_meta = meta;
+    zf->entry[idx].state = ((zf->cdir == NULL || idx >= zf->cdir->nentry)
+			    ? ZIP_ST_ADDED : ZIP_ST_REPLACED);
     zf->entry[idx].ch_func = fn;
     zf->entry[idx].ch_data = state;
-    zf->entry[idx].ch_comp = comp;
+    zf->entry[idx].ch_flags = flags;
 
     return 0;
 }
diff --git a/lib/zip_replace_data.c b/lib/zip_replace_data.c
index 75b1cb6..5b1c533 100644
--- a/lib/zip_replace_data.c
+++ b/lib/zip_replace_data.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_data.c,v 1.11 2003/10/01 09:51:01 dillo Exp $
+  $NiH: zip_replace_data.c,v 1.12.4.1 2004/03/20 09:54:08 dillo Exp $
 
   zip_replace_data.c -- replace file from buffer
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -43,29 +43,37 @@
 
 struct read_data {
     const char *buf, *data;
-    int len;
+    off_t len;
     int freep;
 };
 
-static int read_data(void *state, void *data, int len, enum zip_cmd cmd);
-
+static ssize_t read_data(void *state, void *data, size_t len,
+			 enum zip_cmd cmd);
 
 
 
 int
-zip_replace_data(struct zip *zf, int idx, const char *name,
-		 struct zip_meta *meta,
-		 const char *data, int len, int freep)
+zip_replace_data(struct zip *zf, int idx,
+		 const void *data, off_t len, int freep)
 {
-    struct read_data *f;
-
-    if (idx < -1 || idx >= zf->nentry) {
-	zip_err = ZERR_INVAL;
+    if (idx < 0 || idx >= zf->nentry) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
 	return -1;
     }
     
-    if ((f=(struct read_data *)malloc(sizeof(struct read_data))) == NULL) {
-	zip_err = ZERR_MEMORY;
+    return _zip_replace_data(zf, idx, NULL, data, len, freep);
+}
+
+
+
+int
+_zip_replace_data(struct zip *zf, int idx, const char *name,
+		  const void *data, off_t len, int freep)
+{
+    struct read_data *f;
+
+    if ((f=malloc(sizeof(*f))) == NULL) {
+	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
 	return -1;
     }
 
@@ -73,13 +81,13 @@
     f->len = len;
     f->freep = freep;
     
-    return zip_replace(zf, idx, name, meta, read_data, f, 0);
+    return _zip_replace(zf, idx, name, read_data, f, 0);
 }
 
 
 
 static int
-read_data(void *state, void *data, int len, enum zip_cmd cmd)
+read_data(void *state, void *data, size_t len, enum zip_cmd cmd)
 {
     struct read_data *z;
     char *buf;
@@ -106,15 +114,16 @@
 
 	return n;
 	
-    case ZIP_CMD_META:
-	return 0;
-
     case ZIP_CMD_CLOSE:
 	if (z->freep) {
 	    free((void *)z->data);
 	    z->data = NULL;
 	}
+	free(z);
 	return 0;
+
+    default:
+	;
     }
 
     return -1;
diff --git a/lib/zip_replace_file.c b/lib/zip_replace_file.c
index 7a992d9..4d70e7b 100644
--- a/lib/zip_replace_file.c
+++ b/lib/zip_replace_file.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_file.c,v 1.10 2003/10/01 09:51:01 dillo Exp $
+  $NiH: zip_replace_file.c,v 1.11.4.1 2004/03/20 09:54:08 dillo Exp $
 
   zip_replace_file.c -- replace file from file system
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -35,7 +35,8 @@
 
 
 
-#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
 
 #include "zip.h"
 #include "zipint.h"
@@ -43,22 +44,29 @@
 
 
 int
-zip_replace_file(struct zip *zf, int idx, const char *name,
-		 struct zip_meta *meta,
-		 const char *fname, int start, int len)
+zip_replace_file(struct zip *zf, int idx,
+		 const char *fname, off_t start, off_t len)
+{
+    if (idx < 0 || idx >= zf->nentry) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
+	return -1;
+    }
+
+    return _zip_replace_file(zf, idx, NULL, fname, start, len);
+}
+
+
+
+int
+_zip_replace_file(struct zip *zf, int idx, const char *name,
+		  const char *fname, off_t start, off_t len)
 {
     FILE *fp;
 
-    if (idx < -1 || idx >= zf->nentry) {
-	zip_err = ZERR_INVAL;
-	return -1;
-    }
-    
     if ((fp=fopen(fname, "rb")) == NULL) {
-	zip_err = ZERR_OPEN;
+	_zip_error_set(&zf->error, ZERR_OPEN, errno);
 	return -1;
     }
 
-    return zip_replace_filep(zf, idx, (name ? name : fname), meta,
-			     fp, start, len);
+    return _zip_replace_filep(zf, idx, name, fp, start, len);
 }
diff --git a/lib/zip_replace_filep.c b/lib/zip_replace_filep.c
index 4a22616..d0bbb21 100644
--- a/lib/zip_replace_filep.c
+++ b/lib/zip_replace_filep.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_filep.c,v 1.6 2003/10/01 09:51:01 dillo Exp $
+  $NiH: zip_replace_filep.c,v 1.7.4.1 2004/03/20 09:54:08 dillo Exp $
 
   zip_replace_filep.c -- replace file from FILE*
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -42,27 +42,35 @@
 
 struct read_file {
     FILE *f;
-    int off, len;
+    off_t off, len;
 };
 
-static int read_file(void *state, void *data, int len, enum zip_cmd cmd);
+static int read_file(void *state, void *data, size_t len, enum zip_cmd cmd);
 
 
 
 int
-zip_replace_filep(struct zip *zf, int idx, const char *name,
-		  struct zip_meta *meta,
-		  FILE *file, int start, int len)
+zip_replace_filep(struct zip *zf, int idx,
+		  FILE *file, off_t start, off_t len)
 {
-    struct read_file *f;
-
-    if (idx < -1 || idx >= zf->nentry) {
-	zip_err = ZERR_INVAL;
+    if (idx < 0 || idx >= zf->nentry) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
 	return -1;
     }
     
+    return _zip_replace_filep(zf, idx, NULL, file, start, len);
+}
+
+
+
+int
+_zip_replace_filep(struct zip *zf, int idx, const char *name,
+		  FILE *file, off_t start, off_t len)
+{
+    struct read_file *f;
+
     if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
-	zip_err = ZERR_MEMORY;
+	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
 	return -1;
     }
 
@@ -70,13 +78,13 @@
     f->off = start;
     f->len = (len ? len : -1);
     
-    return zip_replace(zf, idx, name, meta, read_file, f, 0);
+    return _zip_replace(zf, idx, name, read_file, f, 0);
 }
 
 
 
 static int
-read_file(void *state, void *data, int len, enum zip_cmd cmd)
+read_file(void *state, void *data, size_t len, enum zip_cmd cmd)
 {
     struct read_file *z;
     char *buf;
@@ -87,8 +95,8 @@
 
     switch (cmd) {
     case ZIP_CMD_INIT:
-	if (fseek(z->f, z->off, SEEK_SET) < 0) {
-	    zip_err = ZERR_SEEK;
+	if (fseeko(z->f, z->off, SEEK_SET) < 0) {
+	    /* XXX: zip_err = ZERR_SEEK; */
 	    return -1;
 	}
 	return 0;
@@ -100,7 +108,7 @@
 	    n = len;
 	
 	if ((i=fread(buf, 1, n, z->f)) < 0) {
-	    zip_err = ZERR_READ;
+	    /* XXX: zip_err = ZERR_READ; */
 	    return -1;
 	}
 
@@ -109,15 +117,16 @@
 
 	return i;
 	
-    case ZIP_CMD_META:
-	return 0;
-
     case ZIP_CMD_CLOSE:
 	if (z->f) {
 	    fclose(z->f);
 	    z->f = NULL;
 	}
+	free(z);
 	return 0;
+
+    default:
+	;
     }
 
     return -1;
diff --git a/lib/zip_replace_zip.c b/lib/zip_replace_zip.c
index e77447c..2ecf9a3 100644
--- a/lib/zip_replace_zip.c
+++ b/lib/zip_replace_zip.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_zip.c,v 1.16 2003/10/01 09:51:01 dillo Exp $
+  $NiH: zip_replace_zip.c,v 1.17.4.10 2004/04/14 09:21:34 dillo Exp $
 
   zip_replace_zip.c -- replace file from zip file
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -40,131 +40,98 @@
 #include "zipint.h"
 
 struct read_zip {
-    struct zip *zf;
-    int idx;
-    long fpos;
-    long avail;
-    /* XXX: ... */
+    struct zip_file *zf;
+    struct zip_stat st;
+    off_t off, len;
 };
 
-struct read_part {
-    struct zip *zf;
-    int idx;
-    struct zip_file *zff;
-    int off, len;
-    /* XXX: ... */
-};
-
-static int read_zip(void *state, void *data, int len, enum zip_cmd cmd);
-static int read_part(void *state, void *data, int len, enum zip_cmd cmd);
+static ssize_t read_zip(void *st, void *data, size_t len, enum zip_cmd cmd);
 
 
 
 int
-zip_replace_zip(struct zip *zf, int idx, const char *name,
-		struct zip_meta *meta,
-		struct zip *srczf, int srcidx, int start, int len)
+zip_replace_zip(struct zip *zf, int idx,
+		struct zip *srczf, int srcidx, int flags,
+		off_t start, off_t len)
 {
-    struct read_zip *z;
-    struct read_part *p;
-
-    if (srcidx < -1 || srcidx >= srczf->nentry) {
-	zip_err = ZERR_INVAL;
+    if (srcidx < 0 || srcidx >= srczf->nentry) {
+	_zip_error_set(&zf->error, ZERR_INVAL, 0);
 	return -1;
     }
 
-    if ((srczf->entry[srcidx].meta->comp_method != 0
-	 && start == 0 && (len == 0 || len == -1))) {
-	if ((z=(struct read_zip *)malloc(sizeof(struct read_zip))) == NULL) {
-	    zip_err = ZERR_MEMORY;
-	    return -1;
-	}
-	z->zf = srczf;
-	z->idx = srcidx;
-	return zip_replace(zf, idx, (name ? name : srczf->entry[srcidx].fn),
-			   meta, read_zip, z, 1);
-    }
-    else {
-	if ((p=(struct read_part *)malloc(sizeof(struct read_part))) == NULL) {
-	    zip_err = ZERR_MEMORY;
-	    return -1;
-	}
-	p->zf = srczf;
-	p->idx = srcidx;
-	p->off = start;
-	p->len = (len ? len : -1);
-	p->zff = NULL;
-	return zip_replace(zf, idx, (name ? name : srczf->entry[srcidx].fn),
-			   meta, read_part, p, 0);
-    }
+    return _zip_replace_zip(zf, idx, NULL, srczf, srcidx, flags, start, len);
 }
 
 
 
-static int
-read_zip(void *state, void *data, int len, enum zip_cmd cmd)
+int
+_zip_replace_zip(struct zip *zf, int idx, const char *name,
+		 struct zip *srczf, int srcidx, int flags,
+		 off_t start, off_t len)
+{
+    struct zip_error error;
+    struct read_zip *p;
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+	&& ZIP_ENTRY_DATA_CHANGED(srczf->entry+srcidx)) {
+	_zip_error_set(&zf->error, ZERR_CHANGED, 0);
+	return NULL;
+    }
+
+    if (len == 0)
+	len = -1;
+
+    if (start == 0 && len == -1)
+	flags |= ZIP_FL_COMPRESSED;
+    else
+	flags &= ~ZIP_FL_COMPRESSED;
+
+    if ((p=malloc(sizeof(*p))) == NULL) {
+	_zip_error_set(&zf->error, ZERR_MEMORY, 0);
+	return -1;
+    }
+	
+    _zip_error_copy(&error, &srczf->error);
+	
+    if (zip_stat_index(srczf, srcidx, flags, &p->st) < 0
+	|| (p->zf=zip_fopen_index(srczf, srcidx, flags)) == NULL) {
+	free(p);
+	_zip_error_copy(&zf->error, &srczf->error);
+	_zip_error_copy(&srczf->error, &error);
+	
+	return -1;
+    }
+    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;
+	/* XXX: crc */
+    }
+    
+    return _zip_replace(zf, idx, name, read_zip, p, 0);
+}
+
+
+
+static ssize_t
+read_zip(void *state, void *data, size_t len, enum zip_cmd cmd)
 {
     struct read_zip *z;
-    int ret;
-    
-    z = (struct read_zip *)state;
-
-    switch (cmd) {
-    case ZIP_CMD_INIT:
-	_zip_local_header_read(z->zf, z->idx);
-	z->fpos = z->zf->entry[z->idx].meta->local_offset + LENTRYSIZE
-	    + z->zf->entry[z->idx].meta->lef_len
-	    + z->zf->entry[z->idx].meta->fc_len
-	    + z->zf->entry[z->idx].file_fnlen;
-	z->avail = z->zf->entry[z->idx].meta->comp_size;
-	return 0;
-	
-    case ZIP_CMD_READ:
-	if (fseek(z->zf->zp, z->fpos, SEEK_SET) < 0) {
-	    zip_err = ZERR_SEEK;
-	    return -1;
-	}
-	if ((ret=fread(data, 1, len < z->avail ? len : z->avail,
-		       z->zf->zp)) < 0) {
-	    zip_err = ZERR_READ;
-	    return -1;
-	}
-	z->fpos += ret;
-	z->avail -= ret;
-	return ret;
-	
-    case ZIP_CMD_META:
-	return _zip_merge_meta_fix((struct zip_meta *)data,
-				   z->zf->entry[z->idx].meta);
-    case ZIP_CMD_CLOSE:
-	return 0;
-    }
-
-    return -1;
-}
-
-
-
-static int
-read_part(void *state, void *data, int len, enum zip_cmd cmd)
-{
-    struct read_part *z;
     char b[8192], *buf;
     int i, n;
 
-    z = (struct read_part *)state;
+    z = (struct read_zip *)state;
     buf = (char *)data;
 
     switch (cmd) {
     case ZIP_CMD_INIT:
-	if ((z->zff=zip_fopen_index(z->zf, z->idx) ) == NULL)
-	    return -1;
-
 	for (n=0; n<z->off; n+= i) {
-	    i = (z->off-n > 8192 ? 8192 : z->off-n);
-	    if ((i=zip_fread(z->zff, b, i)) < 0) {
-		zip_fclose(z->zff);
-		z->zff = NULL;
+	    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;
 	    }
 	}
@@ -176,23 +143,31 @@
 	else
 	    n = len;
 	
-	if ((i=zip_fread(z->zff, buf, n)) < 0)
+
+	if ((i=zip_fread(z->zf, buf, n)) < 0) {
+	    /* XXX: copy error from z->zff */
 	    return -1;
+	}
 
 	if (z->len != -1)
 	    z->len -= i;
 
 	return i;
 	
-    case ZIP_CMD_META:
+    case ZIP_CMD_CLOSE:
+	zip_fclose(z->zf);
+	free(z);
 	return 0;
 
-    case ZIP_CMD_CLOSE:
-	if (z->zff) {
-	    zip_fclose(z->zff);
-	    z->zff = NULL;
-	}
+    case ZIP_CMD_STAT:
+	if (len < sizeof(z->st))
+	    return -1;
+
+	memcpy(data, &z->st, sizeof(z->st));
 	return 0;
+
+    default:
+	;
     }
 
     return -1;
diff --git a/lib/zip_set_name.c b/lib/zip_set_name.c
index 6647b01..57dcab8 100644
--- a/lib/zip_set_name.c
+++ b/lib/zip_set_name.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_set_name.c,v 1.9 2003/10/02 14:13:32 dillo Exp $
+  $NiH: zip_set_name.c,v 1.10.4.1 2004/04/06 20:30:07 dillo Exp $
 
   zip_set_name.c -- rename helper function
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -58,11 +58,8 @@
 	    return -1;
 	}
 	
-	if (zf->entry[idx].fn_old == NULL)
-	    zf->entry[idx].fn_old = zf->entry[idx].fn;
-	else
-	    free(zf->entry[idx].fn);
-	zf->entry[idx].fn = s;
+	free(zf->entry[idx].ch_filename);
+	zf->entry[idx].ch_filename = s;
     }
 
     return 0;
diff --git a/lib/zip_stat.c b/lib/zip_stat.c
index 44a1113..81f6b26 100644
--- a/lib/zip_stat.c
+++ b/lib/zip_stat.c
@@ -1,5 +1,5 @@
 /*
-  $NiH$
+  $NiH: zip_stat.c,v 1.1.4.1 2004/04/14 09:21:34 dillo Exp $
 
   zip_stat.c -- get information about file by name
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -48,5 +48,5 @@
     if ((idx=zip_name_locate(za, fname, flags)) < 0)
 	return -1;
 
-    return zip_stat_index(za, idx, st);
+    return zip_stat_index(za, idx, flags, st);
 }
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c
index 06bda6e..a1c02aa 100644
--- a/lib/zip_stat_index.c
+++ b/lib/zip_stat_index.c
@@ -1,5 +1,5 @@
 /*
-  $NiH$
+  $NiH: zip_stat_index.c,v 1.1.4.4 2004/04/14 09:21:34 dillo Exp $
 
   zip_stat_index.c -- get information about file by index
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -41,21 +41,28 @@
 
 
 int
-zip_stat_index(struct zip *za, int index, struct zip_stat *st)
+zip_stat_index(struct zip *za, int index, int flags, struct zip_stat *st)
 {
     if (index < 0 || index >= za->nentry) {
 	_zip_error_set(&za->error, ZERR_INVAL, 0);
 	return -1;
     }
 
-    st->name = za->entry[index].fn;
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+	&& ZIP_ENTRY_DATA_CHANGED(za->entry+index)) {
+	/* XXX: call ch_func with ZIP_CMD_STAT */
+	_zip_error_set(&za->error, ZERR_CHANGED, 0);
+	return NULL;
+    }
+    
+    st->name = zip_get_name(za, index);
     st->index = index;
-    st->crc = za->entry[index].meta->crc;
-    st->size = za->entry[index].meta->uncomp_size;
-    st->mtime = za->entry[index].meta->last_mod;
-    st->comp_size = za->entry[index].meta->comp_size;
-    st->comp_method = za->entry[index].meta->comp_method;
-    /* st->bitflags = za->entry[index].meta->bitflags; */
+    st->crc = za->cdir->entry[index].crc;
+    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;
+    /* st->bitflags = za->cdir->entry[index].bitflags; */
 
     return 0;
 }
diff --git a/lib/zip_unchange.c b/lib/zip_unchange.c
index 8b8ad25..7cd76ca 100644
--- a/lib/zip_unchange.c
+++ b/lib/zip_unchange.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_unchange.c,v 1.10 2003/10/03 08:34:11 dillo Exp $
+  $NiH: zip_unchange.c,v 1.11.4.2 2004/04/06 20:30:07 dillo Exp $
 
   zip_unchange.c -- undo changes to file in zip archive
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -51,13 +51,11 @@
 	return -1;
     }
 
-    if (zf->entry[idx].fn_old) {
-	free(zf->entry[idx].fn);
-	zf->entry[idx].fn = zf->entry[idx].fn_old;
-	zf->entry[idx].fn_old = NULL;
+    if (zf->entry[idx].ch_filename) {
+	free(zf->entry[idx].ch_filename);
+	zf->entry[idx].ch_filename = NULL;
     }
 
-    zip_free_meta(zf->entry[idx].ch_meta);
     ret = _zip_unchange_data(zf->entry+idx);
         
     return ret;
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c
index aa81637..880f489 100644
--- a/lib/zip_unchange_data.c
+++ b/lib/zip_unchange_data.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_unchange_data.c,v 1.8 2003/03/16 10:21:42 wiz Exp $
+  $NiH: zip_unchange_data.c,v 1.9.4.2 2004/04/06 20:30:07 dillo Exp $
 
   zip_unchange_data.c -- undo helper function
   Copyright (C) 1999 Dieter Baron and Thomas Klausner
@@ -51,13 +51,9 @@
 	ze->ch_func = NULL;
     }
     
-    free(ze->ch_data);
-    ze->ch_data = NULL;
-    
-    ze->ch_comp = 0;
+    ze->ch_flags = 0;
 
-    ze->state = (ze->fn_old || ze->ch_meta) ? ZIP_ST_RENAMED
-	: ZIP_ST_UNCHANGED;
+    ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED;
 
     return ret;
 }
diff --git a/lib/zipint.h b/lib/zipint.h
index 8a74463..ce43d06 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -1,8 +1,9 @@
+
 #ifndef _HAD_ZIPINT_H
 #define _HAD_ZIPINT_H
 
 /*
-  $NiH: zipint.h,v 1.21 2003/10/06 16:37:42 dillo Exp $
+  $NiH: zipint.h,v 1.22.4.12 2004/04/14 09:21:35 dillo Exp $
 
   zipint.h -- internal declarations.
   Copyright (C) 1999, 2003 Dieter Baron and Thomas Klausner
@@ -50,60 +51,103 @@
 
 
 
+/* state of change of a file in zip archive */
+
+enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED,
+		 ZIP_ST_ADDED, ZIP_ST_RENAMED };
+
+/* constants for struct zip_file's member flags */
+
+#define ZIP_ZF_EOF	1 /* EOF reached */
+#define ZIP_ZF_COMP	2 /* read compressed data */
+
+/* error information */
+
 struct zip_error {
     int zip_err;	/* libzip error code (ZERR_*) */
     int sys_err;	/* copy of errno (E*) or zlib error code */
     char *str;		/* string representation or NULL */
 };
 
+/* zip archive, part of API */
+
 struct zip {
-    char *zn;
-    FILE *zp;
-    struct zip_error error;
-    unsigned short comlen, changes;
-    unsigned int cd_size, cd_offset;
-    char *com;
-    int nentry, nentry_alloc;
-    struct zip_entry *entry;
-    int nfile, nfile_alloc;
-    struct zip_file **file;
+    char *zn;			/* file name */
+    FILE *zp;			/* file */
+    struct zip_error error;	/* error information */
+
+    struct zip_cdir *cdir;	/* central directory */
+    int nentry;			/* number of entries */
+    int nentry_alloc;		/* number of entries allocated */
+    struct zip_entry *entry;	/* entries */
+    int nfile;			/* number of opened files within archvie */
+    int nfile_alloc;		/* number of files allocated */
+    struct zip_file **file;	/* opened files within archvie */
 };
 
-/* file in zip file */
+/* file in zip archive, part of API */
 
 struct zip_file {
-    struct zip *zf;
-    char *name;
-    struct zip_error error;
-    int flags; /* -1: eof, >0: error */
+    struct zip *zf;		/* zip archive containing this file */
+    struct zip_error error;	/* error information */
+    int flags;			/* -1: eof, >0: error */
 
-    int method;
-    /* position within zip file (fread/fwrite) */
-    long fpos;
-    /* no of bytes left to read */
-    unsigned long bytes_left;
-    /* no of bytes of compressed data left */
-    unsigned long cbytes_left;
-    /* crc so far */
-    unsigned long crc, crc_orig;
+    int method;			/* compression method */
+    long fpos;			/* position within zip file (fread/fwrite) */
+    unsigned long bytes_left;	/* number of bytes left to read */
+    unsigned long cbytes_left;  /* number of bytes of compressed data left */
+    
+    unsigned long crc;		/* crc so far */
+    unsigned long crc_orig;	/* CRC recorded in archive */
     
     char *buffer;
     z_stream *zstr;
 };
 
-/* entry in zip file directory */
+/* zip archive directory entry (central or local) */
+
+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 purposee 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 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)  offest of local header  */
+};
+
+/* zip archive central directory */
+
+struct zip_cdir {
+    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 */
+};
+
+/* entry in zip archive directory */
 
 struct zip_entry {
-    struct zip_meta *meta;
-    char *fn;
-    char *fn_old;
-    unsigned int file_fnlen;
-
     enum zip_state state;
     zip_read_func ch_func;
     void *ch_data;
-    int ch_comp;		/* 1: data returned by ch_func is compressed */
-    struct zip_meta *ch_meta;
+    int ch_flags;		/* 1: data returned by ch_func is compressed */
+    char *ch_filename;
+    time_t ch_mtime;
 };
 
 
@@ -114,6 +158,20 @@
 
 
 
+#define ZIP_ENTRY_DATA_CHANGED(x)	\
+			((x)->state == ZIP_ST_REPLACED  \
+			 || (x)->state == ZIP_ST_ADDED)
+
+
+
+void _zip_cdir_free(struct zip_cdir *);
+struct zip_cdir *_zip_cdir_new(int, struct zip_error *);
+int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *);
+void _zip_dirent_finalize(struct zip_dirent *);
+void _zip_dirent_init(struct zip_dirent *);
+int _zip_dirent_read(struct zip_dirent *, FILE *,
+		     unsigned char **, int, int, struct zip_error *);
+int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *);
 void _zip_entry_init(struct zip *, int);
 void _zip_error_copy(struct zip_error *, struct zip_error *);
 void _zip_error_fini(struct zip_error *);
@@ -121,17 +179,24 @@
 void _zip_error_init(struct zip_error *);
 void _zip_error_set(struct zip_error *, int, int);
 const char *_zip_error_strerror(struct zip_error *);
-int _zip_file_fillbuf(char *, int, struct zip_file *);
+int _zip_file_fillbuf(void *, size_t, struct zip_file *);
+unsigned int _zip_file_get_offset(struct zip *, int);
 void _zip_free(struct zip *);
 int _zip_free_entry(struct zip_entry *);
 int _zip_local_header_read(struct zip *, int);
 void *_zip_memdup(const void *, int);
-int _zip_merge_meta(struct zip_meta *, struct zip_meta *);
-int _zip_merge_meta_fix(struct zip_meta *, struct zip_meta *);
-struct zip *_zip_new(int *);
+struct zip *_zip_new(struct zip_error *);
 struct zip_entry *_zip_new_entry(struct zip *);
-int _zip_readcdentry(FILE *, struct zip_entry *, unsigned char **, 
-		     int, int, int);
+unsigned short _zip_read2(unsigned char **);
+unsigned int _zip_read4(unsigned char **);
+int _zip_replace(struct zip *, int, const char *,zip_read_func, void *, int);
+int _zip_replace_data(struct zip *, int, const char *,
+		      const void *, off_t, int);
+int _zip_replace_file(struct zip *, int, const char *,
+		      const char *, off_t, off_t);
+int _zip_replace_filep(struct zip *, int, const char *, FILE *, off_t, off_t);
+int _zip_replace_zip(struct zip *, int, const char *,
+		     struct zip *, int, int, off_t, off_t);
 int _zip_set_name(struct zip *, int, const char *);
 int _zip_unchange(struct zip_entry *);
 int _zip_unchange_data(struct zip_entry *);