change functions API overhaul:
- rename ZIP_CMD_INIT to ZIP_CMD_OPEN
- ZIP_CMD_CLOSE is called when reading is done
- add ZIP_CMD_FREE to free resources
- ZIP_CMD_STAT is called to retrieve meta info (time stamp, compression
        method, sizes, crc)
- add ZIP_CMD_ERROR to return error codes

get rid of (now unused) zip_entry members ch_flags and ch_mtime

--HG--
branch : HEAD
diff --git a/TODO b/TODO
index 91506a9..84b7ba0 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,5 @@
 ------------------------------------------------ showstopper
+* zip_replace: remove flags argument?  (currently unused)
 * API cleanup
 	check function names (consistency, appropriateness)
 	file sizes, offsets: type big enough? (no, zip64)
@@ -13,6 +14,7 @@
 * README
 * set mtime for changed entries
 ------------------------------------------------ others
+* zip_replace_zip: allow rewinding
 * API for (file and archive) comments
 * fix warnings in zipcmp
 * zipcmp: add option for file content comparison
diff --git a/lib/zip.h b/lib/zip.h
index e5dc65c..576f900 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -2,7 +2,7 @@
 #define _HAD_ZIP_H
 
 /*
-  $NiH: zip.h,v 1.36 2004/04/14 14:01:22 dillo Exp $
+  $NiH: zip.h,v 1.37 2004/04/16 09:40:26 dillo Exp $
 
   zip.h -- exported declarations.
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -85,6 +85,7 @@
 #define ZERR_NOZIP           19  /* N Not a zip archive */
 #define ZERR_INTERNAL        20  /* N Internal error */
 #define ZERR_INCONS	     21  /* N Zip archive inconsistent */
+#define ZERR_REMOVE	     22  /* S Can't remove file */
 
 
 /* type of system error value */
@@ -110,10 +111,12 @@
 
 
 enum zip_cmd {
-    ZIP_CMD_INIT,	/* prepare for reading */
+    ZIP_CMD_OPEN,	/* prepare for reading */
     ZIP_CMD_READ, 	/* read data */
-    ZIP_CMD_CLOSE,	/* close and cleanup */
-    ZIP_CMD_STAT	/* for compressed data */
+    ZIP_CMD_CLOSE,	/* reading is done */
+    ZIP_CMD_STAT,	/* get meta information */
+    ZIP_CMD_ERROR,	/* get error information */
+    ZIP_CMD_FREE	/* cleanup and free resources */
 };
 
 typedef ssize_t (*zip_read_func)(void *state, void *data,
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 485f060..5f85f1a 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_close.c,v 1.40 2004/04/16 09:40:27 dillo Exp $
+  $NiH: zip_close.c,v 1.41 2004/04/19 11:49:12 dillo Exp $
 
   zip_close.c -- close zip archive and update changes
   Copyright (C) 1999, 2004 Dieter Baron and Thomas Klausner
@@ -47,10 +47,11 @@
 #include "zipint.h"
 
 static int add_data(struct zip *, int, struct zip_dirent *, FILE *);
-static int add_data_comp(zip_read_func, void *, struct zip_dirent *, FILE *,
+static int add_data_comp(zip_read_func, void *, struct zip_stat *, FILE *,
 			 struct zip_error *);
-static int add_data_uncomp(zip_read_func, void *, struct zip_dirent *, FILE *,
+static int add_data_uncomp(zip_read_func, void *, struct zip_stat *, FILE *,
 			   struct zip_error *);
+static void ch_set_error(struct zip_error *, zip_read_func, void *);
 static int copy_data(FILE *, off_t, FILE *, struct zip_error *);
 
 
@@ -163,11 +164,11 @@
 	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].last_mod = de.last_mod;
 	    cd->entry[j].comp_method = de.comp_method;
 	    cd->entry[j].comp_size = de.comp_size;
 	    cd->entry[j].uncomp_size = de.uncomp_size;
@@ -241,12 +242,18 @@
     off_t offstart, offend;
     zip_read_func rf;
     void *ud;
+    struct zip_stat st;
     
     rf = za->entry[idx].ch_func;
     ud = za->entry[idx].ch_data;
 
-    if (rf(ud, NULL, 0, ZIP_CMD_INIT) < 0) {
-	/* XXX: set error */
+    if (rf(ud, &st, sizeof(st), ZIP_CMD_STAT) < sizeof(st)) {
+	ch_set_error(&za->error, rf, ud);
+	return -1;
+    }
+
+    if (rf(ud, NULL, 0, ZIP_CMD_OPEN) < 0) {
+	ch_set_error(&za->error, rf, ud);
 	return -1;
     }
 
@@ -255,22 +262,19 @@
     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)
+    if (st.comp_method != ZIP_CM_STORE) {
+	if (add_data_comp(rf, ud, &st, ft, &za->error) < 0)
 	    return -1;
     }
     else {
-	if (add_data_uncomp(rf, ud, de, ft, &za->error) < 0)
+	if (add_data_uncomp(rf, ud, &st, ft, &za->error) < 0)
 	    return -1;
     }
 
-#if 0
-    /* XXX: this is also called in _zip_free */
     if (rf(ud, NULL, 0, ZIP_CMD_CLOSE) < 0) {
-	/* XXX: set error */
+	ch_set_error(&za->error, rf, ud);
 	return -1;
     }
-#endif
 
     offend = ftell(ft);
 
@@ -279,6 +283,12 @@
 	return -1;
     }
     
+    de->comp_method = st.comp_method;
+    de->last_mod = st.mtime;
+    de->crc = st.crc;
+    de->uncomp_size = st.size;
+    de->comp_size = st.comp_size;
+
     if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
 	return -1;
     
@@ -293,44 +303,33 @@
 
 
 static int
-add_data_comp(zip_read_func rf, void *ud, struct zip_dirent *de, FILE *ft,
+add_data_comp(zip_read_func rf, void *ud, struct zip_stat *st,FILE *ft,
 	      struct zip_error *error)
 {
     char buf[BUFSIZE];
     ssize_t n;
-    struct zip_stat st;
 
-    if (rf(ud, &st, sizeof(st), ZIP_CMD_STAT) < 0) {
-	/* XXX: set error */
-	return -1;
-    }
-
-    de->comp_size = 0;
+    st->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->comp_size += n;
+	st->comp_size += n;
     }
     if (n < 0) {
-	/* XXX: set error */
+	ch_set_error(error, rf, ud);
 	return -1;
     }	
 
-    de->comp_method = st.comp_method;
-    /* de->last_mod = st.mtime; */
-    de->crc = st.crc;
-    de->uncomp_size = st.size;
-
     return 0;
 }
 
 
 
 static int
-add_data_uncomp(zip_read_func rf, void *ud, struct zip_dirent *de, FILE *ft,
+add_data_uncomp(zip_read_func rf, void *ud, struct zip_stat *st, FILE *ft,
 		struct zip_error *error)
 {
     char b1[BUFSIZE], b2[BUFSIZE];
@@ -338,11 +337,9 @@
     ssize_t n;
     z_stream zstr;
 
-    /* ZIP_CMD_STAT for mtime? */
-
-    de->comp_method = ZIP_CM_DEFLATE;
-    de->comp_size = de->uncomp_size = 0;
-    de->crc = crc32(0, NULL, 0);
+    st->comp_method = ZIP_CM_DEFLATE;
+    st->comp_size = st->size = 0;
+    st->crc = crc32(0, NULL, 0);
 
     zstr.zalloc = Z_NULL;
     zstr.zfree = Z_NULL;
@@ -363,15 +360,15 @@
     while (!end) {
 	if (zstr.avail_in == 0 && !flush) {
 	    if ((n=rf(ud, b1, sizeof(b1), ZIP_CMD_READ)) < 0) {
-		/* XXX: set error */
+		ch_set_error(error, rf, ud);
 		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);
+		st->size += n;
+		st->crc = crc32(st->crc, b1, n);
 	    }
 	    else
 		flush = Z_FINISH;
@@ -393,7 +390,7 @@
 	
 	    zstr.next_out = b2;
 	    zstr.avail_out = sizeof(b2);
-	    de->comp_size += n;
+	    st->comp_size += n;
 	}
 
 	if (ret == Z_STREAM_END) {
@@ -407,6 +404,23 @@
 
 
 
+static void
+ch_set_error(struct zip_error *error, zip_read_func rf, void *ud)
+{
+    int e[2];
+
+    if ((rf(ud, e, sizeof(e), ZIP_CMD_READ)) < sizeof(e)) {
+	error->zip_err = ZERR_INTERNAL;
+	error->sys_err = 0;
+    }
+    else {
+	error->zip_err = e[0];
+	error->sys_err = e[1];
+    }
+}
+
+
+
 static int
 copy_data(FILE *fs, off_t len, FILE *ft, struct zip_error *error)
 {
diff --git a/lib/zip_free_entry.c b/lib/zip_free_entry.c
index 719864b..47b00e2 100644
--- a/lib/zip_free_entry.c
+++ b/lib/zip_free_entry.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_free_entry.c,v 1.10 2004/04/14 14:01:25 dillo Exp $
+  $NiH: zip_free_entry.c,v 1.11 2004/04/16 09:40:28 dillo Exp $
 
   zip_free_entry.c -- free struct zip_entry
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -52,7 +52,7 @@
     free(ze->ch_filename);
     
     if (ze->ch_func)
-	ret = ze->ch_func(ze->ch_data, NULL, 0, ZIP_CMD_CLOSE);
+	ret = ze->ch_func(ze->ch_data, NULL, 0, ZIP_CMD_FREE);
 
     return ret;
 }
diff --git a/lib/zip_new_entry.c b/lib/zip_new_entry.c
index d8971ac..e35a423 100644
--- a/lib/zip_new_entry.c
+++ b/lib/zip_new_entry.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_new_entry.c,v 1.8 2004/04/14 14:01:26 dillo Exp $
+  $NiH: zip_new_entry.c,v 1.9 2004/04/16 09:40:29 dillo Exp $
 
   zip_new_entry.c -- create and init struct zip_entry
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -72,8 +72,6 @@
     ze->ch_filename = NULL;
     ze->ch_func = NULL;
     ze->ch_data = NULL;
-    ze->ch_flags = 0;
-    ze->ch_mtime = -1;
 
     if (zf)
 	zf->nentry++;
diff --git a/lib/zip_replace.c b/lib/zip_replace.c
index 7d2266d..553b11f 100644
--- a/lib/zip_replace.c
+++ b/lib/zip_replace.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace.c,v 1.12 2004/04/14 14:01:27 dillo Exp $
+  $NiH: zip_replace.c,v 1.13 2004/04/16 09:40:29 dillo Exp $
 
   zip_replace.c -- replace file via callback function
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -75,7 +75,6 @@
 			    ? ZIP_ST_ADDED : ZIP_ST_REPLACED);
     zf->entry[idx].ch_func = fn;
     zf->entry[idx].ch_data = state;
-    zf->entry[idx].ch_flags = flags;
 
     return 0;
 }
diff --git a/lib/zip_replace_data.c b/lib/zip_replace_data.c
index 9ff8e2a..367b8cc 100644
--- a/lib/zip_replace_data.c
+++ b/lib/zip_replace_data.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_data.c,v 1.13 2004/04/14 14:01:27 dillo Exp $
+  $NiH: zip_replace_data.c,v 1.14 2004/04/16 09:40:30 dillo Exp $
 
   zip_replace_data.c -- replace file from buffer
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -42,8 +42,8 @@
 #include "zipint.h"
 
 struct read_data {
-    const char *buf, *data;
-    off_t len;
+    const char *buf, *data, *end;
+    time_t mtime;
     int freep;
 };
 
@@ -78,8 +78,9 @@
     }
 
     f->data = data;
-    f->len = len;
+    f->end = data+len;
     f->freep = freep;
+    f->mtime = time(NULL);
     
     return _zip_replace(zf, idx, name, read_data, f, 0);
 }
@@ -97,24 +98,57 @@
     buf = (char *)data;
 
     switch (cmd) {
-    case ZIP_CMD_INIT:
+    case ZIP_CMD_OPEN:
 	z->buf = z->data;
 	return 0;
 	
     case ZIP_CMD_READ:
-	n = len > z->len ? z->len : len;
+	n = z->end - z->buf;
+	if (n > len)
+	    n = len;
 	if (n < 0)
 	    n = 0;
 
 	if (n) {
 	    memcpy(buf, z->buf, n);
 	    z->buf += n;
-	    z->len -= n;
 	}
 
 	return n;
 	
     case ZIP_CMD_CLOSE:
+	return 0;
+
+    case ZIP_CMD_STAT:
+        {
+	    struct zip_stat *st;
+	    
+	    if (len < sizeof(*st))
+		return -1;
+
+	    st = (struct zip_stat *)data;
+
+	    st->mtime = z->mtime;
+	    st->crc = 0;
+	    st->size = z->end - z->data;
+	    st->comp_size = -1;
+	    st->comp_method = ZIP_CM_STORE;
+	    
+	    return sizeof(*st);
+	}
+
+    case ZIP_CMD_ERROR:
+	{
+	    int *e;
+
+	    if (len < sizeof(int)*2)
+		return -1;
+
+	    e[0] = e[1] = 0;
+	}
+	return sizeof(int)*2;
+
+    case ZIP_CMD_FREE:
 	if (z->freep) {
 	    free((void *)z->data);
 	    z->data = NULL;
diff --git a/lib/zip_replace_filep.c b/lib/zip_replace_filep.c
index 95d7d0b..cfe193b 100644
--- a/lib/zip_replace_filep.c
+++ b/lib/zip_replace_filep.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_filep.c,v 1.8 2004/04/14 14:01:27 dillo Exp $
+  $NiH: zip_replace_filep.c,v 1.9 2004/04/16 09:40:30 dillo Exp $
 
   zip_replace_filep.c -- replace file from FILE*
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -35,14 +35,21 @@
 
 
 
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "zip.h"
 #include "zipint.h"
 
 struct read_file {
-    FILE *f;
-    off_t off, len;
+    FILE *f;		/* file to copy from */
+    off_t off;		/* start offset of */
+    off_t len;		/* lengt of data to copy */
+    off_t remain;	/* bytes remaining to be copied */
+    int e[2];		/* error codes */
 };
 
 static int read_file(void *state, void *data, size_t len, enum zip_cmd cmd);
@@ -94,34 +101,74 @@
     buf = (char *)data;
 
     switch (cmd) {
-    case ZIP_CMD_INIT:
+    case ZIP_CMD_OPEN:
 	if (fseeko(z->f, z->off, SEEK_SET) < 0) {
-	    /* XXX: zip_err = ZERR_SEEK; */
+	    z->e[0] = ZERR_SEEK;
+	    z->e[1] = errno;
 	    return -1;
 	}
+	z->remain = z->len;
 	return 0;
 	
     case ZIP_CMD_READ:
-	if (z->len != -1)
-	    n = len > z->len ? z->len : len;
+	if (z->remain != -1)
+	    n = len > z->remain ? z->remain : len;
 	else
 	    n = len;
 	
 	if ((i=fread(buf, 1, n, z->f)) < 0) {
-	    /* XXX: zip_err = ZERR_READ; */
+	    z->e[0] = ZERR_READ;
+	    z->e[1] = errno;
 	    return -1;
 	}
 
-	if (z->len != -1)
-	    z->len -= i;
+	if (z->remain != -1)
+	    z->remain -= i;
 
 	return i;
 	
     case ZIP_CMD_CLOSE:
-	if (z->f) {
-	    fclose(z->f);
-	    z->f = NULL;
+	return 0;
+
+    case ZIP_CMD_STAT:
+        {
+	    struct zip_stat *st;
+	    struct stat fst;
+	    
+	    if (len < sizeof(*st))
+		return -1;
+
+	    st = (struct zip_stat *)data;
+
+	    if (fstat(fileno(z->f), &fst) != 0) {
+		z->e[0] = ZERR_READ; /* best match */
+		z->e[1] = errno;
+		return -1;
+	    }
+
+	    st->mtime = fst.st_mtime;
+	    st->crc = 0;
+	    if (z->len != -1)
+		st->size = z->len;
+	    else if ((fst.st_mode&S_IFMT) == S_IFREG)
+		st->size = fst.st_size;
+	    else
+		st->size = -1;
+	    st->comp_size = -1;
+	    st->comp_method = ZIP_CM_STORE;
+
+	    return sizeof(*st);
 	}
+
+    case ZIP_CMD_ERROR:
+	if (len < sizeof(int)*2)
+	    return -1;
+
+	memcpy(data, z->e, sizeof(int)*2);
+	return sizeof(int)*2;
+
+    case ZIP_CMD_FREE:
+	fclose(z->f);
 	free(z);
 	return 0;
 
diff --git a/lib/zip_replace_zip.c b/lib/zip_replace_zip.c
index 2098467..fa0ceec 100644
--- a/lib/zip_replace_zip.c
+++ b/lib/zip_replace_zip.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_replace_zip.c,v 1.20 2004/04/17 19:15:30 dillo Exp $
+  $NiH: zip_replace_zip.c,v 1.21 2004/05/16 00:50:48 dillo Exp $
 
   zip_replace_zip.c -- replace file from zip file
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -36,6 +36,8 @@
 
 
 #include <stdlib.h>
+#include <string.h>
+
 #include "zip.h"
 #include "zipint.h"
 
@@ -127,7 +129,7 @@
     buf = (char *)data;
 
     switch (cmd) {
-    case ZIP_CMD_INIT:
+    case ZIP_CMD_OPEN:
 	for (n=0; n<z->off; n+= i) {
 	    i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n);
 	    if ((i=zip_fread(z->zf, b, i)) < 0) {
@@ -156,15 +158,31 @@
 	return i;
 	
     case ZIP_CMD_CLOSE:
-	zip_fclose(z->zf);
-	free(z);
 	return 0;
 
     case ZIP_CMD_STAT:
 	if (len < sizeof(z->st))
 	    return -1;
+	len = sizeof(z->st);
 
-	memcpy(data, &z->st, sizeof(z->st));
+	memcpy(data, &z->st, len);
+	return len;
+
+    case ZIP_CMD_ERROR:
+	{
+	    int *e;
+
+	    if (len < sizeof(int)*2)
+		return -1;
+
+	    e = (int *)data;
+	    zip_file_get_error(z->zf, e, e+1);
+	}
+	return sizeof(int)*2;
+
+    case ZIP_CMD_FREE:
+	zip_fclose(z->zf);
+	free(z);
 	return 0;
 
     default:
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c
index ab88ae0..b6a7b1a 100644
--- a/lib/zip_unchange_data.c
+++ b/lib/zip_unchange_data.c
@@ -1,5 +1,5 @@
 /*
-  $NiH: zip_unchange_data.c,v 1.10 2004/04/14 14:01:28 dillo Exp $
+  $NiH: zip_unchange_data.c,v 1.11 2004/04/16 09:40:31 dillo Exp $
 
   zip_unchange_data.c -- undo helper function
   Copyright (C) 1999, 2004 Dieter Baron and Thomas Klausner
@@ -51,8 +51,6 @@
 	ze->ch_func = NULL;
     }
     
-    ze->ch_flags = 0;
-
     ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED;
 
     return ret;
diff --git a/lib/zipint.h b/lib/zipint.h
index 88a8f6a..3f60759 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -3,7 +3,7 @@
 #define _HAD_ZIPINT_H
 
 /*
-  $NiH: zipint.h,v 1.24 2004/04/16 09:40:31 dillo Exp $
+  $NiH: zipint.h,v 1.25 2004/04/19 11:49:13 dillo Exp $
 
   zipint.h -- internal declarations.
   Copyright (C) 1999, 2003, 2004 Dieter Baron and Thomas Klausner
@@ -146,9 +146,7 @@
     enum zip_state state;
     zip_read_func ch_func;
     void *ch_data;
-    int ch_flags;		/* 1: data returned by ch_func is compressed */
     char *ch_filename;
-    time_t ch_mtime;
 };