Mercurial > 510Connectbot
diff app/src/main/java/com/jcraft/jzlib/Inflate.java @ 438:d29cce60f393
migrate from Eclipse to Android Studio
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 03 Dec 2015 11:23:55 -0800 |
parents | src/com/jcraft/jzlib/Inflate.java@46c2115ae1c8 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/src/main/java/com/jcraft/jzlib/Inflate.java Thu Dec 03 11:23:55 2015 -0800 @@ -0,0 +1,751 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +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: + + 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 + + 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; + + static final int INFLATE_ANY=0x40000000; + + int mode; // current inflate mode + + // mode dependent information + int method; // if FLAGS, method byte + + // if CHECK, check values to compare + long was = -1; // computed check value + long need; // stream check value + + // if BAD, inflateSync's marker bytes count + int marker; + + // mode independent information + int wrap; // flag for no wrapper + // 0: no wrapper + // 1: zlib header + // 2: gzip header + // 4: auto detection + + int wbits; // log2(window size) (8..15, defaults to 15) + + InfBlocks blocks; // current inflate_blocks state + + 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; + this.mode = HEAD; + this.need_bytes = -1; + this.blocks.reset(); + return Z_OK; + } + + int inflateEnd(){ + if(blocks != null){ + blocks.free(); + } + return Z_OK; + } + + Inflate(ZStream z){ + this.z=z; + } + + int inflateInit(int w){ + z.msg = null; + blocks = null; + + // handle undocumented wrap option (no zlib header or check) + wrap = 0; + if(w < 0){ + w = - w; + } + else if((w&INFLATE_ANY) != 0){ + wrap = 4; + w &= ~INFLATE_ANY; + if(w < 48) + w &= 15; + } + else if((w & ~31) != 0) { // for example, DEF_WBITS + 32 + wrap = 4; // zlib and gzip wrapped data should be accepted. + w &= 15; + } + 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 + wbits=w; + + this.blocks=new InfBlocks(z, 1<<w); + + // reset state + inflateReset(); + + return Z_OK; + } + + int inflate(int f){ + int hold = 0; + + int r; + int b; + + 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){ + + switch (this.mode){ + case HEAD: + if(wrap==0){ + this.mode = BLOCKS; + break; + } + + try { r=readBytes(2, r, f); } + catch(Return e){ return e.r; } + + if((wrap == 4 || (wrap&2)!=0) && + this.need == 0x8b1fL) { // gzip header + if(wrap == 4){ + wrap = 2; + } + z.adler=new CRC32(); + checksum(2, this.need); + + if(gheader==null) + gheader=new GZIPHeader(); + + this.mode = FLAGS; + break; + } + + if((wrap&2) != 0){ + this.mode = BAD; + z.msg = "incorrect header check"; + break; + } + + flags = 0; + + this.method = ((int)this.need)&0xff; + b=((int)(this.need>>8))&0xff; + + if(((wrap&1)==0 || // check if zlib header allowed + (((this.method << 8)+b) % 31)!=0) && + (this.method&0xf)!=Z_DEFLATED){ + if(wrap == 4){ + z.next_in_index -= 2; + z.avail_in += 2; + z.total_in -= 2; + wrap = 0; + this.mode = BLOCKS; + break; + } + this.mode = BAD; + z.msg = "incorrect header check"; + // 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(wrap == 4){ + wrap = 1; + } + + 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){ + this.mode = BLOCKS; + break; + } + this.mode = DICT4; + case DICT4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + 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++; + 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++; + 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++; + this.need += (z.next_in[z.next_in_index++]&0xffL); + z.adler.reset(this.need); + this.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + this.mode = BAD; + z.msg = "need dictionary"; + this.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + r = this.blocks.proc(r); + if(r == Z_DATA_ERROR){ + this.mode = BAD; + this.marker = 0; // can try inflateSync + break; + } + if(r == Z_OK){ + r = f; + } + if(r != Z_STREAM_END){ + return r; + } + r = f; + this.was=z.adler.getValue(); + this.blocks.reset(); + if(this.wrap==0){ + this.mode=DONE; + break; + } + this.mode=CHECK4; + case CHECK4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + 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++; + 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++; + 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++; + this.need+=(z.next_in[z.next_in_index++]&0xffL); + + if(flags!=0){ // gzip + this.need = ((this.need&0xff000000)>>24 | + (this.need&0x00ff0000)>>8 | + (this.need&0x0000ff00)<<8 | + (this.need&0x0000ffff)<<24)&0xffffffffL; + } + + 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 index=0; + int length = dictLength; + + 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.reset(); + + if(length >= (1<<this.wbits)){ + length = (1<<this.wbits)-1; + index=dictLength - length; + } + 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(){ + 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) + return Z_STREAM_ERROR; + 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=this.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; + 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.total_in=r; z.total_out = w; + this.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(){ + if(z == null || this.blocks == null) + return Z_STREAM_ERROR; + 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; + } + } +}