Mercurial > 510Connectbot
diff src/com/jcraft/jzlib/Inflate.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children | 46c2115ae1c8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/jcraft/jzlib/Inflate.java Thu May 22 10:41:19 2014 -0700 @@ -0,0 +1,397 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 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 class Inflate { + + static final private int MAX_WBITS = 15; // 32K LZ77 window + + // preset dictionary flag in zlib header + static final private int PRESET_DICT = 0x20; + + static final int Z_NO_FLUSH = 0; + static final int Z_PARTIAL_FLUSH = 1; + static final int Z_SYNC_FLUSH = 2; + static final int Z_FULL_FLUSH = 3; + static final int Z_FINISH = 4; + + static final private int Z_DEFLATED = 8; + + static final private int Z_OK = 0; + static final private int Z_STREAM_END = 1; + static final private int Z_NEED_DICT = 2; + static final private int Z_ERRNO = -1; + static final private int Z_STREAM_ERROR = -2; + static final private int Z_DATA_ERROR = -3; + static final private int Z_MEM_ERROR = -4; + static final private int Z_BUF_ERROR = -5; + static final private int Z_VERSION_ERROR = -6; + + static final private int METHOD = 0; // waiting for method byte + static final private int FLAG = 1; // waiting for flag byte + static final private int DICT4 = 2; // four dictionary check bytes to go + static final private int DICT3 = 3; // three dictionary check bytes to go + static final private int DICT2 = 4; // two dictionary check bytes to go + static final private int DICT1 = 5; // one dictionary check byte to go + static final private int DICT0 = 6; // waiting for inflateSetDictionary + static final private int BLOCKS = 7; // decompressing blocks + static final private int CHECK4 = 8; // four check bytes to go + static final private int CHECK3 = 9; // three check bytes to go + static final private int CHECK2 = 10; // two check bytes to go + static final private int CHECK1 = 11; // one check byte to go + static final private int DONE = 12; // finished check, done + static final private int BAD = 13; // got an error--stay here + + 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 need; // stream check value + + // if BAD, inflateSync's marker bytes count + int marker; + + // mode independent information + int nowrap; // 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; + + 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); + return Z_OK; + } + + int inflateEnd(ZStream z) { + if (blocks != null) + blocks.free(z); + + blocks = null; + // ZFREE(z, z->state); + return Z_OK; + } + + int inflateInit(ZStream z, int w) { + z.msg = null; + blocks = null; + // handle undocumented nowrap option (no zlib header or check) + nowrap = 0; + + if (w < 0) { + w = - w; + nowrap = 1; + } + + // 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); + // reset state + inflateReset(z); + return Z_OK; + } + + int inflate(ZStream z, int f) { + int r; + int b; + + if (z == null || z.istate == null || z.next_in == null) + 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; + + 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 + 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; + + z.avail_in--; z.total_in++; + b = (z.next_in[z.next_in_index++]) & 0xff; + + if ((((z.istate.method << 8) + b) % 31) != 0) { + z.istate.mode = BAD; + z.msg = "incorrect header check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + if ((b & PRESET_DICT) == 0) { + z.istate.mode = BLOCKS; + break; + } + + z.istate.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; + + 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; + + 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; + + 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; + return Z_NEED_DICT; + + case DICT0: + z.istate.mode = BAD; + z.msg = "need dictionary"; + z.istate.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + + case BLOCKS: + r = z.istate.blocks.proc(z, r); + + if (r == Z_DATA_ERROR) { + z.istate.mode = BAD; + z.istate.marker = 0; // can try inflateSync + break; + } + + if (r == Z_OK) { + r = f; + } + + if (r != Z_STREAM_END) { + return r; + } + + r = f; + z.istate.blocks.reset(z, z.istate.was); + + if (z.istate.nowrap != 0) { + z.istate.mode = DONE; + break; + } + + z.istate.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; + + 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; + + 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; + + 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); + + 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; + } + + z.istate.mode = DONE; + + case DONE: + return Z_STREAM_END; + + case BAD: + return Z_DATA_ERROR; + + default: + 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; + } + + z.adler = z._adler.adler32(0, null, 0, 0); + + if (length >= (1 << z.istate.wbits)) { + length = (1 << z.istate.wbits) - 1; + index = dictLength - length; + } + + z.istate.blocks.set_dictionary(dictionary, index, length); + z.istate.mode = BLOCKS; + return Z_OK; + } + + static private byte[] mark = { (byte)0, (byte)0, (byte)0xff, (byte)0xff}; + + int inflateSync(ZStream z) { + 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) + return Z_STREAM_ERROR; + + if (z.istate.mode != BAD) { + z.istate.mode = BAD; + z.istate.marker = 0; + } + + if ((n = z.avail_in) == 0) + return Z_BUF_ERROR; + + p = z.next_in_index; + m = z.istate.marker; + + // search + while (n != 0 && m < 4) { + if (z.next_in[p] == mark[m]) { + m++; + } + else if (z.next_in[p] != 0) { + m = 0; + } + else { + m = 4 - m; + } + + p++; n--; + } + + // restore + z.total_in += p - z.next_in_index; + z.next_in_index = p; + z.avail_in = n; + z.istate.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); + z.total_in = r; z.total_out = w; + z.istate.mode = BLOCKS; + return Z_OK; + } + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + // 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) + return Z_STREAM_ERROR; + + return z.istate.blocks.sync_point(); + } +}