Decryption improvements:
- Implement zip_set_default_password().
- Fix ZIP_SOURCE_STAT in file source.
- Fix error returns for pkware decryption.

XXX: Actually decrypting still fails.

--HG--
branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 68dbaf8..e4baef8 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -52,6 +52,7 @@
 	zip_replace.c \
 	zip_set_archive_comment.c \
 	zip_set_archive_flag.c \
+	zip_set_default_password.c \
 	zip_set_file_comment.c \
 	zip_source_buffer.c \
 	zip_source_call.c \
diff --git a/lib/zip.h b/lib/zip.h
index 26350d9..4a764de 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -235,6 +235,7 @@
 ZIP_EXTERN int zip_replace(struct zip *, zip_uint64_t, struct zip_source *);
 ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int);
 ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int);
+ZIP_EXTERN int zip_set_default_password(struct zip *, const char *);
 ZIP_EXTERN int zip_set_file_comment(struct zip *, zip_uint64_t,
 				    const char *, int);
 ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *,
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c
index 4e01958..0abbcef 100644
--- a/lib/zip_fopen_index_encrypted.c
+++ b/lib/zip_fopen_index_encrypted.c
@@ -83,6 +83,10 @@
     enc_impl = NULL;
     if ((flags & ZIP_FL_ENCRYPTED) == 0) {
 	if (st.encryption_method != ZIP_EM_NONE) {
+	    if (password == NULL) {
+		_zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
+		return NULL;
+	    }
 	    if ((enc_impl=zip_get_encryption_implementation(
 		     st.encryption_method)) == NULL) {
 		_zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
@@ -117,6 +121,7 @@
 	    if ((s2=enc_impl(za, src, ZIP_EM_TRAD_PKWARE, 0,
 			     password)) == NULL) {
 		zip_source_free(src);
+		/* XXX: set error (how?) */
 		return NULL;
 	    }
 	    src = s2;
@@ -125,6 +130,7 @@
 	    if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method,
 			      0)) == NULL) {
 		zip_source_free(src);
+		/* XXX: set error (how?) */
 		return NULL;
 	    }
 	    src = s2;
@@ -132,6 +138,12 @@
     }
 
     if (zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) {
+	int e[2];
+	
+	if (zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0)
+	    _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
+	else
+	    _zip_error_set(&za->error, e[0], e[1]);
 	zip_source_free(src);
 	return NULL;
     }
diff --git a/lib/zip_set_default_password.c b/lib/zip_set_default_password.c
new file mode 100644
index 0000000..eb02c34
--- /dev/null
+++ b/lib/zip_set_default_password.c
@@ -0,0 +1,59 @@
+/*
+  zip_set_default_password.c -- set default password for decryption
+  Copyright (C) 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>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN int
+zip_set_default_password(struct zip *za, const char *passwd)
+{
+    if (za->default_password)
+	free(za->default_password);
+    
+    if (passwd) {
+	if ((za->default_password=strdup(passwd)) == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+	    return -1;
+	}
+    }
+    else
+	za->default_password = NULL;
+
+    return 0;
+}
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 7020dd6..a3ac7e3 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -187,16 +187,16 @@
 
     case ZIP_SOURCE_STAT:
         {
-	    struct zip_stat *st;
-	    struct stat fst;
-	    int err;
-	    
-	    if (len < sizeof(*st))
+	    if (len < sizeof(z->st))
 		return -1;
 
 	    if (z->st.size != -1)
-		memcpy(st, &z->st, sizeof(st));
+		memcpy(data, &z->st, sizeof(z->st));
 	    else {
+		struct zip_stat *st;
+		struct stat fst;
+		int err;
+	    
 		if (z->f)
 		    err = fstat(fileno(z->f), &fst);
 		else
@@ -217,7 +217,7 @@
 		else if ((fst.st_mode&S_IFMT) == S_IFREG)
 		    st->size = fst.st_size;
 	    }
-	    return sizeof(*st);
+	    return sizeof(z->st);
 	}
 
     case ZIP_SOURCE_ERROR:
diff --git a/lib/zip_source_pkware.c b/lib/zip_source_pkware.c
index 8b1c749..26e1160 100644
--- a/lib/zip_source_pkware.c
+++ b/lib/zip_source_pkware.c
@@ -53,7 +53,7 @@
 
 
 static void decrypt(struct trad_pkware *, zip_uint8_t *,
-		    const zip_uint8_t *, zip_uint64_t);
+		    const zip_uint8_t *, zip_uint64_t, int);
 static int decrypt_header(struct trad_pkware *);
 static zip_int64_t pkware_decrypt(void *, void *, zip_uint64_t, enum zip_source_cmd);
 
@@ -66,7 +66,7 @@
     struct trad_pkware *ctx;
 
     if (za == NULL || password == NULL || src == NULL
-	|| em != ZIP_EM_TRAD_PKWARE || (flags & ZIP_CODEC_ENCODE) == 0) {
+	|| em != ZIP_EM_TRAD_PKWARE || (flags & ZIP_CODEC_ENCODE)) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return NULL;
     }
@@ -82,7 +82,7 @@
     ctx->key[0] = KEY0;
     ctx->key[1] = KEY1;
     ctx->key[2] = KEY2;
-    decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password));
+    decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password), 1);
 
     return zip_source_function(za, pkware_decrypt, ctx);
 }
@@ -91,20 +91,23 @@
 
 static void
 decrypt(struct trad_pkware *ctx, zip_uint8_t *out, const zip_uint8_t *in,
-	zip_uint64_t len)
+	zip_uint64_t len, int update_only)
 {
-    zip_uint16_t clr;
+    zip_uint16_t tmp;
     zip_uint64_t i;
     Bytef b;
 
     for (i=0; i<len; i++) {
-	/* decrypt next byte */
-	clr = ctx->key[2] || 2;
-	clr = (clr * (clr ^ 1)) >> 8;
-	clr = in[i] ^ clr;
+	b = in[i];
+
+	if (!update_only) {
+	    /* decrypt next byte */
+	    tmp = ctx->key[2] || 2;
+	    tmp = (tmp * (tmp ^ 1)) >> 8;
+	    b ^= tmp;
+	}
 
 	/* update keys */
-	b = clr;
 	ctx->key[0] = crc32(ctx->key[0], &b, 1);
 	ctx->key[1] = (ctx->key[1] + (ctx->key[0] & 0xff)) * 134775813 + 1;
 	b = ctx->key[1] >> 24;
@@ -112,7 +115,7 @@
 
 	/* store cleartext */
 	if (out)
-	    out[i] = clr;
+	    out[i] = b;
     }
 }
 
@@ -136,7 +139,7 @@
 	return -1;
     }
 
-    decrypt(ctx, header, header, HEADERLEN);
+    decrypt(ctx, header, header, HEADERLEN, 0);
 
     if (zip_source_call(ctx->src, &st, sizeof(st), ZIP_SOURCE_STAT) < 0
 	|| st.crc == 0) {
@@ -147,6 +150,7 @@
     if (header[HEADERLEN-1] != st.crc>>24) {
 	ctx->e[0] = ZIP_ER_WRONGPASSWD;
 	ctx->e[1] = 0;
+	return -1;
     }
 
     return 0;
@@ -177,7 +181,8 @@
 	    zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR);
 	    return -1;
 	}
-	decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);
+	decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n,
+		0);
 	return n;
 
     case ZIP_SOURCE_CLOSE: