Checkpoint commit of stacked sources to implement encryption/compression.

Used for zip_fread.
Not yet used for writing (zip_close).
Traditional PKWARE encryption untested.

--HG--
branch : HEAD
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 6d13972..7ca0704 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -1,6 +1,6 @@
 /*
   zip_source_filep.c -- create data source from FILE *
-  Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
 
   This file is part of libzip, a library to manipulate ZIP archives.
   The authors can be contacted at <libzip@nih.at>
@@ -44,6 +44,9 @@
 struct read_file {
     char *fname;	/* name of file to copy from */
     FILE *f;		/* file to copy from */
+    int closep;		/* close f */
+    struct zip_stat st;	/* stat information passed in */
+
     zip_uint64_t off;	/* start offset of */
     zip_int64_t len;	/* length of data to copy */
     zip_int64_t remain;	/* bytes remaining to be copied */
@@ -67,14 +70,15 @@
 	return NULL;
     }
 
-    return _zip_source_file_or_p(za, NULL, file, start, len);
+    return _zip_source_file_or_p(za, NULL, file, start, len, 1, NULL);
 }
 
 
 
 struct zip_source *
 _zip_source_file_or_p(struct zip *za, const char *fname, FILE *file,
-		      zip_uint64_t start, zip_int64_t len)
+		      zip_uint64_t start, zip_int64_t len, int closep,
+		      const struct zip_stat *st)
 {
     struct read_file *f;
     struct zip_source *zs;
@@ -100,7 +104,12 @@
     f->f = file;
     f->off = start;
     f->len = (len ? len : -1);
-    
+    f->closep = f->fname ? 1 : closep;
+    if (st)
+	memcpy(&f->st, st, sizeof(f->st));
+    else
+	zip_stat_init(&f->st);
+
     if ((zs=zip_source_function(za, read_file, f)) == NULL) {
 	free(f);
 	return NULL;
@@ -131,10 +140,12 @@
 	    }
 	}
 
-	if (fseeko(z->f, (off_t)z->off, SEEK_SET) < 0) {
-	    z->e[0] = ZIP_ER_SEEK;
-	    z->e[1] = errno;
-	    return -1;
+	if (z->closep) {
+	    if (fseeko(z->f, (off_t)z->off, SEEK_SET) < 0) {
+		z->e[0] = ZIP_ER_SEEK;
+		z->e[1] = errno;
+		return -1;
+	    }
 	}
 	z->remain = z->len;
 	return 0;
@@ -144,7 +155,17 @@
 	    n = len > z->remain ? z->remain : len;
 	else
 	    n = len;
-	
+
+	if (!z->closep) {
+	    /* we might share this file with others, so let's be save */
+	    if (fseeko(z->f, (off_t)(z->off + z->len-z->remain),
+		       SEEK_SET) < 0) {
+		z->e[0] = ZIP_ER_SEEK;
+		z->e[1] = errno;
+		return -1;
+	    }
+	}
+
 	if ((i=fread(buf, 1, n, z->f)) < 0) {
 	    z->e[0] = ZIP_ER_READ;
 	    z->e[1] = errno;
@@ -172,26 +193,29 @@
 	    if (len < sizeof(*st))
 		return -1;
 
-	    if (z->f)
-		err = fstat(fileno(z->f), &fst);
-	    else
-		err = stat(z->fname, &fst);
+	    if (z->st.size != -1)
+		memcpy(st, &z->st, sizeof(st));
+	    else {
+		if (z->f)
+		    err = fstat(fileno(z->f), &fst);
+		else
+		    err = stat(z->fname, &fst);
 
-	    if (err != 0) {
-		z->e[0] = ZIP_ER_READ; /* best match */
-		z->e[1] = errno;
-		return -1;
+		if (err != 0) {
+		    z->e[0] = ZIP_ER_READ; /* best match */
+		    z->e[1] = errno;
+		    return -1;
+		}
+
+		st = (struct zip_stat *)data;
+		
+		zip_stat_init(st);
+		st->mtime = fst.st_mtime;
+		if (z->len != -1)
+		    st->size = z->len;
+		else if ((fst.st_mode&S_IFMT) == S_IFREG)
+		    st->size = fst.st_size;
 	    }
-
-	    st = (struct zip_stat *)data;
-
-	    zip_stat_init(st);
-	    st->mtime = fst.st_mtime;
-	    if (z->len != -1)
-		st->size = z->len;
-	    else if ((fst.st_mode&S_IFMT) == S_IFREG)
-		st->size = fst.st_size;
-
 	    return sizeof(*st);
 	}
 
@@ -204,7 +228,7 @@
 
     case ZIP_SOURCE_FREE:
 	free(z->fname);
-	if (z->f)
+	if (z->closep && z->f)
 	    fclose(z->f);
 	free(z);
 	return 0;