jaroslav@694: /* -*-mode:java; c-basic-offset:2; -*- */ jaroslav@694: /* jaroslav@694: Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. jaroslav@694: jaroslav@694: Redistribution and use in source and binary forms, with or without jaroslav@694: modification, are permitted provided that the following conditions are met: jaroslav@694: jaroslav@694: 1. Redistributions of source code must retain the above copyright notice, jaroslav@694: this list of conditions and the following disclaimer. jaroslav@694: jaroslav@694: 2. Redistributions in binary form must reproduce the above copyright jaroslav@694: notice, this list of conditions and the following disclaimer in jaroslav@694: the documentation and/or other materials provided with the distribution. jaroslav@694: jaroslav@694: 3. The names of the authors may not be used to endorse or promote products jaroslav@694: derived from this software without specific prior written permission. jaroslav@694: jaroslav@694: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, jaroslav@694: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND jaroslav@694: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, jaroslav@694: INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, jaroslav@694: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT jaroslav@694: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, jaroslav@694: OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF jaroslav@694: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING jaroslav@694: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, jaroslav@694: EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jaroslav@694: */ jaroslav@694: /* jaroslav@694: * This program is based on zlib-1.1.3, so all credit should go authors jaroslav@694: * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) jaroslav@694: * and contributors of zlib. jaroslav@694: */ jaroslav@694: jaroslav@694: package org.apidesign.bck2brwsr.emul.zip; jaroslav@694: jaroslav@694: import org.apidesign.bck2brwsr.emul.lang.System; jaroslav@694: jaroslav@694: final class InfCodes{ jaroslav@694: jaroslav@694: static final private int[] inflate_mask = { jaroslav@694: 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, jaroslav@694: 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, jaroslav@694: 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, jaroslav@694: 0x00007fff, 0x0000ffff jaroslav@694: }; jaroslav@694: jaroslav@694: static final private int Z_OK=0; jaroslav@694: static final private int Z_STREAM_END=1; jaroslav@694: static final private int Z_NEED_DICT=2; jaroslav@694: static final private int Z_ERRNO=-1; jaroslav@694: static final private int Z_STREAM_ERROR=-2; jaroslav@694: static final private int Z_DATA_ERROR=-3; jaroslav@694: static final private int Z_MEM_ERROR=-4; jaroslav@694: static final private int Z_BUF_ERROR=-5; jaroslav@694: static final private int Z_VERSION_ERROR=-6; jaroslav@694: jaroslav@694: // waiting for "i:"=input, jaroslav@694: // "o:"=output, jaroslav@694: // "x:"=nothing jaroslav@694: static final private int START=0; // x: set up for LEN jaroslav@694: static final private int LEN=1; // i: get length/literal/eob next jaroslav@694: static final private int LENEXT=2; // i: getting length extra (have base) jaroslav@694: static final private int DIST=3; // i: get distance next jaroslav@694: static final private int DISTEXT=4;// i: getting distance extra jaroslav@694: static final private int COPY=5; // o: copying bytes in window, waiting for space jaroslav@694: static final private int LIT=6; // o: got literal, waiting for output space jaroslav@694: static final private int WASH=7; // o: got eob, possibly still output waiting jaroslav@694: static final private int END=8; // x: got eob and all data flushed jaroslav@694: static final private int BADCODE=9;// x: got error jaroslav@694: jaroslav@694: int mode; // current inflate_codes mode jaroslav@694: jaroslav@694: // mode dependent information jaroslav@694: int len; jaroslav@694: jaroslav@694: int[] tree; // pointer into tree jaroslav@694: int tree_index=0; jaroslav@694: int need; // bits needed jaroslav@694: jaroslav@694: int lit; jaroslav@694: jaroslav@694: // if EXT or COPY, where and how much jaroslav@694: int get; // bits to get for extra jaroslav@694: int dist; // distance back to copy from jaroslav@694: jaroslav@694: byte lbits; // ltree bits decoded per branch jaroslav@694: byte dbits; // dtree bits decoder per branch jaroslav@694: int[] ltree; // literal/length/eob tree jaroslav@694: int ltree_index; // literal/length/eob tree jaroslav@694: int[] dtree; // distance tree jaroslav@694: int dtree_index; // distance tree jaroslav@694: jaroslav@694: private final ZStream z; jaroslav@694: private final InfBlocks s; jaroslav@694: InfCodes(ZStream z, InfBlocks s){ jaroslav@694: this.z=z; jaroslav@694: this.s=s; jaroslav@694: } jaroslav@694: jaroslav@694: void init(int bl, int bd, jaroslav@694: int[] tl, int tl_index, jaroslav@694: int[] td, int td_index){ jaroslav@694: mode=START; jaroslav@694: lbits=(byte)bl; jaroslav@694: dbits=(byte)bd; jaroslav@694: ltree=tl; jaroslav@694: ltree_index=tl_index; jaroslav@694: dtree = td; jaroslav@694: dtree_index=td_index; jaroslav@694: tree=null; jaroslav@694: } jaroslav@694: jaroslav@694: int proc(int r){ jaroslav@694: int j; // temporary storage jaroslav@694: int[] t; // temporary pointer jaroslav@694: int tindex; // temporary pointer jaroslav@694: int e; // extra bits or operation jaroslav@694: int b=0; // bit buffer jaroslav@694: int k=0; // bits in bit buffer jaroslav@694: int p=0; // input data pointer jaroslav@694: int n; // bytes available there jaroslav@694: int q; // output window write pointer jaroslav@694: int m; // bytes to end of window or read pointer jaroslav@694: int f; // pointer to copy strings from jaroslav@694: jaroslav@694: // copy input/output information to locals (UPDATE macro restores) jaroslav@694: p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; jaroslav@694: q=s.write;m=q= 258 && n >= 10){ jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: r = inflate_fast(lbits, dbits, jaroslav@694: ltree, ltree_index, jaroslav@694: dtree, dtree_index, jaroslav@694: s, z); jaroslav@694: jaroslav@694: p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; jaroslav@694: q=s.write;m=q>>=(tree[tindex+1]); jaroslav@694: k-=(tree[tindex+1]); jaroslav@694: jaroslav@694: e=tree[tindex]; jaroslav@694: jaroslav@694: if(e == 0){ // literal jaroslav@694: lit = tree[tindex+2]; jaroslav@694: mode = LIT; jaroslav@694: break; jaroslav@694: } jaroslav@694: if((e & 16)!=0 ){ // length jaroslav@694: get = e & 15; jaroslav@694: len = tree[tindex+2]; jaroslav@694: mode = LENEXT; jaroslav@694: break; jaroslav@694: } jaroslav@694: if ((e & 64) == 0){ // next table jaroslav@694: need = e; jaroslav@694: tree_index = tindex/3+tree[tindex+2]; jaroslav@694: break; jaroslav@694: } jaroslav@694: if ((e & 32)!=0){ // end of block jaroslav@694: mode = WASH; jaroslav@694: break; jaroslav@694: } jaroslav@694: mode = BADCODE; // invalid code jaroslav@694: z.msg = "invalid literal/length code"; jaroslav@694: r = Z_DATA_ERROR; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: return s.inflate_flush(r); jaroslav@694: jaroslav@694: case LENEXT: // i: getting length extra (have base) jaroslav@694: j = get; jaroslav@694: jaroslav@694: while(k<(j)){ jaroslav@694: if(n!=0)r=Z_OK; jaroslav@694: else{ jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: return s.inflate_flush(r); jaroslav@694: } jaroslav@694: n--; b|=(z.next_in[p++]&0xff)<>=j; jaroslav@694: k-=j; jaroslav@694: jaroslav@694: need = dbits; jaroslav@694: tree = dtree; jaroslav@694: tree_index=dtree_index; jaroslav@694: mode = DIST; jaroslav@694: case DIST: // i: get distance next jaroslav@694: j = need; jaroslav@694: jaroslav@694: while(k<(j)){ jaroslav@694: if(n!=0)r=Z_OK; jaroslav@694: else{ jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: return s.inflate_flush(r); jaroslav@694: } jaroslav@694: n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1]; jaroslav@694: k-=tree[tindex+1]; jaroslav@694: jaroslav@694: e = (tree[tindex]); jaroslav@694: if((e & 16)!=0){ // distance jaroslav@694: get = e & 15; jaroslav@694: dist = tree[tindex+2]; jaroslav@694: mode = DISTEXT; jaroslav@694: break; jaroslav@694: } jaroslav@694: if ((e & 64) == 0){ // next table jaroslav@694: need = e; jaroslav@694: tree_index = tindex/3 + tree[tindex+2]; jaroslav@694: break; jaroslav@694: } jaroslav@694: mode = BADCODE; // invalid code jaroslav@694: z.msg = "invalid distance code"; jaroslav@694: r = Z_DATA_ERROR; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: return s.inflate_flush(r); jaroslav@694: jaroslav@694: case DISTEXT: // i: getting distance extra jaroslav@694: j = get; jaroslav@694: jaroslav@694: while(k<(j)){ jaroslav@694: if(n!=0)r=Z_OK; jaroslav@694: else{ jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: return s.inflate_flush(r); jaroslav@694: } jaroslav@694: n--; b|=(z.next_in[p++]&0xff)<>=j; jaroslav@694: k-=j; jaroslav@694: jaroslav@694: mode = COPY; jaroslav@694: case COPY: // o: copying bytes in window, waiting for space jaroslav@694: f = q - dist; jaroslav@694: while(f < 0){ // modulo window size-"while" instead jaroslav@694: f += s.end; // of "if" handles invalid distances jaroslav@694: } jaroslav@694: while (len!=0){ jaroslav@694: jaroslav@694: if(m==0){ jaroslav@694: if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any jaroslav@694: k -= 8; jaroslav@694: n++; jaroslav@694: p--; // can always return one jaroslav@694: } jaroslav@694: jaroslav@694: s.write=q; r=s.inflate_flush(r); jaroslav@694: q=s.write;m=q= 258 && n >= 10 jaroslav@694: // get literal/length code jaroslav@694: while(k<(20)){ // max bits for literal/length code jaroslav@694: n--; jaroslav@694: b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); jaroslav@694: jaroslav@694: s.window[q++] = (byte)tp[tp_index_t_3+2]; jaroslav@694: m--; jaroslav@694: continue; jaroslav@694: } jaroslav@694: do { jaroslav@694: jaroslav@694: b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); jaroslav@694: jaroslav@694: if((e&16)!=0){ jaroslav@694: e &= 15; jaroslav@694: c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); jaroslav@694: jaroslav@694: b>>=e; k-=e; jaroslav@694: jaroslav@694: // decode distance base of block to copy jaroslav@694: while(k<(15)){ // max bits for distance code jaroslav@694: n--; jaroslav@694: b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); jaroslav@694: jaroslav@694: if((e&16)!=0){ jaroslav@694: // get extra bits to add to distance base jaroslav@694: e &= 15; jaroslav@694: while(k<(e)){ // get extra bits (up to 13) jaroslav@694: n--; jaroslav@694: b|=(z.next_in[p++]&0xff)<>=(e); k-=(e); jaroslav@694: jaroslav@694: // do the copy jaroslav@694: m -= c; jaroslav@694: if (q >= d){ // offset before dest jaroslav@694: // just copy jaroslav@694: r=q-d; jaroslav@694: if(q-r>0 && 2>(q-r)){ jaroslav@694: s.window[q++]=s.window[r++]; // minimum count is three, jaroslav@694: s.window[q++]=s.window[r++]; // so unroll loop a little jaroslav@694: c-=2; jaroslav@694: } jaroslav@694: else{ jaroslav@694: System.arraycopy(s.window, r, s.window, q, 2); jaroslav@694: q+=2; r+=2; c-=2; jaroslav@694: } jaroslav@694: } jaroslav@694: else{ // else offset after destination jaroslav@694: r=q-d; jaroslav@694: do{ jaroslav@694: r+=s.end; // force pointer in window jaroslav@694: }while(r<0); // covers invalid distances jaroslav@694: e=s.end-r; jaroslav@694: if(c>e){ // if source crosses, jaroslav@694: c-=e; // wrapped copy jaroslav@694: if(q-r>0 && e>(q-r)){ jaroslav@694: do{s.window[q++] = s.window[r++];} jaroslav@694: while(--e!=0); jaroslav@694: } jaroslav@694: else{ jaroslav@694: System.arraycopy(s.window, r, s.window, q, e); jaroslav@694: q+=e; r+=e; e=0; jaroslav@694: } jaroslav@694: r = 0; // copy rest from start of window jaroslav@694: } jaroslav@694: jaroslav@694: } jaroslav@694: jaroslav@694: // copy all or what's left jaroslav@694: if(q-r>0 && c>(q-r)){ jaroslav@694: do{s.window[q++] = s.window[r++];} jaroslav@694: while(--c!=0); jaroslav@694: } jaroslav@694: else{ jaroslav@694: System.arraycopy(s.window, r, s.window, q, c); jaroslav@694: q+=c; r+=c; c=0; jaroslav@694: } jaroslav@694: break; jaroslav@694: } jaroslav@694: else if((e&64)==0){ jaroslav@694: t+=tp[tp_index_t_3+2]; jaroslav@694: t+=(b&inflate_mask[e]); jaroslav@694: tp_index_t_3=(tp_index+t)*3; jaroslav@694: e=tp[tp_index_t_3]; jaroslav@694: } jaroslav@694: else{ jaroslav@694: z.msg = "invalid distance code"; jaroslav@694: jaroslav@694: c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: jaroslav@694: return Z_DATA_ERROR; jaroslav@694: } jaroslav@694: } jaroslav@694: while(true); jaroslav@694: break; jaroslav@694: } jaroslav@694: jaroslav@694: if((e&64)==0){ jaroslav@694: t+=tp[tp_index_t_3+2]; jaroslav@694: t+=(b&inflate_mask[e]); jaroslav@694: tp_index_t_3=(tp_index+t)*3; jaroslav@694: if((e=tp[tp_index_t_3])==0){ jaroslav@694: jaroslav@694: b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); jaroslav@694: jaroslav@694: s.window[q++]=(byte)tp[tp_index_t_3+2]; jaroslav@694: m--; jaroslav@694: break; jaroslav@694: } jaroslav@694: } jaroslav@694: else if((e&32)!=0){ jaroslav@694: jaroslav@694: c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: jaroslav@694: return Z_STREAM_END; jaroslav@694: } jaroslav@694: else{ jaroslav@694: z.msg="invalid literal/length code"; jaroslav@694: jaroslav@694: c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: jaroslav@694: return Z_DATA_ERROR; jaroslav@694: } jaroslav@694: } jaroslav@694: while(true); jaroslav@694: } jaroslav@694: while(m>=258 && n>= 10); jaroslav@694: jaroslav@694: // not enough input or output--restore pointers and return jaroslav@694: c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; jaroslav@694: jaroslav@694: s.bitb=b;s.bitk=k; jaroslav@694: z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; jaroslav@694: s.write=q; jaroslav@694: jaroslav@694: return Z_OK; jaroslav@694: } jaroslav@694: }