upgrade jzlib to 1.1.1

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4990 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index f321594..86b9627 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -7,7 +7,7 @@
 
 find_package(Java)
 
-set(DEFAULT_JAVACFLAGS "-source 1.5 -target 1.5 -Xlint:all,-serial,-cast,-unchecked,-fallthrough,-dep-ann")
+set(DEFAULT_JAVACFLAGS "-source 1.5 -target 1.5 -Xlint:all,-serial,-cast,-unchecked,-fallthrough,-dep-ann,-deprecation")
 set(JAVACFLAGS ${DEFAULT_JAVACFLAGS} CACHE STRING
   "Java compiler flags (Default: ${DEFAULT_JAVACFLAGS})")
 message(STATUS "Java compiler flags = ${JAVACFLAGS}")
diff --git a/java/com/jcraft/jzlib/Adler32.java b/java/com/jcraft/jzlib/Adler32.java
index d8b6ef8..a789a5a 100644
--- a/java/com/jcraft/jzlib/Adler32.java
+++ b/java/com/jcraft/jzlib/Adler32.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -34,61 +34,106 @@
 
 package com.jcraft.jzlib;
 
-final class Adler32{
+final public class Adler32 implements Checksum {
 
   // largest prime smaller than 65536
   static final private int BASE=65521; 
   // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
   static final private int NMAX=5552;
 
-  long adler32(long adler, byte[] buf, int index, int len){
-    if(buf == null){ return 1L; }
+  private long s1=1L;
+  private long s2=0L;
 
-    long s1=adler&0xffff;
-    long s2=(adler>>16)&0xffff;
-    int k;
+  public void reset(long init){
+    s1=init&0xffff;
+    s2=(init>>16)&0xffff;
+  }
 
-    while(len > 0) {
-      k=len<NMAX?len:NMAX;
+  public void reset(){
+    s1=1L;
+    s2=0L;
+  }
+
+  public long getValue(){
+    return ((s2<<16)|s1);
+  }
+
+  public void update(byte[] buf, int index, int len){
+
+    if(len==1){
+      s1+=buf[index++]&0xff; s2+=s1;
+      s1%=BASE;
+      s2%=BASE;
+      return;
+    }
+
+    int len1 = len/NMAX;
+    int len2 = len%NMAX;
+    while(len1-->0) {
+      int k=NMAX;
       len-=k;
-      while(k>=16){
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        s1+=buf[index++]&0xff; s2+=s1;
-        k-=16;
-      }
-      if(k!=0){
-        do{
-          s1+=buf[index++]&0xff; s2+=s1;
-        }
-        while(--k!=0);
+      while(k-->0){
+	s1+=buf[index++]&0xff; s2+=s1;
       }
       s1%=BASE;
       s2%=BASE;
     }
-    return (s2<<16)|s1;
+
+    int k=len2;
+    len-=k;
+    while(k-->0){
+      s1+=buf[index++]&0xff; s2+=s1;
+    }
+    s1%=BASE;
+    s2%=BASE;
   }
 
-  /*
+  public Adler32 copy(){
+    Adler32 foo = new Adler32();
+    foo.s1 = this.s1;
+    foo.s2 = this.s2;
+    return foo;
+  }
+
+  // The following logic has come from zlib.1.2.
+  static long combine(long adler1, long adler2, long len2){
+    long BASEL = (long)BASE;
+    long sum1;
+    long sum2;
+    long rem;  // unsigned int
+
+    rem = len2 % BASEL;
+    sum1 = adler1 & 0xffffL;
+    sum2 = rem * sum1;
+    sum2 %= BASEL; // MOD(sum2);
+    sum1 += (adler2 & 0xffffL) + BASEL - 1;
+    sum2 += ((adler1 >> 16) & 0xffffL) + ((adler2 >> 16) & 0xffffL) + BASEL - rem;
+    if (sum1 >= BASEL) sum1 -= BASEL;
+    if (sum1 >= BASEL) sum1 -= BASEL;
+    if (sum2 >= (BASEL << 1)) sum2 -= (BASEL << 1);
+    if (sum2 >= BASEL) sum2 -= BASEL;
+    return sum1 | (sum2 << 16);
+  }
+
+/*
   private java.util.zip.Adler32 adler=new java.util.zip.Adler32();
-  long adler32(long value, byte[] buf, int index, int len){
-    if(value==1) {adler.reset();}
+  public void update(byte[] buf, int index, int len){
     if(buf==null) {adler.reset();}
     else{adler.update(buf, index, len);}
+  }
+  public void reset(){
+    adler.reset();
+  }
+  public void reset(long init){
+    if(init==1L){
+      adler.reset();
+    }
+    else{
+      System.err.println("unsupported operation");
+    }
+  }
+  public long getValue(){
     return adler.getValue();
   }
-  */
+*/
 }
diff --git a/java/com/jcraft/jzlib/CRC32.java b/java/com/jcraft/jzlib/CRC32.java
new file mode 100644
index 0000000..3045796
--- /dev/null
+++ b/java/com/jcraft/jzlib/CRC32.java
@@ -0,0 +1,179 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+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 ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final public class CRC32 implements Checksum {
+
+  /*
+   *  The following logic has come from RFC1952.
+   */
+  private int v = 0;
+  private static int[] crc_table = null;
+  static {
+    crc_table = new int[256];
+    for (int n = 0; n < 256; n++) {
+      int c = n;
+      for (int k = 8;  --k >= 0; ) {
+        if ((c & 1) != 0)
+	  c = 0xedb88320 ^ (c >>> 1);
+        else
+          c = c >>> 1;
+      }
+      crc_table[n] = c;
+    }
+  }
+
+  public void update (byte[] buf, int index, int len) {
+    int c = ~v;
+    while (--len >= 0)
+      c = crc_table[(c^buf[index++])&0xff]^(c >>> 8);
+    v = ~c;
+  }
+
+  public void reset(){
+    v = 0;
+  }
+
+  public void reset(long vv){
+    v = (int)(vv&0xffffffffL);
+  }
+
+  public long getValue(){
+    return (long)(v&0xffffffffL);
+  }
+
+  // The following logic has come from zlib.1.2.
+  private static final int GF2_DIM = 32;
+  static long combine(long crc1, long crc2, long len2){
+    long row;
+    long[] even = new long[GF2_DIM];
+    long[] odd = new long[GF2_DIM];
+
+    // degenerate case (also disallow negative lengths)
+    if (len2 <= 0)
+      return crc1;
+
+    // put operator for one zero bit in odd
+    odd[0] = 0xedb88320L;          // CRC-32 polynomial
+    row = 1;
+    for (int n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    // put operator for two zero bits in even
+    gf2_matrix_square(even, odd);
+
+    // put operator for four zero bits in odd
+    gf2_matrix_square(odd, even);
+
+    // apply len2 zeros to crc1 (first square will put the operator for one
+    // zero byte, eight zero bits, in even)
+    do {
+      // apply zeros operator for this bit of len2
+      gf2_matrix_square(even, odd);
+      if ((len2 & 1)!=0)
+        crc1 = gf2_matrix_times(even, crc1);
+      len2 >>= 1;
+
+      // if no more bits set, then done
+      if (len2 == 0)
+        break;
+
+      // another iteration of the loop with odd and even swapped
+      gf2_matrix_square(odd, even);
+      if ((len2 & 1)!=0)
+        crc1 = gf2_matrix_times(odd, crc1);
+      len2 >>= 1;
+
+      // if no more bits set, then done
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+  }
+
+  private static long gf2_matrix_times(long[] mat, long vec){
+    long sum = 0;
+    int index = 0;
+    while (vec!=0) {
+      if ((vec & 1)!=0)
+        sum ^= mat[index];
+      vec >>= 1;
+      index++;
+    }
+    return sum;
+  }
+
+  static final void gf2_matrix_square(long[] square, long[] mat) {
+    for (int n = 0; n < GF2_DIM; n++)
+      square[n] = gf2_matrix_times(mat, mat[n]);
+  }
+
+  /*
+  private java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
+
+  public void update(byte[] buf, int index, int len){
+    if(buf==null) {crc32.reset();}
+    else{crc32.update(buf, index, len);}
+  }
+  public void reset(){
+    crc32.reset();
+  }
+  public void reset(long init){
+    if(init==0L){
+      crc32.reset();
+    }
+    else{
+      System.err.println("unsupported operation");
+    }
+  }
+  public long getValue(){
+    return crc32.getValue();
+  }
+*/
+  public CRC32 copy(){
+    CRC32 foo = new CRC32();
+    foo.v = this.v;
+    return foo;
+  }
+
+  public static int[] getCRC32Table(){
+    int[] tmp = new int[crc_table.length];
+    System.arraycopy(crc_table, 0, tmp, 0, tmp.length);
+    return tmp;
+  }
+}
diff --git a/java/com/jcraft/jzlib/ChangeLog b/java/com/jcraft/jzlib/ChangeLog
index c828fae..d963cff 100644
--- a/java/com/jcraft/jzlib/ChangeLog
+++ b/java/com/jcraft/jzlib/ChangeLog
@@ -1,17 +1,54 @@
 ChangeLog of JZlib
 ====================================================================
-Last modified: Thu Aug 18 16:16:06 UTC 2005
+Last modified: Mon Feb 20 06:06:07 UTC 2012
 
-	
-Changes since version 1.0.6:	
-- change: memory and performance optimizations in the inflate operation.
-  Many thanks to Paul Wakefield at platx.org(http://www.platx.org), who 
-  suggested above improvements.
+
+Changes since version 1.1.0:
+- fixed a bug in DeflaterOutputStream#write() with empty data.  9d4616f
+- fixed a bug in processing unwrapped data with InfalterInputStream. d35db2
+- fixed bugs reported in https://github.com/ymnk/jzlib/pull/5 e4aa20
+  - comments and filename in GZIPHeader must be in ISO-8859-1 encoding
+  - fixing a bug in GZIPHeader#setOS(int os)
+- some refactoring code. e912088 6900f5 614fdf
+- improving the performace of Adler32#update method.  6900f5
+- constructors of Alder32 and CRC32 become public. 30c4cf
+- added ZStream#end() and ZStream#finished().  6b55e3
+- exposed useful constants for jruby.  e17ad1
+- updated pom.xml to delete "souceDirectory"
+  No need to specify sourceDirectory if the project follows maven
+  standard.
+- updated configurations to use sbt 0.11.1
+
+
+Changes since version 1.0.7:
+- supported some new functionalities, which have been introduced since 'zlib' 1.2.
+  - JZlib#{adler32,crc32}_combine,
+  - JZlib can handle gzip file format(RFC1952).
+- added following classes,
+  - DeflaterOutputStream
+  - InflaterInputStream
+  - GZIPOutputStream
+  - GZIPInputStream
+  - Inflater
+  - Deflater
+  - ZStream has been deprecated.
+    Use Inflater and Deflater instead of it.
+  - GZIPHeader
+- re-implemented Z{Input,Output}Stream with {Deflater,Inflater}{I/O}Stream
+  - those classes have been deprecated.
+    Use DeflaterOutputStream and InfaterInputStream instead of them.
+- com/ -> src/main/java/com/
+- some tests under src/test/scala/
+- pom.xml for mvn, and projects/ for sbt.
+
+
+Changes since version 1.0.6:
+- change: memory and performance optimisations in the inflate operation.
 - change: added the nowrap argument to Z{Input,Output}?Stream.
 
-	
+
 Changes since version 1.0.5:
-- ZInputStream.read(byte[], int, int) method return sometimes zero 
+- ZInputStream.read(byte[], int, int) method return sometimes zero
   instead of -1 at the end of stream.
 - ZOutputStream.end() method should not declare IOException.
 - It should be possible to call ZOutputStream.end() method more times 
@@ -20,64 +57,64 @@
 - ZOutputStream.finish() method should not ignore IOException from flush().
 Many thanks to Matej Kraus at seznam.cz , who pointed out above problems.
 
-	
+
 Changes since version 1.0.4:
 - a minor bug fix in ZInputStream
 
-	
+
 Changes since version 1.0.3:
 - fixed a bug in closing ZOutputStream.
   The inflating and deflating processes were not finished successfully.
 - added 'finish' and 'end' methods to ZOutputStream.java
 - added 'example/test_stream_deflate_inflate.java'
 
-	
+
 Changes since version 1.0.2:
 - enabled pure Java implementation of adler32 and
   commented out the dependency on J2SE in Adler32.java for J2ME users.
 
-	
+
 Changes since version 1.0.1:
 - fixed a bug in deflating some trivial data, for example,
-  large data chunk filled with zero.	
+  large data chunk filled with zero.
 - added 'version' method to JZlib class.
 
-	
+
 Changes since version 1.0.0:
 - added ZInputStream and ZOutputStream classes.
 - fixed a typo in LICENSE.txt.
 
-	
+
 Changes since version 0.0.9:
 - fixed a bug in setting a dictionary in the inflation process.
 - The license was changed to a BSD style license.
 - Z{Input,Output}Stream classes were deleted.
-	
-	
+
+
 Changes since version 0.0.8:
 - fixed a bug in handling a preset dictionary in the inflation process.
 
-	
+
 Changes since version 0.0.7:
 - added methods to control the window size (the size of the history
   buffer) and to handle the no-wrap option (no zlib header or check),
   which is the undocumented functionality of zlib.
 
-	
+
 Changes since version 0.0.6:
 - updated InfBlocks.java as zlib did to fix the vulnerability related to
   the 'double free'. Of course, JZlib is free from such a vulnerability
   like the 'double free', but JZlib had crashed with NullPointerException
-  by a specially-crafted block of invalid deflated data.	
+  by a specially-crafted block of invalid deflated data.
 
-	
+
 Changes since version 0.0.5:
 - added 'flush()' method to com.jcraft.jzlib.ZOutputStream.
-- fixed to take care when occurring the buffer overflow in 
+- fixed to take care when occurring the buffer overflow in
   com.jcraft.jzlib.ZOutputStream.
 Many thanks to Tim Bendfelt at cs.wisc.edu , who pointed out above problems.
-	
-	
+
+
 Changes since version 0.0.4:
 ............................
 - fixed a bug in Adler32 class.
@@ -87,11 +124,11 @@
 - modified ZOutputStream to be extended from OutputStream
   instead of FileOutputStream.
 - modified ZStream to be changeable wbits. Give wbits value to
-  the method 'deflateInit' of ZStream.	 
+  the method 'deflateInit' of ZStream.
 Many thanks to Bryan Keller<keller@neomar.com>, who reported bugs
 and made suggestions.
 
-	
+
 Changes since version 0.0.3:
 ............................
 - fixed a bug in the compression level 0.
diff --git a/java/com/jcraft/jzlib/Checksum.java b/java/com/jcraft/jzlib/Checksum.java
new file mode 100644
index 0000000..1139093
--- /dev/null
+++ b/java/com/jcraft/jzlib/Checksum.java
@@ -0,0 +1,43 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+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 ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+interface Checksum {
+  void update(byte[] buf, int index, int len);
+  void reset();
+  void reset(long init);
+  long getValue();
+  Checksum copy();
+}
diff --git a/java/com/jcraft/jzlib/Deflate.java b/java/com/jcraft/jzlib/Deflate.java
index 9978802..baaac9b 100644
--- a/java/com/jcraft/jzlib/Deflate.java
+++ b/java/com/jcraft/jzlib/Deflate.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
 package com.jcraft.jzlib;
 
 public 
-final class Deflate{
+final class Deflate implements Cloneable {
 
   static final private int MAX_MEM_LEVEL=9;
 
@@ -169,13 +169,13 @@
 
   static final private int END_BLOCK=256;
 
-  ZStream strm;         // pointer back to this zlib stream
+  ZStream strm;        // pointer back to this zlib stream
   int status;           // as the name implies
   byte[] pending_buf;   // output still pending
   int pending_buf_size; // size of pending_buf
   int pending_out;      // next pending byte to output to the stream
   int pending;          // nb of bytes in the pending buffer
-  int noheader;         // suppress zlib header and adler32
+  int wrap = 1;
   byte data_type;       // UNKNOWN, BINARY or ASCII
   byte method;          // STORED (for zip only) or DEFLATED
   int last_flush;       // value of flush param for previous deflate call
@@ -317,7 +317,10 @@
   // are always zero.
   int bi_valid;
 
-  Deflate(){
+  GZIPHeader gheader = null;
+
+  Deflate(ZStream strm){
+    this.strm=strm;
     dyn_ltree=new short[HEAP_SIZE*2];
     dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
     bl_tree=new short[(2*BL_CODES+1)*2];  // Huffman tree for bit lengths
@@ -1311,17 +1314,22 @@
     if (best_len <= lookahead) return best_len;
     return lookahead;
   }
-    
-  int deflateInit(ZStream strm, int level, int bits){
-    return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+
+  int deflateInit(int level, int bits, int memlevel){
+    return deflateInit(level, Z_DEFLATED, bits, memlevel,
 			Z_DEFAULT_STRATEGY);
   }
-  int deflateInit(ZStream strm, int level){
-    return deflateInit(strm, level, MAX_WBITS);
+    
+  int deflateInit(int level, int bits){
+    return deflateInit(level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+			Z_DEFAULT_STRATEGY);
   }
-  int deflateInit2(ZStream strm, int level, int method,  int windowBits,
-		   int memLevel, int strategy){
-    int noheader = 0;
+  int deflateInit(int level){
+    return deflateInit(level, MAX_WBITS);
+  }
+  private int deflateInit(int level, int method,  int windowBits,
+			  int memLevel, int strategy){
+    int wrap = 1;
     //    byte[] my_version=ZLIB_VERSION;
 
     //
@@ -1335,9 +1343,14 @@
     if (level == Z_DEFAULT_COMPRESSION) level = 6;
 
     if (windowBits < 0) { // undocumented feature: suppress zlib header
-      noheader = 1;
+      wrap = 0;
       windowBits = -windowBits;
     }
+    else if(windowBits > 15){
+      wrap = 2;
+      windowBits -= 16;
+      strm.adler=new CRC32();
+    }
 
     if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || 
 	method != Z_DEFLATED ||
@@ -1348,7 +1361,7 @@
 
     strm.dstate = (Deflate)this;
 
-    this.noheader = noheader;
+    this.wrap = wrap;
     w_bits = windowBits;
     w_size = 1 << w_bits;
     w_mask = w_size - 1;
@@ -1374,15 +1387,13 @@
 
     this.level = level;
 
-//System.out.println("level="+level);
-
     this.strategy = strategy;
     this.method = (byte)method;
 
-    return deflateReset(strm);
+    return deflateReset();
   }
 
-  int deflateReset(ZStream strm){
+  int deflateReset(){
     strm.total_in = strm.total_out = 0;
     strm.msg = null; //
     strm.data_type = Z_UNKNOWN;
@@ -1390,11 +1401,11 @@
     pending = 0;
     pending_out = 0;
 
-    if(noheader < 0) {
-      noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
+    if(wrap < 0){
+      wrap = -wrap;
     }
-    status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
-    strm.adler=strm._adler.adler32(0, null, 0, 0);
+    status = (wrap==0) ? BUSY_STATE : INIT_STATE;
+    strm.adler.reset();
 
     last_flush = Z_NO_FLUSH;
 
@@ -1417,7 +1428,7 @@
     return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
   }
 
-  int deflateParams(ZStream strm, int _level, int _strategy){
+  int deflateParams(int _level, int _strategy){
     int err=Z_OK;
 
     if(_level == Z_DEFAULT_COMPRESSION){
@@ -1445,14 +1456,14 @@
     return err;
   }
 
-  int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
+  int deflateSetDictionary (byte[] dictionary, int dictLength){
     int length = dictLength;
     int index=0;
 
     if(dictionary == null || status != INIT_STATE)
       return Z_STREAM_ERROR;
 
-    strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
+    strm.adler.update(dictionary, 0, dictLength);
 
     if(length < MIN_MATCH) return Z_OK;
     if(length > w_size-MIN_LOOKAHEAD){
@@ -1478,7 +1489,7 @@
     return Z_OK;
   }
 
-  int deflate(ZStream strm, int flush){
+  int deflate(int flush){
     int old_flush;
 
     if(flush>Z_FINISH || flush<0){
@@ -1496,12 +1507,17 @@
       return Z_BUF_ERROR;
     }
 
-    this.strm = strm; // just in case
     old_flush = last_flush;
     last_flush = flush;
 
     // Write the zlib header
     if(status == INIT_STATE) {
+      if(wrap == 2){
+        getGZIPHeader().put(this);
+        status=BUSY_STATE;
+        strm.adler.reset();
+      }
+      else{
       int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
       int level_flags=((level-1)&0xff)>>1;
 
@@ -1516,17 +1532,18 @@
 
       // Save the adler32 of the preset dictionary:
       if(strstart!=0){
-        putShortMSB((int)(strm.adler>>>16));
-        putShortMSB((int)(strm.adler&0xffff));
+        long adler=strm.adler.getValue();
+        putShortMSB((int)(adler>>>16));
+        putShortMSB((int)(adler&0xffff));
       }
-      strm.adler=strm._adler.adler32(0, null, 0, 0);
+      strm.adler.reset();
+      }
     }
 
     // Flush as much pending output as possible
     if(pending != 0) {
       strm.flush_pending();
       if(strm.avail_out == 0) {
-	//System.out.println("  avail_out==0");
 	// Since avail_out is 0, deflate will be called again with
 	// more output space, but possibly with both pending and
 	// avail_in equal to zero. There won't be anything to do,
@@ -1608,16 +1625,127 @@
     }
 
     if(flush!=Z_FINISH) return Z_OK;
-    if(noheader!=0) return Z_STREAM_END;
+    if(wrap<=0) return Z_STREAM_END;
 
-    // Write the zlib trailer (adler32)
-    putShortMSB((int)(strm.adler>>>16));
-    putShortMSB((int)(strm.adler&0xffff));
+    if(wrap==2){
+      long adler=strm.adler.getValue();
+      put_byte((byte)(adler&0xff));
+      put_byte((byte)((adler>>8)&0xff));
+      put_byte((byte)((adler>>16)&0xff));
+      put_byte((byte)((adler>>24)&0xff));
+      put_byte((byte)(strm.total_in&0xff));
+      put_byte((byte)((strm.total_in>>8)&0xff));
+      put_byte((byte)((strm.total_in>>16)&0xff));
+      put_byte((byte)((strm.total_in>>24)&0xff));
+
+      getGZIPHeader().setCRC(adler);
+    } 
+    else{
+      // Write the zlib trailer (adler32)
+      long adler=strm.adler.getValue();
+      putShortMSB((int)(adler>>>16));
+      putShortMSB((int)(adler&0xffff));
+    }
+
     strm.flush_pending();
 
     // If avail_out is zero, the application will call deflate again
     // to flush the rest.
-    noheader = -1; // write the trailer only once!
+
+    if(wrap > 0) wrap = -wrap; // write the trailer only once!
     return pending != 0 ? Z_OK : Z_STREAM_END;
   }
+
+  static int deflateCopy(ZStream dest, ZStream src){
+
+    if(src.dstate == null){
+      return Z_STREAM_ERROR;
+    }
+
+    if(src.next_in!=null){
+      dest.next_in = new byte[src.next_in.length];
+      System.arraycopy(src.next_in, 0, dest.next_in, 0, src.next_in.length);
+    }
+    dest.next_in_index = src.next_in_index;
+    dest.avail_in = src.avail_in;
+    dest.total_in = src.total_in;
+
+    if(src.next_out!=null){
+      dest.next_out = new byte[src.next_out.length];
+      System.arraycopy(src.next_out, 0, dest.next_out ,0 , src.next_out.length);
+    }
+
+    dest.next_out_index = src.next_out_index;
+    dest.avail_out = src.avail_out;
+    dest.total_out = src.total_out;
+
+    dest.msg = src.msg;
+    dest.data_type = src.data_type;
+    dest.adler = src.adler.copy();
+
+    try{
+      dest.dstate = (Deflate)src.dstate.clone();
+      dest.dstate.strm = dest;
+    }
+    catch(CloneNotSupportedException e){
+      //
+    }
+    return Z_OK;
+  }
+
+  public Object clone() throws CloneNotSupportedException {
+    Deflate dest = (Deflate)super.clone();
+
+    dest.pending_buf = dup(dest.pending_buf);
+    dest.window = dup(dest.window);
+
+    dest.prev = dup(dest.prev);
+    dest.head = dup(dest.head);
+    dest.dyn_ltree = dup(dest.dyn_ltree);
+    dest.dyn_dtree = dup(dest.dyn_dtree);
+    dest.bl_tree = dup(dest.bl_tree);
+
+    dest.bl_count = dup(dest.bl_count);
+    dest.heap = dup(dest.heap);
+    dest.depth = dup(dest.depth);
+
+    dest.l_desc.dyn_tree = dest.dyn_ltree;
+    dest.d_desc.dyn_tree = dest.dyn_dtree;
+    dest.bl_desc.dyn_tree = dest.bl_tree;
+
+    /*
+    dest.l_desc.stat_desc = StaticTree.static_l_desc;
+    dest.d_desc.stat_desc = StaticTree.static_d_desc;
+    dest.bl_desc.stat_desc = StaticTree.static_bl_desc;
+    */
+
+    if(dest.gheader!=null){
+      dest.gheader = (GZIPHeader)dest.gheader.clone();
+    }
+
+    return dest;
+  }
+
+  private byte[] dup(byte[] buf){
+    byte[] foo = new byte[buf.length];
+    System.arraycopy(buf, 0, foo, 0, foo.length);
+    return foo;
+  }
+  private short[] dup(short[] buf){
+    short[] foo = new short[buf.length];
+    System.arraycopy(buf, 0, foo, 0, foo.length);
+    return foo;
+  }
+  private int[] dup(int[] buf){
+    int[] foo = new int[buf.length];
+    System.arraycopy(buf, 0, foo, 0, foo.length);
+    return foo;
+  }
+
+  synchronized GZIPHeader getGZIPHeader(){
+    if(gheader==null){
+      gheader = new GZIPHeader();
+    }
+    return gheader;
+  }
 }
diff --git a/java/com/jcraft/jzlib/GZIPHeader.java b/java/com/jcraft/jzlib/GZIPHeader.java
new file mode 100644
index 0000000..0405e00
--- /dev/null
+++ b/java/com/jcraft/jzlib/GZIPHeader.java
@@ -0,0 +1,214 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+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 ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @see "http://www.ietf.org/rfc/rfc1952.txt"
+ */
+public class GZIPHeader implements Cloneable {
+
+  public static final byte OS_MSDOS = (byte) 0x00;
+  public static final byte OS_AMIGA = (byte) 0x01;
+  public static final byte OS_VMS = (byte) 0x02;
+  public static final byte OS_UNIX = (byte) 0x03;
+  public static final byte OS_ATARI = (byte) 0x05;
+  public static final byte OS_OS2 = (byte) 0x06;
+  public static final byte OS_MACOS = (byte) 0x07;
+  public static final byte OS_TOPS20 = (byte) 0x0a;
+  public static final byte OS_WIN32 = (byte) 0x0b;
+  public static final byte OS_VMCMS = (byte) 0x04;
+  public static final byte OS_ZSYSTEM = (byte) 0x08;
+  public static final byte OS_CPM = (byte) 0x09;
+  public static final byte OS_QDOS = (byte) 0x0c;
+  public static final byte OS_RISCOS = (byte) 0x0d;
+  public static final byte OS_UNKNOWN = (byte) 0xff;
+
+  boolean text = false;
+  private boolean fhcrc = false;
+  long time;
+  int xflags;
+  int os = 255;
+  byte[] extra;
+  byte[] name;
+  byte[] comment;
+  int hcrc;
+  long crc;
+  boolean done = false;
+  long mtime = 0;
+
+  public void setModifiedTime(long mtime) {
+    this.mtime = mtime;
+  }
+
+  public long getModifiedTime() {
+    return mtime;
+  }
+
+  public void setOS(int os) {
+    if((0<=os && os <=13) || os==255)
+      this.os=os;
+    else
+      throw new IllegalArgumentException("os: "+os);
+  }
+
+  public int getOS(){
+    return os;
+  }
+
+  public void setName(String name) {
+    try{
+      this.name=name.getBytes("ISO-8859-1");
+    }
+    catch(UnsupportedEncodingException e){
+      throw new IllegalArgumentException("name must be in ISO-8859-1 "+name);
+    }
+  }
+
+  public String getName(){
+    if(name==null) return "";
+    try {
+      return new String(name, "ISO-8859-1");
+    }
+    catch (UnsupportedEncodingException e) {
+      throw new InternalError(e.toString());
+    }
+  }
+
+  public void setComment(String comment) {
+    try{
+      this.comment=comment.getBytes("ISO-8859-1");
+    }
+    catch(UnsupportedEncodingException e){
+      throw new IllegalArgumentException("comment must be in ISO-8859-1 "+name);
+    }
+  }
+
+  public String getComment(){
+    if(comment==null) return "";
+    try {
+      return new String(comment, "ISO-8859-1");
+    }
+    catch (UnsupportedEncodingException e) {
+      throw new InternalError(e.toString());
+    }
+  }
+
+  public void setCRC(long crc){
+    this.crc = crc;
+  }
+
+  public long getCRC(){
+    return crc;
+  }
+
+  void put(Deflate d){
+    int flag = 0;
+    if(text){
+      flag |= 1;     // FTEXT
+    }
+    if(fhcrc){
+      flag |= 2;     // FHCRC
+    }
+    if(extra!=null){
+      flag |= 4;     // FEXTRA
+    }
+    if(name!=null){
+      flag |= 8;    // FNAME
+    }
+    if(comment!=null){
+      flag |= 16;   // FCOMMENT
+    }
+    int xfl = 0;
+    if(d.level == JZlib.Z_BEST_SPEED){
+      xfl |= 4;
+    }
+    else if (d.level == JZlib.Z_BEST_COMPRESSION){
+      xfl |= 2;
+    }
+
+    d.put_short((short)0x8b1f);  // ID1 ID2
+    d.put_byte((byte)8);         // CM(Compression Method)
+    d.put_byte((byte)flag);
+    d.put_byte((byte)mtime);
+    d.put_byte((byte)(mtime>>8));
+    d.put_byte((byte)(mtime>>16));
+    d.put_byte((byte)(mtime>>24));
+    d.put_byte((byte)xfl);
+    d.put_byte((byte)os);
+
+    if(extra!=null){
+      d.put_byte((byte)extra.length);
+      d.put_byte((byte)(extra.length>>8));
+      d.put_byte(extra, 0, extra.length);
+    }
+
+    if(name!=null){
+      d.put_byte(name, 0, name.length);
+      d.put_byte((byte)0);
+    }
+
+    if(comment!=null){
+      d.put_byte(comment, 0, comment.length);
+      d.put_byte((byte)0);
+    }
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    GZIPHeader gheader = (GZIPHeader)super.clone();
+    byte[] tmp;
+    if(gheader.extra!=null){
+      tmp=new byte[gheader.extra.length];
+      System.arraycopy(gheader.extra, 0, tmp, 0, tmp.length);
+      gheader.extra = tmp;
+    }
+
+    if(gheader.name!=null){
+      tmp=new byte[gheader.name.length];
+      System.arraycopy(gheader.name, 0, tmp, 0, tmp.length);
+      gheader.name = tmp;
+    }
+
+    if(gheader.comment!=null){
+      tmp=new byte[gheader.comment.length];
+      System.arraycopy(gheader.comment, 0, tmp, 0, tmp.length);
+      gheader.comment = tmp;
+    }
+
+    return gheader;
+  }
+}
diff --git a/java/com/jcraft/jzlib/InfBlocks.java b/java/com/jcraft/jzlib/InfBlocks.java
index f6997fc..6793c60 100644
--- a/java/com/jcraft/jzlib/InfBlocks.java
+++ b/java/com/jcraft/jzlib/InfBlocks.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -81,7 +81,15 @@
   int[] bb=new int[1]; // bit length tree depth 
   int[] tb=new int[1]; // bit length decoding tree 
 
-  InfCodes codes=new InfCodes();      // if CODES, current state 
+  int[] bl=new int[1];
+  int[] bd=new int[1];
+
+  int[][] tl=new int[1][];
+  int[][] td=new int[1][];
+  int[] tli=new int[1]; // tl_index
+  int[] tdi=new int[1]; // td_index
+
+  private final InfCodes codes;      // if CODES, current state 
 
   int last;            // true if this block is the last block 
 
@@ -93,22 +101,24 @@
   int end;             // one byte after sliding window 
   int read;            // window read pointer 
   int write;           // window write pointer 
-  Object checkfn;      // check function 
-  long check;          // check on output 
+  private boolean check;
 
-  InfTree inftree=new InfTree();
+  private final InfTree inftree=new InfTree();
 
-  InfBlocks(ZStream z, Object checkfn, int w){
+  private final ZStream z; 
+
+  InfBlocks(ZStream z, int w){
+    this.z=z;
+    this.codes=new InfCodes(this.z, this);
     hufts=new int[MANY*3];
     window=new byte[w];
     end=w;
-    this.checkfn = checkfn;
+    this.check = (z.istate.wrap==0) ? false : true;
     mode = TYPE;
-    reset(z, null);
+    reset();
   }
 
-  void reset(ZStream z, long[] c){
-    if(c!=null) c[0]=check;
+  void reset(){
     if(mode==BTREE || mode==DTREE){
     }
     if(mode==CODES){
@@ -118,12 +128,12 @@
     bitk=0;
     bitb=0;
     read=write=0;
-
-    if(checkfn != null)
-      z.adler=check=z._adler.adler32(0L, null, 0, 0);
+    if(check){
+      z.adler.reset();
+    }
   }
 
-  int proc(ZStream z, int r){
+  int proc(int r){
     int t;              // temporary storage
     int b;              // bit buffer
     int k;              // bits in bit buffer
@@ -150,7 +160,7 @@
 	    z.avail_in=n;
 	    z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    write=q;
-	    return inflate_flush(z,r);
+	    return inflate_flush(r);
 	  };
 	  n--;
 	  b|=(z.next_in[p++]&0xff)<<k;
@@ -168,15 +178,8 @@
           mode = LENS;                  // get length of stored block
           break;
         case 1:                         // fixed
-          {
-            int[] bl=new int[1];
-	    int[] bd=new int[1];
-            int[][] tl=new int[1][];
-	    int[][] td=new int[1][];
-
-	    InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
-            codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
-          }
+          InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
+          codes.init(bl[0], bd[0], tl[0], 0, td[0], 0);
 
           {b>>>=(3);k-=(3);}
 
@@ -198,7 +201,7 @@
 	  bitb=b; bitk=k; 
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  write=q;
-	  return inflate_flush(z,r);
+	  return inflate_flush(r);
 	}
 	break;
       case LENS:
@@ -212,7 +215,7 @@
 	    z.avail_in=n;
 	    z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    write=q;
-	    return inflate_flush(z,r);
+	    return inflate_flush(r);
 	  };
 	  n--;
 	  b|=(z.next_in[p++]&0xff)<<k;
@@ -227,7 +230,7 @@
 	  bitb=b; bitk=k; 
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  write=q;
-	  return inflate_flush(z,r);
+	  return inflate_flush(r);
 	}
 	left = (b & 0xffff);
 	b = k = 0;                       // dump bits
@@ -238,7 +241,7 @@
 	  bitb=b; bitk=k; 
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  write=q;
-	  return inflate_flush(z,r);
+	  return inflate_flush(r);
 	}
 
 	if(m==0){
@@ -247,7 +250,7 @@
 	  }
 	  if(m==0){
 	    write=q; 
-	    r=inflate_flush(z,r);
+	    r=inflate_flush(r);
 	    q=write;m=(int)(q<read?read-q-1:end-q);
 	    if(q==end&&read!=0){
 	      q=0; m=(int)(q<read?read-q-1:end-q);
@@ -256,7 +259,7 @@
 	      bitb=b; bitk=k; 
 	      z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	      write=q;
-	      return inflate_flush(z,r);
+	      return inflate_flush(r);
 	    }
 	  }
 	}
@@ -283,7 +286,7 @@
 	    z.avail_in=n;
 	    z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    write=q;
-	    return inflate_flush(z,r);
+	    return inflate_flush(r);
 	  };
 	  n--;
 	  b|=(z.next_in[p++]&0xff)<<k;
@@ -300,7 +303,7 @@
 	    bitb=b; bitk=k; 
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    write=q;
-	    return inflate_flush(z,r);
+	    return inflate_flush(r);
 	  }
 	t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
 	if(blens==null || blens.length<t){
@@ -325,7 +328,7 @@
 	      z.avail_in=n;
 	      z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	      write=q;
-	      return inflate_flush(z,r);
+	      return inflate_flush(r);
 	    };
 	    n--;
 	    b|=(z.next_in[p++]&0xff)<<k;
@@ -353,7 +356,7 @@
 	  bitb=b; bitk=k; 
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  write=q;
-	  return inflate_flush(z,r);
+	  return inflate_flush(r);
 	}
 
 	index = 0;
@@ -379,7 +382,7 @@
 	      z.avail_in=n;
 	      z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	      write=q;
-	      return inflate_flush(z,r);
+	      return inflate_flush(r);
 	    };
 	    n--;
 	    b|=(z.next_in[p++]&0xff)<<k;
@@ -410,7 +413,7 @@
 		z.avail_in=n;
 		z.total_in+=p-z.next_in_index;z.next_in_index=p;
 		write=q;
-		return inflate_flush(z,r);
+		return inflate_flush(r);
 	      };
 	      n--;
 	      b|=(z.next_in[p++]&0xff)<<k;
@@ -435,7 +438,7 @@
 	      bitb=b; bitk=k; 
 	      z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	      write=q;
-	      return inflate_flush(z,r);
+	      return inflate_flush(r);
 	    }
 
 	    c = c == 16 ? blens[i-1] : 0;
@@ -449,17 +452,12 @@
 
 	tb[0]=-1;
 	{
-	  int[] bl=new int[1];
-	  int[] bd=new int[1];
-	  int[] tl=new int[1];
-	  int[] td=new int[1];
 	  bl[0] = 9;         // must be <= 9 for lookahead assumptions
 	  bd[0] = 6;         // must be <= 9 for lookahead assumptions
-
 	  t = table;
 	  t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 
 					    1 + ((t >> 5) & 0x1f),
-					    blens, bl, bd, tl, td, hufts, z);
+					    blens, bl, bd, tli, tdi, hufts, z);
 
 	  if (t != Z_OK){
 	    if (t == Z_DATA_ERROR){
@@ -471,9 +469,9 @@
 	    bitb=b; bitk=k; 
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    write=q;
-	    return inflate_flush(z,r);
+	    return inflate_flush(r);
 	  }
-	  codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
+	  codes.init(bl[0], bd[0], hufts, tli[0], hufts, tdi[0]);
 	}
 	mode = CODES;
       case CODES:
@@ -481,8 +479,8 @@
 	z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	write=q;
 
-	if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
-	  return inflate_flush(z, r);
+	if ((r = codes.proc(r)) != Z_STREAM_END){
+	  return inflate_flush(r);
 	}
 	r = Z_OK;
 	codes.free(z);
@@ -497,13 +495,13 @@
 	mode = DRY;
       case DRY:
 	write=q; 
-	r=inflate_flush(z, r); 
+	r=inflate_flush(r); 
 	q=write; m=(int)(q<read?read-q-1:end-q);
 	if (read != write){
 	  bitb=b; bitk=k; 
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  write=q;
-	  return inflate_flush(z, r);
+	  return inflate_flush(r);
 	}
 	mode = DONE;
       case DONE:
@@ -512,14 +510,14 @@
 	bitb=b; bitk=k; 
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	write=q;
-	return inflate_flush(z, r);
+	return inflate_flush(r);
       case BAD:
 	r = Z_DATA_ERROR;
 
 	bitb=b; bitk=k; 
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	write=q;
-	return inflate_flush(z, r);
+	return inflate_flush(r);
 
       default:
 	r = Z_STREAM_ERROR;
@@ -527,13 +525,13 @@
 	bitb=b; bitk=k; 
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	write=q;
-	return inflate_flush(z, r);
+	return inflate_flush(r);
       }
     }
   }
 
-  void free(ZStream z){
-    reset(z, null);
+  void free(){
+    reset();
     window=null;
     hufts=null;
     //ZFREE(z, s);
@@ -551,7 +549,7 @@
   }
 
   // copy as much as possible from the sliding window to the output area
-  int inflate_flush(ZStream z, int r){
+  int inflate_flush(int r){
     int n;
     int p;
     int q;
@@ -562,16 +560,17 @@
 
     // compute number of bytes to copy as far as end of window
     n = (int)((q <= write ? write : end) - q);
-    if (n > z.avail_out) n = z.avail_out;
-    if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+    if(n > z.avail_out) n = z.avail_out;
+    if(n!=0 && r == Z_BUF_ERROR) r = Z_OK;
 
     // update counters
     z.avail_out -= n;
     z.total_out += n;
 
     // update check information
-    if(checkfn != null)
-      z.adler=check=z._adler.adler32(check, window, q, n);
+    if(check && n>0){
+      z.adler.update(window, q, n);
+    }
 
     // copy as far as end of window
     System.arraycopy(window, q, z.next_out, p, n);
@@ -595,8 +594,9 @@
       z.total_out += n;
 
       // update check information
-      if(checkfn != null)
-	z.adler=check=z._adler.adler32(check, window, q, n);
+      if(check && n>0){
+	z.adler.update(window, q, n);
+      }
 
       // copy
       System.arraycopy(window, q, z.next_out, p, n);
diff --git a/java/com/jcraft/jzlib/InfCodes.java b/java/com/jcraft/jzlib/InfCodes.java
index c768fb1..aaf69cd 100644
--- a/java/com/jcraft/jzlib/InfCodes.java
+++ b/java/com/jcraft/jzlib/InfCodes.java
@@ -89,11 +89,16 @@
   int[] dtree;          // distance tree
   int dtree_index;      // distance tree
 
-  InfCodes(){
+  private final ZStream z;
+  private final InfBlocks s;
+  InfCodes(ZStream z, InfBlocks s){
+    this.z=z; 
+    this.s=s; 
   }
+
   void init(int bl, int bd,
 	   int[] tl, int tl_index,
-	   int[] td, int td_index, ZStream z){
+	   int[] td, int td_index){
     mode=START;
     lbits=(byte)bl;
     dbits=(byte)bd;
@@ -104,7 +109,7 @@
     tree=null;
   }
 
-  int proc(InfBlocks s, ZStream z, int r){ 
+  int proc(int r){ 
     int j;              // temporary storage
     int[] t;            // temporary pointer
     int tindex;         // temporary pointer
@@ -159,7 +164,7 @@
 	    s.bitb=b;s.bitk=k;
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    s.write=q;
-	    return s.inflate_flush(z,r);
+	    return s.inflate_flush(r);
 	  }
 	  n--;
 	  b|=(z.next_in[p++]&0xff)<<k;
@@ -200,7 +205,7 @@
 	s.bitb=b;s.bitk=k;
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	s.write=q;
-	return s.inflate_flush(z,r);
+	return s.inflate_flush(r);
 
       case LENEXT:        // i: getting length extra (have base)
 	j = get;
@@ -212,7 +217,7 @@
 	    s.bitb=b;s.bitk=k;
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    s.write=q;
-	    return s.inflate_flush(z,r);
+	    return s.inflate_flush(r);
 	  }
 	  n--; b|=(z.next_in[p++]&0xff)<<k;
 	  k+=8;
@@ -237,7 +242,7 @@
 	    s.bitb=b;s.bitk=k;
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    s.write=q;
-	    return s.inflate_flush(z,r);
+	    return s.inflate_flush(r);
 	  }
 	  n--; b|=(z.next_in[p++]&0xff)<<k;
 	  k+=8;
@@ -267,7 +272,7 @@
 	s.bitb=b;s.bitk=k;
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	s.write=q;
-	return s.inflate_flush(z,r);
+	return s.inflate_flush(r);
 
       case DISTEXT:       // i: getting distance extra
 	j = get;
@@ -279,7 +284,7 @@
 	    s.bitb=b;s.bitk=k;
 	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	    s.write=q;
-	    return s.inflate_flush(z,r);
+	    return s.inflate_flush(r);
 	  }
 	  n--; b|=(z.next_in[p++]&0xff)<<k;
 	  k+=8;
@@ -301,7 +306,7 @@
 	  if(m==0){
 	    if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
 	    if(m==0){
-	      s.write=q; r=s.inflate_flush(z,r);
+	      s.write=q; r=s.inflate_flush(r);
 	      q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
 	      if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
@@ -310,7 +315,7 @@
 		s.bitb=b;s.bitk=k;
 		z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 		s.write=q;
-		return s.inflate_flush(z,r);
+		return s.inflate_flush(r);
 	      }  
 	    }
 	  }
@@ -327,7 +332,7 @@
 	if(m==0){
 	  if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
 	  if(m==0){
-	    s.write=q; r=s.inflate_flush(z,r);
+	    s.write=q; r=s.inflate_flush(r);
 	    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
 	    if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
@@ -335,7 +340,7 @@
 	      s.bitb=b;s.bitk=k;
 	      z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	      s.write=q;
-	      return s.inflate_flush(z,r);
+	      return s.inflate_flush(r);
 	    }
 	  }
 	}
@@ -352,14 +357,14 @@
 	  p--;             // can always return one
 	}
 
-	s.write=q; r=s.inflate_flush(z,r);
+	s.write=q; r=s.inflate_flush(r);
 	q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
 	if (s.read != s.write){
 	  s.bitb=b;s.bitk=k;
 	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	  s.write=q;
-	  return s.inflate_flush(z,r);
+	  return s.inflate_flush(r);
 	}
 	mode = END;
       case END:
@@ -367,7 +372,7 @@
 	s.bitb=b;s.bitk=k;
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	s.write=q;
-	return s.inflate_flush(z,r);
+	return s.inflate_flush(r);
 
       case BADCODE:       // x: got error
 
@@ -376,7 +381,7 @@
 	s.bitb=b;s.bitk=k;
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	s.write=q;
-	return s.inflate_flush(z,r);
+	return s.inflate_flush(r);
 
       default:
 	r = Z_STREAM_ERROR;
@@ -384,7 +389,7 @@
 	s.bitb=b;s.bitk=k;
 	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
 	s.write=q;
-	return s.inflate_flush(z,r);
+	return s.inflate_flush(r);
       }
     }
   }
diff --git a/java/com/jcraft/jzlib/InfTree.java b/java/com/jcraft/jzlib/InfTree.java
index cbca436..80a2b7b 100644
--- a/java/com/jcraft/jzlib/InfTree.java
+++ b/java/com/jcraft/jzlib/InfTree.java
@@ -512,9 +512,7 @@
     for(int i=0; i<vsize; i++){v[i]=0;}
     for(int i=0; i<BMAX+1; i++){c[i]=0;}
     for(int i=0; i<3; i++){r[i]=0;}
-//  for(int i=0; i<BMAX; i++){u[i]=0;}
     System.arraycopy(c, 0, u, 0, BMAX);
-//  for(int i=0; i<BMAX+1; i++){x[i]=0;}
     System.arraycopy(c, 0, x, 0, BMAX+1);
   }
 }
diff --git a/java/com/jcraft/jzlib/Inflate.java b/java/com/jcraft/jzlib/Inflate.java
index 30310f6..6aa6240 100644
--- a/java/com/jcraft/jzlib/Inflate.java
+++ b/java/com/jcraft/jzlib/Inflate.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -74,158 +74,221 @@
   static final private int DONE=12;    // finished check, done
   static final private int BAD=13;     // got an error--stay here
 
+  static final private int HEAD=14;
+  static final private int LENGTH=15;
+  static final private int TIME=16;
+  static final private int OS=17;
+  static final private int EXLEN=18;
+  static final private int EXTRA=19;
+  static final private int NAME=20;
+  static final private int COMMENT=21;
+  static final private int HCRC=22;
+  static final private int FLAGS=23;
+
   int mode;                            // current inflate mode
 
   // mode dependent information
   int method;        // if FLAGS, method byte
 
   // if CHECK, check values to compare
-  long[] was=new long[1] ; // computed check value
+  long was = -1;           // computed check value
   long need;               // stream check value
 
   // if BAD, inflateSync's marker bytes count
   int marker;
 
   // mode independent information
-  int  nowrap;          // flag for no wrapper
+  int  wrap;          // flag for no wrapper
   int wbits;            // log2(window size)  (8..15, defaults to 15)
 
   InfBlocks blocks;     // current inflate_blocks state
 
-  int inflateReset(ZStream z){
-    if(z == null || z.istate == null) return Z_STREAM_ERROR;
+  private final ZStream z;
+
+  private int flags; 
+
+  private int need_bytes = -1;
+  private byte[] crcbuf=new byte[4];
+
+  GZIPHeader gheader = null;
+
+  int inflateReset(){
+    if(z == null) return Z_STREAM_ERROR;
     
     z.total_in = z.total_out = 0;
     z.msg = null;
-    z.istate.mode = z.istate.nowrap!=0 ? BLOCKS : METHOD;
-    z.istate.blocks.reset(z, null);
+    this.mode = HEAD;
+    this.need_bytes = -1;
+    this.blocks.reset();
     return Z_OK;
   }
 
-  int inflateEnd(ZStream z){
-    if(blocks != null)
-      blocks.free(z);
-    blocks=null;
-    //    ZFREE(z, z->state);
+  int inflateEnd(){
+    if(blocks != null){
+      blocks.free();
+    }
     return Z_OK;
   }
 
-  int inflateInit(ZStream z, int w){
+  Inflate(ZStream z){
+    this.z=z;
+  }
+
+  int inflateInit(int w){
     z.msg = null;
     blocks = null;
 
-    // handle undocumented nowrap option (no zlib header or check)
-    nowrap = 0;
+    // handle undocumented wrap option (no zlib header or check)
+    wrap = 0;
     if(w < 0){
       w = - w;
-      nowrap = 1;
+    }
+    else {
+      wrap = (w >> 4) + 1;
+      if(w < 48)
+        w &= 15;
+    }
+
+    if(w<8 ||w>15){
+      inflateEnd();
+      return Z_STREAM_ERROR;
+    }
+    if(blocks != null && wbits != w){
+      blocks.free();
+      blocks=null;
     }
 
     // set window size
-    if(w<8 ||w>15){
-      inflateEnd(z);
-      return Z_STREAM_ERROR;
-    }
     wbits=w;
 
-    z.istate.blocks=new InfBlocks(z, 
-				  z.istate.nowrap!=0 ? null : this,
-				  1<<w);
+    this.blocks=new InfBlocks(z, 1<<w);
 
     // reset state
-    inflateReset(z);
+    inflateReset();
+
     return Z_OK;
   }
 
-  int inflate(ZStream z, int f){
+  int inflate(int f){
+    int hold = 0;
+
     int r;
     int b;
 
-    if(z == null || z.istate == null || z.next_in == null)
+    if(z == null || z.next_in == null){
+      if(f == Z_FINISH && this.mode==HEAD)
+        return Z_OK; 
       return Z_STREAM_ERROR;
+    }
+
     f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
     r = Z_BUF_ERROR;
     while (true){
-//System.out.println("mode: "+z.istate.mode);
-      switch (z.istate.mode){
-      case METHOD:
 
-        if(z.avail_in==0)return r;r=f;
+      switch (this.mode){
+      case HEAD:
+        if(wrap==0){
+	  this.mode = BLOCKS;
+          break;
+        } 
 
-        z.avail_in--; z.total_in++;
-        if(((z.istate.method = z.next_in[z.next_in_index++])&0xf)!=Z_DEFLATED){
-          z.istate.mode = BAD;
-          z.msg="unknown compression method";
-          z.istate.marker = 5;       // can't try inflateSync
+        try { r=readBytes(2, r, f); }
+        catch(Return e){ return e.r; }
+
+        if((wrap&2)!=0 && this.need == 0x8b1fL) {   // gzip header
+	  z.adler=new CRC32();
+          checksum(2, this.need);
+
+          if(gheader==null) 
+            gheader=new GZIPHeader();
+
+          this.mode = FLAGS;
           break;
         }
-        if((z.istate.method>>4)+8>z.istate.wbits){
-          z.istate.mode = BAD;
-          z.msg="invalid window size";
-          z.istate.marker = 5;       // can't try inflateSync
-          break;
-        }
-        z.istate.mode=FLAG;
-      case FLAG:
 
-        if(z.avail_in==0)return r;r=f;
+        flags = 0;
 
-        z.avail_in--; z.total_in++;
-        b = (z.next_in[z.next_in_index++])&0xff;
+        this.method = ((int)this.need)&0xff;
+        b=((int)(this.need>>8))&0xff;
 
-        if((((z.istate.method << 8)+b) % 31)!=0){
-          z.istate.mode = BAD;
+        if((wrap&1)==0 ||  // check if zlib header allowed
+           (((this.method << 8)+b) % 31)!=0){
+          this.mode = BAD;
           z.msg = "incorrect header check";
-          z.istate.marker = 5;       // can't try inflateSync
+          // since zlib 1.2, it is allowted to inflateSync for this case.
+          /*
+          this.marker = 5;       // can't try inflateSync
+          */
           break;
         }
 
+        if((this.method&0xf)!=Z_DEFLATED){
+          this.mode = BAD;
+          z.msg="unknown compression method";
+          // since zlib 1.2, it is allowted to inflateSync for this case.
+	  /*
+          this.marker = 5;       // can't try inflateSync
+	  */
+          break;
+        }
+
+        if((this.method>>4)+8>this.wbits){
+          this.mode = BAD;
+          z.msg="invalid window size";
+          // since zlib 1.2, it is allowted to inflateSync for this case.
+	  /*
+          this.marker = 5;       // can't try inflateSync
+	  */
+          break;
+        }
+
+        z.adler=new Adler32();
+
         if((b&PRESET_DICT)==0){
-          z.istate.mode = BLOCKS;
+          this.mode = BLOCKS;
           break;
         }
-        z.istate.mode = DICT4;
+        this.mode = DICT4;
       case DICT4:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
-        z.istate.mode=DICT3;
+        this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+        this.mode=DICT3;
       case DICT3:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
-        z.istate.mode=DICT2;
+        this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+        this.mode=DICT2;
       case DICT2:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
-        z.istate.mode=DICT1;
+        this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+        this.mode=DICT1;
       case DICT1:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
-        z.adler = z.istate.need;
-        z.istate.mode = DICT0;
+        this.need += (z.next_in[z.next_in_index++]&0xffL);
+        z.adler.reset(this.need);
+        this.mode = DICT0;
         return Z_NEED_DICT;
       case DICT0:
-        z.istate.mode = BAD;
+        this.mode = BAD;
         z.msg = "need dictionary";
-        z.istate.marker = 0;       // can try inflateSync
+        this.marker = 0;       // can try inflateSync
         return Z_STREAM_ERROR;
       case BLOCKS:
-
-        r = z.istate.blocks.proc(z, r);
+        r = this.blocks.proc(r);
         if(r == Z_DATA_ERROR){
-          z.istate.mode = BAD;
-          z.istate.marker = 0;     // can try inflateSync
+          this.mode = BAD;
+          this.marker = 0;     // can try inflateSync
           break;
         }
         if(r == Z_OK){
@@ -235,100 +298,280 @@
           return r;
         }
         r = f;
-        z.istate.blocks.reset(z, z.istate.was);
-        if(z.istate.nowrap!=0){
-          z.istate.mode=DONE;
+        this.was=z.adler.getValue();
+        this.blocks.reset();
+        if(this.wrap==0){
+          this.mode=DONE;
           break;
         }
-        z.istate.mode=CHECK4;
+        this.mode=CHECK4;
       case CHECK4:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
-        z.istate.mode=CHECK3;
+        this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+        this.mode=CHECK3;
       case CHECK3:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
-        z.istate.mode = CHECK2;
+        this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+        this.mode = CHECK2;
       case CHECK2:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
-        z.istate.mode = CHECK1;
+        this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+        this.mode = CHECK1;
       case CHECK1:
 
         if(z.avail_in==0)return r;r=f;
 
         z.avail_in--; z.total_in++;
-        z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
+        this.need+=(z.next_in[z.next_in_index++]&0xffL);
 
-        if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
-          z.istate.mode = BAD;
-          z.msg = "incorrect data check";
-          z.istate.marker = 5;       // can't try inflateSync
-          break;
+        if(flags!=0){  // gzip
+          this.need = ((this.need&0xff000000)>>24 | 
+                          (this.need&0x00ff0000)>>8 | 
+                          (this.need&0x0000ff00)<<8 | 
+                          (this.need&0x0000ffff)<<24)&0xffffffffL;
         }
 
-        z.istate.mode = DONE;
+        if(((int)(this.was)) != ((int)(this.need))){
+          z.msg = "incorrect data check";
+          // chack is delayed
+          /*
+          this.mode = BAD;
+          this.marker = 5;       // can't try inflateSync
+          break;
+	  */
+        }
+        else if(flags!=0 && gheader!=null){
+          gheader.crc = this.need; 
+        }
+
+        this.mode = LENGTH;
+      case LENGTH:
+        if (wrap!=0 && flags!=0) {
+
+          try { r=readBytes(4, r, f); }
+          catch(Return e){ return e.r; }
+
+          if(z.msg!=null && z.msg.equals("incorrect data check")){
+            this.mode = BAD;
+            this.marker = 5;       // can't try inflateSync
+            break;
+          }
+
+          if (this.need != (z.total_out & 0xffffffffL)) {
+            z.msg = "incorrect length check";
+            this.mode = BAD;
+            break;
+          }
+          z.msg = null;
+        }
+        else {
+          if(z.msg!=null && z.msg.equals("incorrect data check")){
+            this.mode = BAD;
+            this.marker = 5;       // can't try inflateSync
+            break;
+          }
+        }
+
+        this.mode = DONE;
       case DONE:
         return Z_STREAM_END;
       case BAD:
         return Z_DATA_ERROR;
+
+      case FLAGS:
+
+        try { r=readBytes(2, r, f); }
+        catch(Return e){ return e.r; }
+
+        flags = ((int)this.need)&0xffff;
+
+        if ((flags & 0xff) != Z_DEFLATED) {
+          z.msg = "unknown compression method";
+          this.mode = BAD; 
+          break;
+        }
+        if ((flags & 0xe000)!=0) {
+          z.msg = "unknown header flags set";
+          this.mode = BAD; 
+          break;
+        }
+
+        if ((flags & 0x0200)!=0){
+          checksum(2, this.need);
+        } 
+
+        this.mode = TIME;
+
+      case TIME:
+        try { r=readBytes(4, r, f); }
+        catch(Return e){ return e.r; }
+        if(gheader!=null)
+          gheader.time = this.need;
+        if ((flags & 0x0200)!=0){
+          checksum(4, this.need);
+        }
+        this.mode = OS;
+      case OS:
+        try { r=readBytes(2, r, f); }
+        catch(Return e){ return e.r; }
+        if(gheader!=null){
+          gheader.xflags = ((int)this.need)&0xff;
+          gheader.os = (((int)this.need)>>8)&0xff;
+        }
+        if ((flags & 0x0200)!=0){
+          checksum(2, this.need);
+        }
+        this.mode = EXLEN;
+      case EXLEN:
+        if ((flags & 0x0400)!=0) {
+          try { r=readBytes(2, r, f); }
+          catch(Return e){ return e.r; }
+          if(gheader!=null){
+            gheader.extra = new byte[((int)this.need)&0xffff];
+          }
+          if ((flags & 0x0200)!=0){
+            checksum(2, this.need);
+          }
+        }
+        else if(gheader!=null){
+          gheader.extra=null;
+        }
+        this.mode = EXTRA;
+
+      case EXTRA:
+        if ((flags & 0x0400)!=0) {
+          try { 
+            r=readBytes(r, f);
+            if(gheader!=null){
+              byte[] foo = tmp_string.toByteArray();
+              tmp_string=null;
+              if(foo.length == gheader.extra.length){
+                System.arraycopy(foo, 0, gheader.extra, 0, foo.length);
+	      }
+              else{
+                z.msg = "bad extra field length";
+                this.mode = BAD; 
+                break;
+	      }
+            }
+          }
+          catch(Return e){ return e.r; }
+        }
+        else if(gheader!=null){
+          gheader.extra=null;
+	}
+	this.mode = NAME;
+      case NAME:
+	if ((flags & 0x0800)!=0) {
+          try { 
+            r=readString(r, f);
+            if(gheader!=null){
+              gheader.name=tmp_string.toByteArray();
+            }
+            tmp_string=null;
+          }
+          catch(Return e){ return e.r; }
+        }
+        else if(gheader!=null){
+          gheader.name=null;
+	}
+        this.mode = COMMENT;
+      case COMMENT:
+        if ((flags & 0x1000)!=0) {
+          try { 
+            r=readString(r, f);
+            if(gheader!=null){
+              gheader.comment=tmp_string.toByteArray();
+            }
+            tmp_string=null;
+          }
+          catch(Return e){ return e.r; }
+        }
+        else if(gheader!=null){
+          gheader.comment=null;
+	}
+        this.mode = HCRC;
+      case HCRC:
+	if ((flags & 0x0200)!=0) {
+          try { r=readBytes(2, r, f); }
+          catch(Return e){ return e.r; }
+          if(gheader!=null){
+            gheader.hcrc=(int)(this.need&0xffff);
+          }
+          if(this.need != (z.adler.getValue()&0xffffL)){
+            this.mode = BAD;
+            z.msg = "header crc mismatch";
+            this.marker = 5;       // can't try inflateSync
+            break;
+          }
+        }
+        z.adler = new CRC32();
+
+        this.mode = BLOCKS;
+        break;
       default:
         return Z_STREAM_ERROR;
       }
     }
   }
 
+  int inflateSetDictionary(byte[] dictionary, int dictLength){
+    if(z==null || (this.mode != DICT0 && this.wrap != 0)){
+      return Z_STREAM_ERROR;
+    }
 
-  int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
     int index=0;
     int length = dictLength;
-    if(z==null || z.istate == null|| z.istate.mode != DICT0)
-      return Z_STREAM_ERROR;
 
-    if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
-      return Z_DATA_ERROR;
+    if(this.mode==DICT0){
+      long adler_need=z.adler.getValue();
+      z.adler.reset();
+      z.adler.update(dictionary, 0, dictLength);
+      if(z.adler.getValue()!=adler_need){
+        return Z_DATA_ERROR;
+      }
     }
 
-    z.adler = z._adler.adler32(0, null, 0, 0);
+    z.adler.reset();
 
-    if(length >= (1<<z.istate.wbits)){
-      length = (1<<z.istate.wbits)-1;
+    if(length >= (1<<this.wbits)){
+      length = (1<<this.wbits)-1;
       index=dictLength - length;
     }
-    z.istate.blocks.set_dictionary(dictionary, index, length);
-    z.istate.mode = BLOCKS;
+    this.blocks.set_dictionary(dictionary, index, length);
+    this.mode = BLOCKS;
     return Z_OK;
   }
 
   static private byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff};
 
-  int inflateSync(ZStream z){
+  int inflateSync(){
     int n;       // number of bytes to look at
     int p;       // pointer to bytes
     int m;       // number of marker bytes found in a row
     long r, w;   // temporaries to save total_in and total_out
 
     // set up
-    if(z == null || z.istate == null)
+    if(z == null)
       return Z_STREAM_ERROR;
-    if(z.istate.mode != BAD){
-      z.istate.mode = BAD;
-      z.istate.marker = 0;
+    if(this.mode != BAD){
+      this.mode = BAD;
+      this.marker = 0;
     }
     if((n=z.avail_in)==0)
       return Z_BUF_ERROR;
-    p=z.next_in_index;
-    m=z.istate.marker;
 
+    p=z.next_in_index;
+    m=this.marker;
     // search
     while (n!=0 && m < 4){
       if(z.next_in[p] == mark[m]){
@@ -347,16 +590,17 @@
     z.total_in += p-z.next_in_index;
     z.next_in_index = p;
     z.avail_in = n;
-    z.istate.marker = m;
+    this.marker = m;
 
     // return no joy or set up to restart on a new block
     if(m != 4){
       return Z_DATA_ERROR;
     }
     r=z.total_in;  w=z.total_out;
-    inflateReset(z);
+    inflateReset();
     z.total_in=r;  z.total_out = w;
-    z.istate.mode = BLOCKS;
+    this.mode = BLOCKS;
+
     return Z_OK;
   }
 
@@ -366,9 +610,102 @@
   // but removes the length bytes of the resulting empty stored block. When
   // decompressing, PPP checks that at the end of input packet, inflate is
   // waiting for these length bytes.
-  int inflateSyncPoint(ZStream z){
-    if(z == null || z.istate == null || z.istate.blocks == null)
+  int inflateSyncPoint(){
+    if(z == null || this.blocks == null)
       return Z_STREAM_ERROR;
-    return z.istate.blocks.sync_point();
+    return this.blocks.sync_point();
+  }
+
+  private int readBytes(int n, int r, int f) throws Return{
+    if(need_bytes == -1){
+      need_bytes=n;
+      this.need=0;
+    }
+    while(need_bytes>0){
+      if(z.avail_in==0){ throw new Return(r); }; r=f;
+      z.avail_in--; z.total_in++;
+      this.need = this.need | 
+	((z.next_in[z.next_in_index++]&0xff)<<((n-need_bytes)*8));
+      need_bytes--;
+    }
+    if(n==2){
+      this.need&=0xffffL;
+    }
+    else if(n==4) {
+      this.need&=0xffffffffL;
+    }
+    need_bytes=-1;
+    return r;
+  }
+  class Return extends Exception{
+    int r;
+    Return(int r){this.r=r; }
+  }
+
+  private java.io.ByteArrayOutputStream tmp_string = null;
+  private int readString(int r, int f) throws Return{
+    if(tmp_string == null){
+      tmp_string=new java.io.ByteArrayOutputStream();
+    }
+    int b=0; 
+    do {
+      if(z.avail_in==0){ throw new Return(r); }; r=f;
+      z.avail_in--; z.total_in++;
+      b = z.next_in[z.next_in_index];
+      if(b!=0) tmp_string.write(z.next_in, z.next_in_index, 1);
+      z.adler.update(z.next_in, z.next_in_index, 1);
+      z.next_in_index++;
+    }while(b!=0);
+    return r;
+  }
+
+  private int readBytes(int r, int f) throws Return{
+    if(tmp_string == null){
+      tmp_string=new java.io.ByteArrayOutputStream();
+    }
+    int b=0; 
+    while(this.need>0){
+      if(z.avail_in==0){ throw new Return(r); }; r=f;
+      z.avail_in--; z.total_in++;
+      b = z.next_in[z.next_in_index];
+      tmp_string.write(z.next_in, z.next_in_index, 1);
+      z.adler.update(z.next_in, z.next_in_index, 1);
+      z.next_in_index++;
+      this.need--;
+    }
+    return r;
+  }
+
+  private void checksum(int n, long v){
+    for(int i=0; i<n; i++){
+      crcbuf[i]=(byte)(v&0xff);
+      v>>=8;
+    }
+    z.adler.update(crcbuf, 0, n);
+  }
+
+  public GZIPHeader getGZIPHeader(){
+    return gheader;
+  }
+
+  boolean inParsingHeader(){
+    switch(mode){
+      case HEAD:
+      case DICT4:
+      case DICT3:
+      case DICT2:
+      case DICT1:
+      case FLAGS:
+      case TIME:
+      case OS:
+      case EXLEN:
+      case EXTRA:
+      case NAME:
+      case COMMENT:
+      case HCRC:
+	return true;
+      default:
+	return false;
+    }
   }
 }
diff --git a/java/com/jcraft/jzlib/JZlib.java b/java/com/jcraft/jzlib/JZlib.java
index b84d7a1..8fd98ea 100644
--- a/java/com/jcraft/jzlib/JZlib.java
+++ b/java/com/jcraft/jzlib/JZlib.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -35,9 +35,12 @@
 package com.jcraft.jzlib;
 
 final public class JZlib{
-  private static final String version="1.0.2";
+  private static final String version="1.1.0";
   public static String version(){return version;}
 
+  static final public int MAX_WBITS=15;        // 32K LZ77 window
+  static final public int DEF_WBITS=MAX_WBITS;
+
   // compression levels
   static final public int Z_NO_COMPRESSION=0;
   static final public int Z_BEST_SPEED=1;
@@ -64,4 +67,17 @@
   static final public int Z_MEM_ERROR=-4;
   static final public int Z_BUF_ERROR=-5;
   static final public int Z_VERSION_ERROR=-6;
+
+  // The three kinds of block type
+  static final public byte Z_BINARY = 0;
+  static final public byte Z_ASCII = 1;
+  static final public byte Z_UNKNOWN = 2;
+
+  public static long adler32_combine(long adler1, long adler2, long len2){
+    return Adler32.combine(adler1, adler2, len2);
+  }
+
+  public static long crc32_combine(long crc1, long crc2, long len2){
+    return CRC32.combine(crc1, crc2, len2);
+  }
 }
diff --git a/java/com/jcraft/jzlib/LICENSE.txt b/java/com/jcraft/jzlib/LICENSE.txt
index cdce500..6859c59 100644
--- a/java/com/jcraft/jzlib/LICENSE.txt
+++ b/java/com/jcraft/jzlib/LICENSE.txt
@@ -2,7 +2,7 @@
 over to a BSD-style license. 
 
 ------------------------------------------------------------------------------
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jzlib/README b/java/com/jcraft/jzlib/README
index 45027db..69aec56 100644
--- a/java/com/jcraft/jzlib/README
+++ b/java/com/jcraft/jzlib/README
@@ -6,7 +6,7 @@
 
                           http://www.jcraft.com/jzlib/
 
-Last modified: Fri Feb 14 13:31:26 UTC 2003
+Last modified: Mon Sep 19 15:28:43 UTC 2011
 
 Description
 ===========
@@ -25,7 +25,7 @@
 
 Directories & Files in the Source Tree
 ======================================
-* com/ has source trees of JZlib.
+* src/main/java has source trees of JZlib.
 * example/ has some samples, which demonstrate the usages.
 * misc/ has some stuffs. At present, this directory includes
   a patch file for MindTerm v.1.2.1, which adds the packet compression
@@ -40,7 +40,7 @@
 * JZlib does not support gzip file handling supports.
 * The performance has not been estimated yet,  but it will be not so bad
   in deflating/inflating data stream on the low bandwidth network.
-* JZlib is licensed under BSD style license.
+* JZlib is under BSD style license.
 * Any invention has not been done in developing JZlib.
   So, if zlib is patent free, JZlib is also not covered by any patents.
 
@@ -73,6 +73,18 @@
 This is our motivation to hack JZlib.
 
 
+Building Jar File
+=================
+Use 'sbt'(https://github.com/harrah/xsbt/wiki),
+  % sbt package
+or
+  % mvn package
+or
+  % cd src/main/java
+  % javac -target 1.5 com/jcraft/jzlib/*.java
+  % jar -cvf jzlib.jar com/jcraft/jzlib/*.class
+
+
 A unofficial patch for MindTerm v.1.2.1
 =======================================
 A unofficial patch file for MindTerm v.1.2.1 has included in 'misc' directory.
@@ -84,7 +96,6 @@
 ========================
 JZlib is copyrighted by ymnk, JCraft,Inc. and is licensed through BSD
 style license.  Read the LICENSE.txt file for the complete license.
-ZInputStream and ZOutputStream classes were contributed by Lapo Luchini.
 
 
 Credits
diff --git a/java/com/jcraft/jzlib/StaticTree.java b/java/com/jcraft/jzlib/StaticTree.java
index 0f7f577..e35931c 100644
--- a/java/com/jcraft/jzlib/StaticTree.java
+++ b/java/com/jcraft/jzlib/StaticTree.java
@@ -134,12 +134,11 @@
   int elems;               // max number of elements in the tree
   int max_length;          // max bit length for the codes
 
-  StaticTree(short[] static_tree,
-	     int[] extra_bits,
-	     int extra_base,
-	     int elems,
-	     int max_length
-	     ){
+  private StaticTree(short[] static_tree,
+                     int[] extra_bits,
+                     int extra_base,
+                     int elems,
+                     int max_length){
     this.static_tree=static_tree;
     this.extra_bits=extra_bits;
     this.extra_base=extra_base;
diff --git a/java/com/jcraft/jzlib/Tree.java b/java/com/jcraft/jzlib/Tree.java
index 8103897..40b6ba8 100644
--- a/java/com/jcraft/jzlib/Tree.java
+++ b/java/com/jcraft/jzlib/Tree.java
@@ -317,17 +317,18 @@
   // the given tree and the field len is set for all tree elements.
   // OUT assertion: the field code is set for all tree elements of non
   //     zero code length.
-  static void gen_codes(short[] tree, // the tree to decorate
-			int max_code, // largest code with non zero frequency
-			short[] bl_count // number of codes at each bit length
-			){
-    short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+  static short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+  synchronized static void gen_codes(short[] tree, // the tree to decorate
+                         int max_code, // largest code with non zero frequency
+                         short[] bl_count // number of codes at each bit length
+                        ){
     short code = 0;            // running code value
     int bits;                  // bit index
     int n;                     // code index
 
     // The distribution counts are first used to generate the code values
     // without bit reversal.
+    next_code[0]=0;
     for (bits = 1; bits <= MAX_BITS; bits++) {
       next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
     }
diff --git a/java/com/jcraft/jzlib/ZInputStream.java b/java/com/jcraft/jzlib/ZInputStream.java
index 3f97c44..0054645 100644
--- a/java/com/jcraft/jzlib/ZInputStream.java
+++ b/java/com/jcraft/jzlib/ZInputStream.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2001 Lapo Luchini.
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -17,8 +17,8 @@
 
 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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
-OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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
@@ -26,91 +26,71 @@
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/*
- * This program is based on zlib-1.1.3, so all credit should go authors
- * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
- * and contributors of zlib.
- */
 
 package com.jcraft.jzlib;
 import java.io.*;
 
+/**
+ * ZInputStream
+ *
+ * @deprecated  use DeflaterOutputStream or InflaterInputStream
+ */
+@Deprecated
 public class ZInputStream extends FilterInputStream {
 
-  protected ZStream z=new ZStream();
-  protected int bufsize=512;
   protected int flush=JZlib.Z_NO_FLUSH;
-  protected byte[] buf=new byte[bufsize],
-                   buf1=new byte[1];
   protected boolean compress;
-
   protected InputStream in=null;
 
-  public ZInputStream(InputStream in) {
+  protected Deflater deflater;
+  protected InflaterInputStream iis;
+
+  public ZInputStream(InputStream in) throws IOException {
     this(in, false);
   }
-  public ZInputStream(InputStream in, boolean nowrap) {
+  public ZInputStream(InputStream in, boolean nowrap) throws IOException {
     super(in);
-    this.in=in;
-    z.inflateInit(nowrap);
+    iis = new InflaterInputStream(in);
     compress=false;
-    z.next_in=buf;
-    z.next_in_index=0;
-    z.avail_in=0;
   }
 
-  public ZInputStream(InputStream in, int level) {
+  public ZInputStream(InputStream in, int level) throws IOException {
     super(in);
     this.in=in;
-    z.deflateInit(level);
+    deflater = new Deflater();
+    deflater.init(level);
     compress=true;
-    z.next_in=buf;
-    z.next_in_index=0;
-    z.avail_in=0;
   }
 
-  /*public int available() throws IOException {
-    return inf.finished() ? 0 : 1;
-  }*/
-
+  private byte[] buf1 = new byte[1];
   public int read() throws IOException {
-    if(read(buf1, 0, 1)==-1)
-      return(-1);
+    if(read(buf1, 0, 1)==-1) return -1;
     return(buf1[0]&0xFF);
   }
 
-  private boolean nomoreinput=false;
+  private byte[] buf = new byte[512];
 
   public int read(byte[] b, int off, int len) throws IOException {
-    if(len==0)
-      return(0);
-    int err;
-    z.next_out=b;
-    z.next_out_index=off;
-    z.avail_out=len;
-    do {
-      if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
-	z.next_in_index=0;
-	z.avail_in=in.read(buf, 0, bufsize);//(bufsize<z.avail_out ? bufsize : z.avail_out));
-	if(z.avail_in==-1) {
-	  z.avail_in=0;
-	  nomoreinput=true;
-	}
+    if(compress){
+      deflater.setOutput(b, off, len);
+      while(true){
+        int datalen = in.read(buf, 0, buf.length);
+        if(datalen == -1) return -1;
+        deflater.setInput(buf, 0, datalen, true);
+        int err = deflater.deflate(flush);
+        if(deflater.next_out_index>0)
+          return deflater.next_out_index;
+        if(err == JZlib.Z_STREAM_END)
+          return 0;
+        if(err == JZlib.Z_STREAM_ERROR ||
+           err == JZlib.Z_DATA_ERROR){
+          throw new ZStreamException("deflating: "+deflater.msg);
+        }
       }
-      if(compress)
-	err=z.deflate(flush);
-      else
-	err=z.inflate(flush);
-      if(nomoreinput&&(err==JZlib.Z_BUF_ERROR))
-        return(-1);
-      if(err!=JZlib.Z_OK && err!=JZlib.Z_STREAM_END)
-	throw new ZStreamException((compress ? "de" : "in")+"flating: "+z.msg);
-      if((nomoreinput||err==JZlib.Z_STREAM_END)&&(z.avail_out==len))
-	return(-1);
-    } 
-    while(z.avail_out==len&&err==JZlib.Z_OK);
-    //System.err.print("("+(len-z.avail_out)+")");
-    return(len-z.avail_out);
+    }
+    else{
+      return iis.read(b, off, len); 
+    }
   }
 
   public long skip(long n) throws IOException {
@@ -122,28 +102,25 @@
   }
 
   public int getFlushMode() {
-    return(flush);
+    return flush;
   }
 
   public void setFlushMode(int flush) {
     this.flush=flush;
   }
 
-  /**
-   * Returns the total number of bytes input so far.
-   */
   public long getTotalIn() {
-    return z.total_in;
+    if(compress) return deflater.total_in;
+    else return iis.getTotalIn();
   }
 
-  /**
-   * Returns the total number of bytes output so far.
-   */
   public long getTotalOut() {
-    return z.total_out;
+    if(compress) return deflater.total_out;
+    else return iis.getTotalOut();
   }
 
   public void close() throws IOException{
-    in.close();
+    if(compress) deflater.end();
+    else iis.close();
   }
 }
diff --git a/java/com/jcraft/jzlib/ZOutputStream.java b/java/com/jcraft/jzlib/ZOutputStream.java
index afee65b..32074aa 100644
--- a/java/com/jcraft/jzlib/ZOutputStream.java
+++ b/java/com/jcraft/jzlib/ZOutputStream.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2001 Lapo Luchini.
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -17,8 +17,8 @@
 
 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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
-OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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
@@ -26,72 +26,79 @@
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/*
- * This program is based on zlib-1.1.3, so all credit should go authors
- * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
- * and contributors of zlib.
- */
 
 package com.jcraft.jzlib;
 import java.io.*;
 
-public class ZOutputStream extends OutputStream {
+/**
+ * ZOutputStream
+ *
+ * @deprecated  use DeflaterOutputStream or InflaterInputStream
+ */
+@Deprecated
+public class ZOutputStream extends FilterOutputStream {
 
-  protected ZStream z=new ZStream();
   protected int bufsize=512;
   protected int flush=JZlib.Z_NO_FLUSH;
-  protected byte[] buf=new byte[bufsize],
-                   buf1=new byte[1];
+  protected byte[] buf=new byte[bufsize];
   protected boolean compress;
 
   protected OutputStream out;
+  private boolean end=false;
 
-  public ZOutputStream(OutputStream out) {
-    super();
+  private DeflaterOutputStream dos;
+  private Inflater inflater;
+
+  public ZOutputStream(OutputStream out) throws IOException {
+    super(out);
     this.out=out;
-    z.inflateInit();
+    inflater = new Inflater();
+    inflater.init();
     compress=false;
   }
 
-  public ZOutputStream(OutputStream out, int level) {
+  public ZOutputStream(OutputStream out, int level) throws IOException {
     this(out, level, false);
   }
-  public ZOutputStream(OutputStream out, int level, boolean nowrap) {
-    super();
+
+  public ZOutputStream(OutputStream out, int level, boolean nowrap) throws IOException {
+    super(out);
     this.out=out;
-    z.deflateInit(level, nowrap);
+    Deflater deflater = new Deflater(level, nowrap);
+    dos = new DeflaterOutputStream(out, deflater);
     compress=true;
   }
 
+  private byte[] buf1 = new byte[1];
   public void write(int b) throws IOException {
     buf1[0]=(byte)b;
     write(buf1, 0, 1);
   }
 
   public void write(byte b[], int off, int len) throws IOException {
-    if(len==0)
+    if(len==0) return;
+    if(compress){
+      dos.write(b, off, len);
+    }
+    else {
+      inflater.setInput(b, off, len, true);
+      int err = JZlib.Z_OK;
+      while(inflater.avail_in>0){
+        inflater.setOutput(buf, 0, buf.length);
+        err = inflater.inflate(flush);
+        if(inflater.next_out_index>0)
+          out.write(buf, 0, inflater.next_out_index);
+        if(err != JZlib.Z_OK)
+          break;
+      }
+      if(err != JZlib.Z_OK)
+        throw new ZStreamException("inflating: "+inflater.msg);
       return;
-    int err;
-    z.next_in=b;
-    z.next_in_index=off;
-    z.avail_in=len;
-    do{
-      z.next_out=buf;
-      z.next_out_index=0;
-      z.avail_out=bufsize;
-      if(compress)
-        err=z.deflate(flush);
-      else
-        err=z.inflate(flush);
-      if(err!=JZlib.Z_OK)
-        throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
-      out.write(buf, 0, bufsize-z.avail_out);
-    } 
-    while(z.avail_in>0 || z.avail_out==0);
+    }
   }
 
   public int getFlushMode() {
-    return(flush);
+    return flush;
   }
 
   public void setFlushMode(int flush) {
@@ -100,28 +107,28 @@
 
   public void finish() throws IOException {
     int err;
-    do{
-      z.next_out=buf;
-      z.next_out_index=0;
-      z.avail_out=bufsize;
-      if(compress){ err=z.deflate(JZlib.Z_FINISH);  }
-      else{ err=z.inflate(JZlib.Z_FINISH); }
-      if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
-      throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
-      if(bufsize-z.avail_out>0){
-	out.write(buf, 0, bufsize-z.avail_out);
+    if(compress){
+      int tmp = flush;
+      int flush = JZlib.Z_FINISH;
+      try{
+        write("".getBytes(), 0, 0);
       }
+      finally { flush = tmp; }
     }
-    while(z.avail_in>0 || z.avail_out==0);
+    else{
+      dos.finish();
+    }
     flush();
   }
-  public void end() {
-    if(z==null)
-      return;
-    if(compress){ z.deflateEnd(); }
-    else{ z.inflateEnd(); }
-    z.free();
-    z=null;
+  public synchronized void end() {
+    if(end) return;
+    if(compress){
+      try { dos.finish(); } catch(Exception e){}
+    }
+    else{
+      inflater.end();
+    }
+    end=true;
   }
   public void close() throws IOException {
     try{
@@ -135,18 +142,14 @@
     }
   }
 
-  /**
-   * Returns the total number of bytes input so far.
-   */
   public long getTotalIn() {
-    return z.total_in;
+    if(compress) return dos.getTotalIn();
+    else return inflater.total_in;
   }
 
-  /**
-   * Returns the total number of bytes output so far.
-   */
   public long getTotalOut() {
-    return z.total_out;
+    if(compress) return dos.getTotalOut();
+    else return inflater.total_out;
   }
 
   public void flush() throws IOException {
diff --git a/java/com/jcraft/jzlib/ZStream.java b/java/com/jcraft/jzlib/ZStream.java
index 334475e..dd0a525 100644
--- a/java/com/jcraft/jzlib/ZStream.java
+++ b/java/com/jcraft/jzlib/ZStream.java
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,13 @@
 
 package com.jcraft.jzlib;
 
-final public class ZStream{
+/**
+ * ZStream
+ *
+ * @deprecated  Not for public use in the future.
+ */
+@Deprecated
+public class ZStream{
 
   static final private int MAX_WBITS=15;        // 32K LZ77 window
   static final private int DEF_WBITS=MAX_WBITS;
@@ -74,8 +80,15 @@
 
   int data_type; // best guess about the data type: ascii or binary
 
-  public long adler;
-  Adler32 _adler=new Adler32();
+  Checksum adler;
+
+  public ZStream(){
+    this(new Adler32());
+  }
+
+  public ZStream(Checksum adler){
+    this.adler=adler;
+  }
 
   public int inflateInit(){
     return inflateInit(DEF_WBITS);
@@ -88,29 +101,37 @@
   }
 
   public int inflateInit(int w, boolean nowrap){
-    istate=new Inflate();
-    return istate.inflateInit(this, nowrap?-w:w);
+    istate=new Inflate(this);
+    return istate.inflateInit(nowrap?-w:w);
   }
 
   public int inflate(int f){
     if(istate==null) return Z_STREAM_ERROR;
-    return istate.inflate(this, f);
+    return istate.inflate(f);
   }
   public int inflateEnd(){
     if(istate==null) return Z_STREAM_ERROR;
-    int ret=istate.inflateEnd(this);
-    istate = null;
+    int ret=istate.inflateEnd();
+//    istate = null;
     return ret;
   }
   public int inflateSync(){
     if(istate == null)
       return Z_STREAM_ERROR;
-    return istate.inflateSync(this);
+    return istate.inflateSync();
+  }
+  public int inflateSyncPoint(){
+    if(istate == null)
+      return Z_STREAM_ERROR;
+    return istate.inflateSyncPoint();
   }
   public int inflateSetDictionary(byte[] dictionary, int dictLength){
     if(istate == null)
       return Z_STREAM_ERROR;
-    return istate.inflateSetDictionary(this, dictionary, dictLength);
+    return istate.inflateSetDictionary(dictionary, dictLength);
+  }
+  public boolean inflateFinished(){
+    return istate.mode==12 /*DONE*/;
   }
 
   public int deflateInit(int level){
@@ -122,15 +143,19 @@
   public int deflateInit(int level, int bits){
     return deflateInit(level, bits, false);
   }
+  public int deflateInit(int level, int bits, int memlevel){
+    dstate=new Deflate(this);
+    return dstate.deflateInit(level, bits, memlevel);
+  }
   public int deflateInit(int level, int bits, boolean nowrap){
-    dstate=new Deflate();
-    return dstate.deflateInit(this, level, nowrap?-bits:bits);
+    dstate=new Deflate(this);
+    return dstate.deflateInit(level, nowrap?-bits:bits);
   }
   public int deflate(int flush){
     if(dstate==null){
       return Z_STREAM_ERROR;
     }
-    return dstate.deflate(this, flush);
+    return dstate.deflate(flush);
   }
   public int deflateEnd(){
     if(dstate==null) return Z_STREAM_ERROR;
@@ -140,12 +165,12 @@
   }
   public int deflateParams(int level, int strategy){
     if(dstate==null) return Z_STREAM_ERROR;
-    return dstate.deflateParams(this, level, strategy);
+    return dstate.deflateParams(level, strategy);
   }
   public int deflateSetDictionary (byte[] dictionary, int dictLength){
     if(dstate == null)
       return Z_STREAM_ERROR;
-    return dstate.deflateSetDictionary(this, dictionary, dictLength);
+    return dstate.deflateSetDictionary(dictionary, dictLength);
   }
 
   // Flush as much pending output as possible. All deflate() output goes
@@ -162,9 +187,9 @@
        next_out.length<=next_out_index ||
        dstate.pending_buf.length<(dstate.pending_out+len) ||
        next_out.length<(next_out_index+len)){
-      System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
-			 ", "+next_out.length+", "+next_out_index+", "+len);
-      System.out.println("avail_out="+avail_out);
+      //System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
+      //		 ", "+next_out.length+", "+next_out_index+", "+len);
+      //System.out.println("avail_out="+avail_out);
     }
 
     System.arraycopy(dstate.pending_buf, dstate.pending_out,
@@ -193,8 +218,8 @@
 
     avail_in-=len;
 
-    if(dstate.noheader==0) {
-      adler=_adler.adler32(adler, next_in, next_in_index, len);
+    if(dstate.wrap!=0) {
+      adler.update(next_in, next_in_index, len);
     }
     System.arraycopy(next_in, next_in_index, buf, start, len);
     next_in_index  += len;
@@ -202,10 +227,117 @@
     return len;
   }
 
+  public long getAdler(){
+    return adler.getValue();
+  }
+
   public void free(){
     next_in=null;
     next_out=null;
     msg=null;
-    _adler=null;
   }
+
+  public void setOutput(byte[] buf){
+    setOutput(buf, 0, buf.length); 
+  }
+
+  public void setOutput(byte[] buf, int off, int len){
+    next_out = buf;
+    next_out_index = off;
+    avail_out = len;
+  }
+
+  public void setInput(byte[] buf){
+    setInput(buf, 0, buf.length, false); 
+  }
+
+  public void setInput(byte[] buf, boolean append){
+    setInput(buf, 0, buf.length, append); 
+  }
+
+  public void setInput(byte[] buf, int off, int len, boolean append){
+    if(len<=0 && append && next_in!=null) return;
+
+    if(avail_in>0 && append){  
+      byte[] tmp = new byte[avail_in+len];
+      System.arraycopy(next_in, next_in_index, tmp, 0, avail_in);
+      System.arraycopy(buf, off, tmp, avail_in, len);
+      next_in=tmp;
+      next_in_index=0;
+      avail_in+=len;
+    }
+    else{
+      next_in=buf;
+      next_in_index=off;
+      avail_in=len;
+    }
+  }
+
+  public byte[] getNextIn(){
+    return next_in;
+  }
+
+  public void setNextIn(byte[] next_in){
+    this.next_in = next_in;
+  }
+
+  public int getNextInIndex(){
+    return next_in_index;
+  }
+
+  public void setNextInIndex(int next_in_index){
+    this.next_in_index = next_in_index;
+  }
+
+  public int getAvailIn(){
+    return avail_in;
+  }
+
+  public void setAvailIn(int avail_in){
+    this.avail_in = avail_in;
+  }
+
+  public byte[] getNextOut(){
+    return next_out;
+  }
+
+  public void setNextOut(byte[] next_out){
+    this.next_out = next_out;
+  }
+
+  public int getNextOutIndex(){
+    return next_out_index;
+  }
+
+  public void setNextOutIndex(int next_out_index){
+    this.next_out_index = next_out_index;
+  }
+
+  public int getAvailOut(){
+    return avail_out;
+
+  }
+
+  public void setAvailOut(int avail_out){
+    this.avail_out = avail_out;
+  }
+
+  public long getTotalOut(){
+    return total_out;
+  }
+
+  public long getTotalIn(){
+    return total_in;
+  }
+
+  public String getMessage(){
+    return msg;
+  }
+
+  /**
+   * Those methods are expected to be override by Inflater and Deflater.
+   * In the future, they will become abstract methods.
+   */ 
+  public int end(){ return Z_OK; }
+  public boolean finished(){ return false; }
 }