emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/InfCodes.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 07 Feb 2013 12:58:12 +0100
branchemul
changeset 694 0d277415ed02
permissions -rw-r--r--
Rebasing the Inflater support on jzlib which, unlike GNU ClassPath, has correct implementation of Huffman code. Making the implementation more easily testable by turning Inflater and ZipInputStream into pure delegates. Current implementation is going to need proper long support.
jaroslav@694
     1
/* -*-mode:java; c-basic-offset:2; -*- */
jaroslav@694
     2
/*
jaroslav@694
     3
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
jaroslav@694
     4
jaroslav@694
     5
Redistribution and use in source and binary forms, with or without
jaroslav@694
     6
modification, are permitted provided that the following conditions are met:
jaroslav@694
     7
jaroslav@694
     8
  1. Redistributions of source code must retain the above copyright notice,
jaroslav@694
     9
     this list of conditions and the following disclaimer.
jaroslav@694
    10
jaroslav@694
    11
  2. Redistributions in binary form must reproduce the above copyright 
jaroslav@694
    12
     notice, this list of conditions and the following disclaimer in 
jaroslav@694
    13
     the documentation and/or other materials provided with the distribution.
jaroslav@694
    14
jaroslav@694
    15
  3. The names of the authors may not be used to endorse or promote products
jaroslav@694
    16
     derived from this software without specific prior written permission.
jaroslav@694
    17
jaroslav@694
    18
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
jaroslav@694
    19
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
jaroslav@694
    20
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
jaroslav@694
    21
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
jaroslav@694
    22
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
jaroslav@694
    23
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
jaroslav@694
    24
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
jaroslav@694
    25
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
jaroslav@694
    26
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
jaroslav@694
    27
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jaroslav@694
    28
 */
jaroslav@694
    29
/*
jaroslav@694
    30
 * This program is based on zlib-1.1.3, so all credit should go authors
jaroslav@694
    31
 * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
jaroslav@694
    32
 * and contributors of zlib.
jaroslav@694
    33
 */
jaroslav@694
    34
jaroslav@694
    35
package org.apidesign.bck2brwsr.emul.zip;
jaroslav@694
    36
jaroslav@694
    37
import org.apidesign.bck2brwsr.emul.lang.System;
jaroslav@694
    38
jaroslav@694
    39
final class InfCodes{
jaroslav@694
    40
jaroslav@694
    41
  static final private int[] inflate_mask = {
jaroslav@694
    42
    0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
jaroslav@694
    43
    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
jaroslav@694
    44
    0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
jaroslav@694
    45
    0x00007fff, 0x0000ffff
jaroslav@694
    46
  };
jaroslav@694
    47
jaroslav@694
    48
  static final private int Z_OK=0;
jaroslav@694
    49
  static final private int Z_STREAM_END=1;
jaroslav@694
    50
  static final private int Z_NEED_DICT=2;
jaroslav@694
    51
  static final private int Z_ERRNO=-1;
jaroslav@694
    52
  static final private int Z_STREAM_ERROR=-2;
jaroslav@694
    53
  static final private int Z_DATA_ERROR=-3;
jaroslav@694
    54
  static final private int Z_MEM_ERROR=-4;
jaroslav@694
    55
  static final private int Z_BUF_ERROR=-5;
jaroslav@694
    56
  static final private int Z_VERSION_ERROR=-6;
jaroslav@694
    57
jaroslav@694
    58
  // waiting for "i:"=input,
jaroslav@694
    59
  //             "o:"=output,
jaroslav@694
    60
  //             "x:"=nothing
jaroslav@694
    61
  static final private int START=0;  // x: set up for LEN
jaroslav@694
    62
  static final private int LEN=1;    // i: get length/literal/eob next
jaroslav@694
    63
  static final private int LENEXT=2; // i: getting length extra (have base)
jaroslav@694
    64
  static final private int DIST=3;   // i: get distance next
jaroslav@694
    65
  static final private int DISTEXT=4;// i: getting distance extra
jaroslav@694
    66
  static final private int COPY=5;   // o: copying bytes in window, waiting for space
jaroslav@694
    67
  static final private int LIT=6;    // o: got literal, waiting for output space
jaroslav@694
    68
  static final private int WASH=7;   // o: got eob, possibly still output waiting
jaroslav@694
    69
  static final private int END=8;    // x: got eob and all data flushed
jaroslav@694
    70
  static final private int BADCODE=9;// x: got error
jaroslav@694
    71
jaroslav@694
    72
  int mode;      // current inflate_codes mode
jaroslav@694
    73
jaroslav@694
    74
  // mode dependent information
jaroslav@694
    75
  int len;
jaroslav@694
    76
jaroslav@694
    77
  int[] tree; // pointer into tree
jaroslav@694
    78
  int tree_index=0;
jaroslav@694
    79
  int need;   // bits needed
jaroslav@694
    80
jaroslav@694
    81
  int lit;
jaroslav@694
    82
jaroslav@694
    83
  // if EXT or COPY, where and how much
jaroslav@694
    84
  int get;              // bits to get for extra
jaroslav@694
    85
  int dist;             // distance back to copy from
jaroslav@694
    86
jaroslav@694
    87
  byte lbits;           // ltree bits decoded per branch
jaroslav@694
    88
  byte dbits;           // dtree bits decoder per branch
jaroslav@694
    89
  int[] ltree;          // literal/length/eob tree
jaroslav@694
    90
  int ltree_index;      // literal/length/eob tree
jaroslav@694
    91
  int[] dtree;          // distance tree
jaroslav@694
    92
  int dtree_index;      // distance tree
jaroslav@694
    93
jaroslav@694
    94
  private final ZStream z;
jaroslav@694
    95
  private final InfBlocks s;
jaroslav@694
    96
  InfCodes(ZStream z, InfBlocks s){
jaroslav@694
    97
    this.z=z; 
jaroslav@694
    98
    this.s=s; 
jaroslav@694
    99
  }
jaroslav@694
   100
jaroslav@694
   101
  void init(int bl, int bd,
jaroslav@694
   102
	   int[] tl, int tl_index,
jaroslav@694
   103
	   int[] td, int td_index){
jaroslav@694
   104
    mode=START;
jaroslav@694
   105
    lbits=(byte)bl;
jaroslav@694
   106
    dbits=(byte)bd;
jaroslav@694
   107
    ltree=tl;
jaroslav@694
   108
    ltree_index=tl_index;
jaroslav@694
   109
    dtree = td;
jaroslav@694
   110
    dtree_index=td_index;
jaroslav@694
   111
    tree=null;
jaroslav@694
   112
  }
jaroslav@694
   113
jaroslav@694
   114
  int proc(int r){ 
jaroslav@694
   115
    int j;              // temporary storage
jaroslav@694
   116
    int[] t;            // temporary pointer
jaroslav@694
   117
    int tindex;         // temporary pointer
jaroslav@694
   118
    int e;              // extra bits or operation
jaroslav@694
   119
    int b=0;            // bit buffer
jaroslav@694
   120
    int k=0;            // bits in bit buffer
jaroslav@694
   121
    int p=0;            // input data pointer
jaroslav@694
   122
    int n;              // bytes available there
jaroslav@694
   123
    int q;              // output window write pointer
jaroslav@694
   124
    int m;              // bytes to end of window or read pointer
jaroslav@694
   125
    int f;              // pointer to copy strings from
jaroslav@694
   126
jaroslav@694
   127
    // copy input/output information to locals (UPDATE macro restores)
jaroslav@694
   128
    p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
jaroslav@694
   129
    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   130
jaroslav@694
   131
    // process input and output based on current state
jaroslav@694
   132
    while (true){
jaroslav@694
   133
      switch (mode){
jaroslav@694
   134
	// waiting for "i:"=input, "o:"=output, "x:"=nothing
jaroslav@694
   135
      case START:         // x: set up for LEN
jaroslav@694
   136
	if (m >= 258 && n >= 10){
jaroslav@694
   137
jaroslav@694
   138
	  s.bitb=b;s.bitk=k;
jaroslav@694
   139
	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   140
	  s.write=q;
jaroslav@694
   141
	  r = inflate_fast(lbits, dbits, 
jaroslav@694
   142
			   ltree, ltree_index, 
jaroslav@694
   143
			   dtree, dtree_index,
jaroslav@694
   144
			   s, z);
jaroslav@694
   145
jaroslav@694
   146
	  p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
jaroslav@694
   147
	  q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   148
jaroslav@694
   149
	  if (r != Z_OK){
jaroslav@694
   150
	    mode = r == Z_STREAM_END ? WASH : BADCODE;
jaroslav@694
   151
	    break;
jaroslav@694
   152
	  }
jaroslav@694
   153
	}
jaroslav@694
   154
	need = lbits;
jaroslav@694
   155
	tree = ltree;
jaroslav@694
   156
	tree_index=ltree_index;
jaroslav@694
   157
jaroslav@694
   158
	mode = LEN;
jaroslav@694
   159
      case LEN:           // i: get length/literal/eob next
jaroslav@694
   160
	j = need;
jaroslav@694
   161
jaroslav@694
   162
	while(k<(j)){
jaroslav@694
   163
	  if(n!=0)r=Z_OK;
jaroslav@694
   164
	  else{
jaroslav@694
   165
jaroslav@694
   166
	    s.bitb=b;s.bitk=k;
jaroslav@694
   167
	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   168
	    s.write=q;
jaroslav@694
   169
	    return s.inflate_flush(r);
jaroslav@694
   170
	  }
jaroslav@694
   171
	  n--;
jaroslav@694
   172
	  b|=(z.next_in[p++]&0xff)<<k;
jaroslav@694
   173
	  k+=8;
jaroslav@694
   174
	}
jaroslav@694
   175
jaroslav@694
   176
	tindex=(tree_index+(b&inflate_mask[j]))*3;
jaroslav@694
   177
jaroslav@694
   178
	b>>>=(tree[tindex+1]);
jaroslav@694
   179
	k-=(tree[tindex+1]);
jaroslav@694
   180
jaroslav@694
   181
	e=tree[tindex];
jaroslav@694
   182
jaroslav@694
   183
	if(e == 0){               // literal
jaroslav@694
   184
	  lit = tree[tindex+2];
jaroslav@694
   185
	  mode = LIT;
jaroslav@694
   186
	  break;
jaroslav@694
   187
	}
jaroslav@694
   188
	if((e & 16)!=0 ){          // length
jaroslav@694
   189
	  get = e & 15;
jaroslav@694
   190
	  len = tree[tindex+2];
jaroslav@694
   191
	  mode = LENEXT;
jaroslav@694
   192
	  break;
jaroslav@694
   193
	}
jaroslav@694
   194
	if ((e & 64) == 0){        // next table
jaroslav@694
   195
	  need = e;
jaroslav@694
   196
	  tree_index = tindex/3+tree[tindex+2];
jaroslav@694
   197
	  break;
jaroslav@694
   198
	}
jaroslav@694
   199
	if ((e & 32)!=0){               // end of block
jaroslav@694
   200
	  mode = WASH;
jaroslav@694
   201
	  break;
jaroslav@694
   202
	}
jaroslav@694
   203
	mode = BADCODE;        // invalid code
jaroslav@694
   204
	z.msg = "invalid literal/length code";
jaroslav@694
   205
	r = Z_DATA_ERROR;
jaroslav@694
   206
jaroslav@694
   207
	s.bitb=b;s.bitk=k;
jaroslav@694
   208
	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   209
	s.write=q;
jaroslav@694
   210
	return s.inflate_flush(r);
jaroslav@694
   211
jaroslav@694
   212
      case LENEXT:        // i: getting length extra (have base)
jaroslav@694
   213
	j = get;
jaroslav@694
   214
jaroslav@694
   215
	while(k<(j)){
jaroslav@694
   216
	  if(n!=0)r=Z_OK;
jaroslav@694
   217
	  else{
jaroslav@694
   218
jaroslav@694
   219
	    s.bitb=b;s.bitk=k;
jaroslav@694
   220
	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   221
	    s.write=q;
jaroslav@694
   222
	    return s.inflate_flush(r);
jaroslav@694
   223
	  }
jaroslav@694
   224
	  n--; b|=(z.next_in[p++]&0xff)<<k;
jaroslav@694
   225
	  k+=8;
jaroslav@694
   226
	}
jaroslav@694
   227
jaroslav@694
   228
	len += (b & inflate_mask[j]);
jaroslav@694
   229
jaroslav@694
   230
	b>>=j;
jaroslav@694
   231
	k-=j;
jaroslav@694
   232
jaroslav@694
   233
	need = dbits;
jaroslav@694
   234
	tree = dtree;
jaroslav@694
   235
	tree_index=dtree_index;
jaroslav@694
   236
	mode = DIST;
jaroslav@694
   237
      case DIST:          // i: get distance next
jaroslav@694
   238
	j = need;
jaroslav@694
   239
jaroslav@694
   240
	while(k<(j)){
jaroslav@694
   241
	  if(n!=0)r=Z_OK;
jaroslav@694
   242
	  else{
jaroslav@694
   243
jaroslav@694
   244
	    s.bitb=b;s.bitk=k;
jaroslav@694
   245
	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   246
	    s.write=q;
jaroslav@694
   247
	    return s.inflate_flush(r);
jaroslav@694
   248
	  }
jaroslav@694
   249
	  n--; b|=(z.next_in[p++]&0xff)<<k;
jaroslav@694
   250
	  k+=8;
jaroslav@694
   251
	}
jaroslav@694
   252
jaroslav@694
   253
	tindex=(tree_index+(b & inflate_mask[j]))*3;
jaroslav@694
   254
jaroslav@694
   255
	b>>=tree[tindex+1];
jaroslav@694
   256
	k-=tree[tindex+1];
jaroslav@694
   257
jaroslav@694
   258
	e = (tree[tindex]);
jaroslav@694
   259
	if((e & 16)!=0){               // distance
jaroslav@694
   260
	  get = e & 15;
jaroslav@694
   261
	  dist = tree[tindex+2];
jaroslav@694
   262
	  mode = DISTEXT;
jaroslav@694
   263
	  break;
jaroslav@694
   264
	}
jaroslav@694
   265
	if ((e & 64) == 0){        // next table
jaroslav@694
   266
	  need = e;
jaroslav@694
   267
	  tree_index = tindex/3 + tree[tindex+2];
jaroslav@694
   268
	  break;
jaroslav@694
   269
	}
jaroslav@694
   270
	mode = BADCODE;        // invalid code
jaroslav@694
   271
	z.msg = "invalid distance code";
jaroslav@694
   272
	r = Z_DATA_ERROR;
jaroslav@694
   273
jaroslav@694
   274
	s.bitb=b;s.bitk=k;
jaroslav@694
   275
	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   276
	s.write=q;
jaroslav@694
   277
	return s.inflate_flush(r);
jaroslav@694
   278
jaroslav@694
   279
      case DISTEXT:       // i: getting distance extra
jaroslav@694
   280
	j = get;
jaroslav@694
   281
jaroslav@694
   282
	while(k<(j)){
jaroslav@694
   283
	  if(n!=0)r=Z_OK;
jaroslav@694
   284
	  else{
jaroslav@694
   285
jaroslav@694
   286
	    s.bitb=b;s.bitk=k;
jaroslav@694
   287
	    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   288
	    s.write=q;
jaroslav@694
   289
	    return s.inflate_flush(r);
jaroslav@694
   290
	  }
jaroslav@694
   291
	  n--; b|=(z.next_in[p++]&0xff)<<k;
jaroslav@694
   292
	  k+=8;
jaroslav@694
   293
	}
jaroslav@694
   294
jaroslav@694
   295
	dist += (b & inflate_mask[j]);
jaroslav@694
   296
jaroslav@694
   297
	b>>=j;
jaroslav@694
   298
	k-=j;
jaroslav@694
   299
jaroslav@694
   300
	mode = COPY;
jaroslav@694
   301
      case COPY:          // o: copying bytes in window, waiting for space
jaroslav@694
   302
        f = q - dist;
jaroslav@694
   303
        while(f < 0){     // modulo window size-"while" instead
jaroslav@694
   304
          f += s.end;     // of "if" handles invalid distances
jaroslav@694
   305
	}
jaroslav@694
   306
	while (len!=0){
jaroslav@694
   307
jaroslav@694
   308
	  if(m==0){
jaroslav@694
   309
	    if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
jaroslav@694
   310
	    if(m==0){
jaroslav@694
   311
	      s.write=q; r=s.inflate_flush(r);
jaroslav@694
   312
	      q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   313
jaroslav@694
   314
	      if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
jaroslav@694
   315
jaroslav@694
   316
	      if(m==0){
jaroslav@694
   317
		s.bitb=b;s.bitk=k;
jaroslav@694
   318
		z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   319
		s.write=q;
jaroslav@694
   320
		return s.inflate_flush(r);
jaroslav@694
   321
	      }  
jaroslav@694
   322
	    }
jaroslav@694
   323
	  }
jaroslav@694
   324
jaroslav@694
   325
	  s.window[q++]=s.window[f++]; m--;
jaroslav@694
   326
jaroslav@694
   327
	  if (f == s.end)
jaroslav@694
   328
            f = 0;
jaroslav@694
   329
	  len--;
jaroslav@694
   330
	}
jaroslav@694
   331
	mode = START;
jaroslav@694
   332
	break;
jaroslav@694
   333
      case LIT:           // o: got literal, waiting for output space
jaroslav@694
   334
	if(m==0){
jaroslav@694
   335
	  if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
jaroslav@694
   336
	  if(m==0){
jaroslav@694
   337
	    s.write=q; r=s.inflate_flush(r);
jaroslav@694
   338
	    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   339
jaroslav@694
   340
	    if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
jaroslav@694
   341
	    if(m==0){
jaroslav@694
   342
	      s.bitb=b;s.bitk=k;
jaroslav@694
   343
	      z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   344
	      s.write=q;
jaroslav@694
   345
	      return s.inflate_flush(r);
jaroslav@694
   346
	    }
jaroslav@694
   347
	  }
jaroslav@694
   348
	}
jaroslav@694
   349
	r=Z_OK;
jaroslav@694
   350
jaroslav@694
   351
	s.window[q++]=(byte)lit; m--;
jaroslav@694
   352
jaroslav@694
   353
	mode = START;
jaroslav@694
   354
	break;
jaroslav@694
   355
      case WASH:           // o: got eob, possibly more output
jaroslav@694
   356
	if (k > 7){        // return unused byte, if any
jaroslav@694
   357
	  k -= 8;
jaroslav@694
   358
	  n++;
jaroslav@694
   359
	  p--;             // can always return one
jaroslav@694
   360
	}
jaroslav@694
   361
jaroslav@694
   362
	s.write=q; r=s.inflate_flush(r);
jaroslav@694
   363
	q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   364
jaroslav@694
   365
	if (s.read != s.write){
jaroslav@694
   366
	  s.bitb=b;s.bitk=k;
jaroslav@694
   367
	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   368
	  s.write=q;
jaroslav@694
   369
	  return s.inflate_flush(r);
jaroslav@694
   370
	}
jaroslav@694
   371
	mode = END;
jaroslav@694
   372
      case END:
jaroslav@694
   373
	r = Z_STREAM_END;
jaroslav@694
   374
	s.bitb=b;s.bitk=k;
jaroslav@694
   375
	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   376
	s.write=q;
jaroslav@694
   377
	return s.inflate_flush(r);
jaroslav@694
   378
jaroslav@694
   379
      case BADCODE:       // x: got error
jaroslav@694
   380
jaroslav@694
   381
	r = Z_DATA_ERROR;
jaroslav@694
   382
jaroslav@694
   383
	s.bitb=b;s.bitk=k;
jaroslav@694
   384
	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   385
	s.write=q;
jaroslav@694
   386
	return s.inflate_flush(r);
jaroslav@694
   387
jaroslav@694
   388
      default:
jaroslav@694
   389
	r = Z_STREAM_ERROR;
jaroslav@694
   390
jaroslav@694
   391
	s.bitb=b;s.bitk=k;
jaroslav@694
   392
	z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   393
	s.write=q;
jaroslav@694
   394
	return s.inflate_flush(r);
jaroslav@694
   395
      }
jaroslav@694
   396
    }
jaroslav@694
   397
  }
jaroslav@694
   398
jaroslav@694
   399
  void free(ZStream z){
jaroslav@694
   400
    //  ZFREE(z, c);
jaroslav@694
   401
  }
jaroslav@694
   402
jaroslav@694
   403
  // Called with number of bytes left to write in window at least 258
jaroslav@694
   404
  // (the maximum string length) and number of input bytes available
jaroslav@694
   405
  // at least ten.  The ten bytes are six bytes for the longest length/
jaroslav@694
   406
  // distance pair plus four bytes for overloading the bit buffer.
jaroslav@694
   407
jaroslav@694
   408
  int inflate_fast(int bl, int bd, 
jaroslav@694
   409
		   int[] tl, int tl_index,
jaroslav@694
   410
		   int[] td, int td_index,
jaroslav@694
   411
		   InfBlocks s, ZStream z){
jaroslav@694
   412
    int t;                // temporary pointer
jaroslav@694
   413
    int[] tp;             // temporary pointer
jaroslav@694
   414
    int tp_index;         // temporary pointer
jaroslav@694
   415
    int e;                // extra bits or operation
jaroslav@694
   416
    int b;                // bit buffer
jaroslav@694
   417
    int k;                // bits in bit buffer
jaroslav@694
   418
    int p;                // input data pointer
jaroslav@694
   419
    int n;                // bytes available there
jaroslav@694
   420
    int q;                // output window write pointer
jaroslav@694
   421
    int m;                // bytes to end of window or read pointer
jaroslav@694
   422
    int ml;               // mask for literal/length tree
jaroslav@694
   423
    int md;               // mask for distance tree
jaroslav@694
   424
    int c;                // bytes to copy
jaroslav@694
   425
    int d;                // distance back to copy from
jaroslav@694
   426
    int r;                // copy source pointer
jaroslav@694
   427
jaroslav@694
   428
    int tp_index_t_3;     // (tp_index+t)*3
jaroslav@694
   429
jaroslav@694
   430
    // load input, output, bit values
jaroslav@694
   431
    p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
jaroslav@694
   432
    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
jaroslav@694
   433
jaroslav@694
   434
    // initialize masks
jaroslav@694
   435
    ml = inflate_mask[bl];
jaroslav@694
   436
    md = inflate_mask[bd];
jaroslav@694
   437
jaroslav@694
   438
    // do until not enough input or output space for fast loop
jaroslav@694
   439
    do {                          // assume called with m >= 258 && n >= 10
jaroslav@694
   440
      // get literal/length code
jaroslav@694
   441
      while(k<(20)){              // max bits for literal/length code
jaroslav@694
   442
	n--;
jaroslav@694
   443
	b|=(z.next_in[p++]&0xff)<<k;k+=8;
jaroslav@694
   444
      }
jaroslav@694
   445
jaroslav@694
   446
      t= b&ml;
jaroslav@694
   447
      tp=tl; 
jaroslav@694
   448
      tp_index=tl_index;
jaroslav@694
   449
      tp_index_t_3=(tp_index+t)*3;
jaroslav@694
   450
      if ((e = tp[tp_index_t_3]) == 0){
jaroslav@694
   451
	b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
jaroslav@694
   452
jaroslav@694
   453
	s.window[q++] = (byte)tp[tp_index_t_3+2];
jaroslav@694
   454
	m--;
jaroslav@694
   455
	continue;
jaroslav@694
   456
      }
jaroslav@694
   457
      do {
jaroslav@694
   458
jaroslav@694
   459
	b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
jaroslav@694
   460
jaroslav@694
   461
	if((e&16)!=0){
jaroslav@694
   462
	  e &= 15;
jaroslav@694
   463
	  c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
jaroslav@694
   464
jaroslav@694
   465
	  b>>=e; k-=e;
jaroslav@694
   466
jaroslav@694
   467
	  // decode distance base of block to copy
jaroslav@694
   468
	  while(k<(15)){           // max bits for distance code
jaroslav@694
   469
	    n--;
jaroslav@694
   470
	    b|=(z.next_in[p++]&0xff)<<k;k+=8;
jaroslav@694
   471
	  }
jaroslav@694
   472
jaroslav@694
   473
	  t= b&md;
jaroslav@694
   474
	  tp=td;
jaroslav@694
   475
	  tp_index=td_index;
jaroslav@694
   476
          tp_index_t_3=(tp_index+t)*3;
jaroslav@694
   477
	  e = tp[tp_index_t_3];
jaroslav@694
   478
jaroslav@694
   479
	  do {
jaroslav@694
   480
jaroslav@694
   481
	    b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
jaroslav@694
   482
jaroslav@694
   483
	    if((e&16)!=0){
jaroslav@694
   484
	      // get extra bits to add to distance base
jaroslav@694
   485
	      e &= 15;
jaroslav@694
   486
	      while(k<(e)){         // get extra bits (up to 13)
jaroslav@694
   487
		n--;
jaroslav@694
   488
		b|=(z.next_in[p++]&0xff)<<k;k+=8;
jaroslav@694
   489
	      }
jaroslav@694
   490
jaroslav@694
   491
	      d = tp[tp_index_t_3+2] + (b&inflate_mask[e]);
jaroslav@694
   492
jaroslav@694
   493
	      b>>=(e); k-=(e);
jaroslav@694
   494
jaroslav@694
   495
	      // do the copy
jaroslav@694
   496
	      m -= c;
jaroslav@694
   497
	      if (q >= d){                // offset before dest
jaroslav@694
   498
		//  just copy
jaroslav@694
   499
		r=q-d;
jaroslav@694
   500
		if(q-r>0 && 2>(q-r)){           
jaroslav@694
   501
		  s.window[q++]=s.window[r++]; // minimum count is three,
jaroslav@694
   502
		  s.window[q++]=s.window[r++]; // so unroll loop a little
jaroslav@694
   503
		  c-=2;
jaroslav@694
   504
		}
jaroslav@694
   505
		else{
jaroslav@694
   506
		  System.arraycopy(s.window, r, s.window, q, 2);
jaroslav@694
   507
		  q+=2; r+=2; c-=2;
jaroslav@694
   508
		}
jaroslav@694
   509
	      }
jaroslav@694
   510
	      else{                  // else offset after destination
jaroslav@694
   511
                r=q-d;
jaroslav@694
   512
                do{
jaroslav@694
   513
                  r+=s.end;          // force pointer in window
jaroslav@694
   514
                }while(r<0);         // covers invalid distances
jaroslav@694
   515
		e=s.end-r;
jaroslav@694
   516
		if(c>e){             // if source crosses,
jaroslav@694
   517
		  c-=e;              // wrapped copy
jaroslav@694
   518
		  if(q-r>0 && e>(q-r)){           
jaroslav@694
   519
		    do{s.window[q++] = s.window[r++];}
jaroslav@694
   520
		    while(--e!=0);
jaroslav@694
   521
		  }
jaroslav@694
   522
		  else{
jaroslav@694
   523
		    System.arraycopy(s.window, r, s.window, q, e);
jaroslav@694
   524
		    q+=e; r+=e; e=0;
jaroslav@694
   525
		  }
jaroslav@694
   526
		  r = 0;                  // copy rest from start of window
jaroslav@694
   527
		}
jaroslav@694
   528
jaroslav@694
   529
	      }
jaroslav@694
   530
jaroslav@694
   531
	      // copy all or what's left
jaroslav@694
   532
	      if(q-r>0 && c>(q-r)){           
jaroslav@694
   533
		do{s.window[q++] = s.window[r++];}
jaroslav@694
   534
		while(--c!=0);
jaroslav@694
   535
	      }
jaroslav@694
   536
	      else{
jaroslav@694
   537
		System.arraycopy(s.window, r, s.window, q, c);
jaroslav@694
   538
		q+=c; r+=c; c=0;
jaroslav@694
   539
	      }
jaroslav@694
   540
	      break;
jaroslav@694
   541
	    }
jaroslav@694
   542
	    else if((e&64)==0){
jaroslav@694
   543
	      t+=tp[tp_index_t_3+2];
jaroslav@694
   544
	      t+=(b&inflate_mask[e]);
jaroslav@694
   545
	      tp_index_t_3=(tp_index+t)*3;
jaroslav@694
   546
	      e=tp[tp_index_t_3];
jaroslav@694
   547
	    }
jaroslav@694
   548
	    else{
jaroslav@694
   549
	      z.msg = "invalid distance code";
jaroslav@694
   550
jaroslav@694
   551
	      c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
jaroslav@694
   552
jaroslav@694
   553
	      s.bitb=b;s.bitk=k;
jaroslav@694
   554
	      z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   555
	      s.write=q;
jaroslav@694
   556
jaroslav@694
   557
	      return Z_DATA_ERROR;
jaroslav@694
   558
	    }
jaroslav@694
   559
	  }
jaroslav@694
   560
	  while(true);
jaroslav@694
   561
	  break;
jaroslav@694
   562
	}
jaroslav@694
   563
jaroslav@694
   564
	if((e&64)==0){
jaroslav@694
   565
	  t+=tp[tp_index_t_3+2];
jaroslav@694
   566
	  t+=(b&inflate_mask[e]);
jaroslav@694
   567
	  tp_index_t_3=(tp_index+t)*3;
jaroslav@694
   568
	  if((e=tp[tp_index_t_3])==0){
jaroslav@694
   569
jaroslav@694
   570
	    b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
jaroslav@694
   571
jaroslav@694
   572
	    s.window[q++]=(byte)tp[tp_index_t_3+2];
jaroslav@694
   573
	    m--;
jaroslav@694
   574
	    break;
jaroslav@694
   575
	  }
jaroslav@694
   576
	}
jaroslav@694
   577
	else if((e&32)!=0){
jaroslav@694
   578
jaroslav@694
   579
	  c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
jaroslav@694
   580
 
jaroslav@694
   581
	  s.bitb=b;s.bitk=k;
jaroslav@694
   582
	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   583
	  s.write=q;
jaroslav@694
   584
jaroslav@694
   585
	  return Z_STREAM_END;
jaroslav@694
   586
	}
jaroslav@694
   587
	else{
jaroslav@694
   588
	  z.msg="invalid literal/length code";
jaroslav@694
   589
jaroslav@694
   590
	  c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
jaroslav@694
   591
jaroslav@694
   592
	  s.bitb=b;s.bitk=k;
jaroslav@694
   593
	  z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   594
	  s.write=q;
jaroslav@694
   595
jaroslav@694
   596
	  return Z_DATA_ERROR;
jaroslav@694
   597
	}
jaroslav@694
   598
      } 
jaroslav@694
   599
      while(true);
jaroslav@694
   600
    } 
jaroslav@694
   601
    while(m>=258 && n>= 10);
jaroslav@694
   602
jaroslav@694
   603
    // not enough input or output--restore pointers and return
jaroslav@694
   604
    c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
jaroslav@694
   605
jaroslav@694
   606
    s.bitb=b;s.bitk=k;
jaroslav@694
   607
    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
jaroslav@694
   608
    s.write=q;
jaroslav@694
   609
jaroslav@694
   610
    return Z_OK;
jaroslav@694
   611
  }
jaroslav@694
   612
}