rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Inflate.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 694 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Inflate.java@0d277415ed02
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
jaroslav@694
     1
/* -*-mode:java; c-basic-offset:2; -*- */
jaroslav@694
     2
/*
jaroslav@694
     3
Copyright (c) 2000-2011 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 Inflate{
jaroslav@694
    40
  
jaroslav@694
    41
  static final private int MAX_WBITS=15; // 32K LZ77 window
jaroslav@694
    42
jaroslav@694
    43
  // preset dictionary flag in zlib header
jaroslav@694
    44
  static final private int PRESET_DICT=0x20;
jaroslav@694
    45
jaroslav@694
    46
  static final int Z_NO_FLUSH=0;
jaroslav@694
    47
  static final int Z_PARTIAL_FLUSH=1;
jaroslav@694
    48
  static final int Z_SYNC_FLUSH=2;
jaroslav@694
    49
  static final int Z_FULL_FLUSH=3;
jaroslav@694
    50
  static final int Z_FINISH=4;
jaroslav@694
    51
jaroslav@694
    52
  static final private int Z_DEFLATED=8;
jaroslav@694
    53
jaroslav@694
    54
  static final private int Z_OK=0;
jaroslav@694
    55
  static final private int Z_STREAM_END=1;
jaroslav@694
    56
  static final private int Z_NEED_DICT=2;
jaroslav@694
    57
  static final private int Z_ERRNO=-1;
jaroslav@694
    58
  static final private int Z_STREAM_ERROR=-2;
jaroslav@694
    59
  static final private int Z_DATA_ERROR=-3;
jaroslav@694
    60
  static final private int Z_MEM_ERROR=-4;
jaroslav@694
    61
  static final private int Z_BUF_ERROR=-5;
jaroslav@694
    62
  static final private int Z_VERSION_ERROR=-6;
jaroslav@694
    63
jaroslav@694
    64
  static final private int METHOD=0;   // waiting for method byte
jaroslav@694
    65
  static final private int FLAG=1;     // waiting for flag byte
jaroslav@694
    66
  static final private int DICT4=2;    // four dictionary check bytes to go
jaroslav@694
    67
  static final private int DICT3=3;    // three dictionary check bytes to go
jaroslav@694
    68
  static final private int DICT2=4;    // two dictionary check bytes to go
jaroslav@694
    69
  static final private int DICT1=5;    // one dictionary check byte to go
jaroslav@694
    70
  static final int DICT0=6;    // waiting for inflateSetDictionary
jaroslav@694
    71
  static final private int BLOCKS=7;   // decompressing blocks
jaroslav@694
    72
  static final private int CHECK4=8;   // four check bytes to go
jaroslav@694
    73
  static final private int CHECK3=9;   // three check bytes to go
jaroslav@694
    74
  static final private int CHECK2=10;  // two check bytes to go
jaroslav@694
    75
  static final private int CHECK1=11;  // one check byte to go
jaroslav@694
    76
  static final private int DONE=12;    // finished check, done
jaroslav@694
    77
  static final private int BAD=13;     // got an error--stay here
jaroslav@694
    78
jaroslav@694
    79
  static final private int HEAD=14;
jaroslav@694
    80
  static final private int LENGTH=15;
jaroslav@694
    81
  static final private int TIME=16;
jaroslav@694
    82
  static final private int OS=17;
jaroslav@694
    83
  static final private int EXLEN=18;
jaroslav@694
    84
  static final private int EXTRA=19;
jaroslav@694
    85
  static final private int NAME=20;
jaroslav@694
    86
  static final private int COMMENT=21;
jaroslav@694
    87
  static final private int HCRC=22;
jaroslav@694
    88
  static final private int FLAGS=23;
jaroslav@694
    89
jaroslav@694
    90
  int mode;                            // current inflate mode
jaroslav@694
    91
jaroslav@694
    92
  // mode dependent information
jaroslav@694
    93
  int method;        // if FLAGS, method byte
jaroslav@694
    94
jaroslav@694
    95
  // if CHECK, check values to compare
jaroslav@694
    96
  long was = -1;           // computed check value
jaroslav@694
    97
  long need;               // stream check value
jaroslav@694
    98
jaroslav@694
    99
  // if BAD, inflateSync's marker bytes count
jaroslav@694
   100
  int marker;
jaroslav@694
   101
jaroslav@694
   102
  // mode independent information
jaroslav@694
   103
  int  wrap;          // flag for no wrapper
jaroslav@694
   104
  int wbits;            // log2(window size)  (8..15, defaults to 15)
jaroslav@694
   105
jaroslav@694
   106
  InfBlocks blocks;     // current inflate_blocks state
jaroslav@694
   107
jaroslav@694
   108
  private final ZStream z;
jaroslav@694
   109
jaroslav@694
   110
  private int flags; 
jaroslav@694
   111
jaroslav@694
   112
  private int need_bytes = -1;
jaroslav@694
   113
  private byte[] crcbuf=new byte[4];
jaroslav@694
   114
jaroslav@694
   115
  GZIPHeader gheader = null;
jaroslav@694
   116
jaroslav@694
   117
  int inflateReset(){
jaroslav@694
   118
    if(z == null) return Z_STREAM_ERROR;
jaroslav@694
   119
    
jaroslav@694
   120
    z.total_in = z.total_out = 0;
jaroslav@694
   121
    z.msg = null;
jaroslav@694
   122
    this.mode = HEAD;
jaroslav@694
   123
    this.need_bytes = -1;
jaroslav@694
   124
    this.blocks.reset();
jaroslav@694
   125
    return Z_OK;
jaroslav@694
   126
  }
jaroslav@694
   127
jaroslav@694
   128
  int inflateEnd(){
jaroslav@694
   129
    if(blocks != null){
jaroslav@694
   130
      blocks.free();
jaroslav@694
   131
    }
jaroslav@694
   132
    return Z_OK;
jaroslav@694
   133
  }
jaroslav@694
   134
jaroslav@694
   135
  Inflate(ZStream z){
jaroslav@694
   136
    this.z=z;
jaroslav@694
   137
  }
jaroslav@694
   138
jaroslav@694
   139
  int inflateInit(int w){
jaroslav@694
   140
    z.msg = null;
jaroslav@694
   141
    blocks = null;
jaroslav@694
   142
jaroslav@694
   143
    // handle undocumented wrap option (no zlib header or check)
jaroslav@694
   144
    wrap = 0;
jaroslav@694
   145
    if(w < 0){
jaroslav@694
   146
      w = - w;
jaroslav@694
   147
    }
jaroslav@694
   148
    else {
jaroslav@694
   149
      wrap = (w >> 4) + 1;
jaroslav@694
   150
      if(w < 48)
jaroslav@694
   151
        w &= 15;
jaroslav@694
   152
    }
jaroslav@694
   153
jaroslav@694
   154
    if(w<8 ||w>15){
jaroslav@694
   155
      inflateEnd();
jaroslav@694
   156
      return Z_STREAM_ERROR;
jaroslav@694
   157
    }
jaroslav@694
   158
    if(blocks != null && wbits != w){
jaroslav@694
   159
      blocks.free();
jaroslav@694
   160
      blocks=null;
jaroslav@694
   161
    }
jaroslav@694
   162
jaroslav@694
   163
    // set window size
jaroslav@694
   164
    wbits=w;
jaroslav@694
   165
jaroslav@694
   166
    this.blocks=new InfBlocks(z, 1<<w);
jaroslav@694
   167
jaroslav@694
   168
    // reset state
jaroslav@694
   169
    inflateReset();
jaroslav@694
   170
jaroslav@694
   171
    return Z_OK;
jaroslav@694
   172
  }
jaroslav@694
   173
jaroslav@694
   174
  int inflate(int f){
jaroslav@694
   175
    int hold = 0;
jaroslav@694
   176
jaroslav@694
   177
    int r;
jaroslav@694
   178
    int b;
jaroslav@694
   179
jaroslav@694
   180
    if(z == null || z.next_in == null){
jaroslav@694
   181
      if(f == Z_FINISH && this.mode==HEAD)
jaroslav@694
   182
        return Z_OK; 
jaroslav@694
   183
      return Z_STREAM_ERROR;
jaroslav@694
   184
    }
jaroslav@694
   185
jaroslav@694
   186
    f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
jaroslav@694
   187
    r = Z_BUF_ERROR;
jaroslav@694
   188
    while (true){
jaroslav@694
   189
jaroslav@694
   190
      switch (this.mode){
jaroslav@694
   191
      case HEAD:
jaroslav@694
   192
        if(wrap==0){
jaroslav@694
   193
	  this.mode = BLOCKS;
jaroslav@694
   194
          break;
jaroslav@694
   195
        } 
jaroslav@694
   196
jaroslav@694
   197
        try { r=readBytes(2, r, f); }
jaroslav@694
   198
        catch(Return e){ return e.r; }
jaroslav@694
   199
jaroslav@694
   200
        if((wrap&2)!=0 && this.need == 0x8b1fL) {   // gzip header
jaroslav@694
   201
	  z.adler=new CRC32();
jaroslav@694
   202
          checksum(2, this.need);
jaroslav@694
   203
jaroslav@694
   204
          if(gheader==null) 
jaroslav@694
   205
            gheader=new GZIPHeader();
jaroslav@694
   206
jaroslav@694
   207
          this.mode = FLAGS;
jaroslav@694
   208
          break;
jaroslav@694
   209
        }
jaroslav@694
   210
jaroslav@694
   211
        flags = 0;
jaroslav@694
   212
jaroslav@694
   213
        this.method = ((int)this.need)&0xff;
jaroslav@694
   214
        b=((int)(this.need>>8))&0xff;
jaroslav@694
   215
jaroslav@694
   216
        if((wrap&1)==0 ||  // check if zlib header allowed
jaroslav@694
   217
           (((this.method << 8)+b) % 31)!=0){
jaroslav@694
   218
          this.mode = BAD;
jaroslav@694
   219
          z.msg = "incorrect header check";
jaroslav@694
   220
          // since zlib 1.2, it is allowted to inflateSync for this case.
jaroslav@694
   221
          /*
jaroslav@694
   222
          this.marker = 5;       // can't try inflateSync
jaroslav@694
   223
          */
jaroslav@694
   224
          break;
jaroslav@694
   225
        }
jaroslav@694
   226
jaroslav@694
   227
        if((this.method&0xf)!=Z_DEFLATED){
jaroslav@694
   228
          this.mode = BAD;
jaroslav@694
   229
          z.msg="unknown compression method";
jaroslav@694
   230
          // since zlib 1.2, it is allowted to inflateSync for this case.
jaroslav@694
   231
	  /*
jaroslav@694
   232
          this.marker = 5;       // can't try inflateSync
jaroslav@694
   233
	  */
jaroslav@694
   234
          break;
jaroslav@694
   235
        }
jaroslav@694
   236
jaroslav@694
   237
        if((this.method>>4)+8>this.wbits){
jaroslav@694
   238
          this.mode = BAD;
jaroslav@694
   239
          z.msg="invalid window size";
jaroslav@694
   240
          // since zlib 1.2, it is allowted to inflateSync for this case.
jaroslav@694
   241
	  /*
jaroslav@694
   242
          this.marker = 5;       // can't try inflateSync
jaroslav@694
   243
	  */
jaroslav@694
   244
          break;
jaroslav@694
   245
        }
jaroslav@694
   246
jaroslav@694
   247
        z.adler=new Adler32();
jaroslav@694
   248
jaroslav@694
   249
        if((b&PRESET_DICT)==0){
jaroslav@694
   250
          this.mode = BLOCKS;
jaroslav@694
   251
          break;
jaroslav@694
   252
        }
jaroslav@694
   253
        this.mode = DICT4;
jaroslav@694
   254
      case DICT4:
jaroslav@694
   255
jaroslav@694
   256
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   257
jaroslav@694
   258
        z.avail_in--; z.total_in++;
jaroslav@694
   259
        this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
jaroslav@694
   260
        this.mode=DICT3;
jaroslav@694
   261
      case DICT3:
jaroslav@694
   262
jaroslav@694
   263
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   264
jaroslav@694
   265
        z.avail_in--; z.total_in++;
jaroslav@694
   266
        this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
jaroslav@694
   267
        this.mode=DICT2;
jaroslav@694
   268
      case DICT2:
jaroslav@694
   269
jaroslav@694
   270
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   271
jaroslav@694
   272
        z.avail_in--; z.total_in++;
jaroslav@694
   273
        this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
jaroslav@694
   274
        this.mode=DICT1;
jaroslav@694
   275
      case DICT1:
jaroslav@694
   276
jaroslav@694
   277
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   278
jaroslav@694
   279
        z.avail_in--; z.total_in++;
jaroslav@694
   280
        this.need += (z.next_in[z.next_in_index++]&0xffL);
jaroslav@694
   281
        z.adler.reset(this.need);
jaroslav@694
   282
        this.mode = DICT0;
jaroslav@694
   283
        return Z_NEED_DICT;
jaroslav@694
   284
      case DICT0:
jaroslav@694
   285
        this.mode = BAD;
jaroslav@694
   286
        z.msg = "need dictionary";
jaroslav@694
   287
        this.marker = 0;       // can try inflateSync
jaroslav@694
   288
        return Z_STREAM_ERROR;
jaroslav@694
   289
      case BLOCKS:
jaroslav@694
   290
        r = this.blocks.proc(r);
jaroslav@694
   291
        if(r == Z_DATA_ERROR){
jaroslav@694
   292
          this.mode = BAD;
jaroslav@694
   293
          this.marker = 0;     // can try inflateSync
jaroslav@694
   294
          break;
jaroslav@694
   295
        }
jaroslav@694
   296
        if(r == Z_OK){
jaroslav@694
   297
          r = f;
jaroslav@694
   298
        }
jaroslav@694
   299
        if(r != Z_STREAM_END){
jaroslav@694
   300
          return r;
jaroslav@694
   301
        }
jaroslav@694
   302
        r = f;
jaroslav@694
   303
        this.was=z.adler.getValue();
jaroslav@694
   304
        this.blocks.reset();
jaroslav@694
   305
        if(this.wrap==0){
jaroslav@694
   306
          this.mode=DONE;
jaroslav@694
   307
          break;
jaroslav@694
   308
        }
jaroslav@694
   309
        this.mode=CHECK4;
jaroslav@694
   310
      case CHECK4:
jaroslav@694
   311
jaroslav@694
   312
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   313
jaroslav@694
   314
        z.avail_in--; z.total_in++;
jaroslav@694
   315
        this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
jaroslav@694
   316
        this.mode=CHECK3;
jaroslav@694
   317
      case CHECK3:
jaroslav@694
   318
jaroslav@694
   319
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   320
jaroslav@694
   321
        z.avail_in--; z.total_in++;
jaroslav@694
   322
        this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
jaroslav@694
   323
        this.mode = CHECK2;
jaroslav@694
   324
      case CHECK2:
jaroslav@694
   325
jaroslav@694
   326
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   327
jaroslav@694
   328
        z.avail_in--; z.total_in++;
jaroslav@694
   329
        this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
jaroslav@694
   330
        this.mode = CHECK1;
jaroslav@694
   331
      case CHECK1:
jaroslav@694
   332
jaroslav@694
   333
        if(z.avail_in==0)return r;r=f;
jaroslav@694
   334
jaroslav@694
   335
        z.avail_in--; z.total_in++;
jaroslav@694
   336
        this.need+=(z.next_in[z.next_in_index++]&0xffL);
jaroslav@694
   337
jaroslav@694
   338
        if(flags!=0){  // gzip
jaroslav@694
   339
          this.need = ((this.need&0xff000000)>>24 | 
jaroslav@694
   340
                          (this.need&0x00ff0000)>>8 | 
jaroslav@694
   341
                          (this.need&0x0000ff00)<<8 | 
jaroslav@694
   342
                          (this.need&0x0000ffff)<<24)&0xffffffffL;
jaroslav@694
   343
        }
jaroslav@694
   344
jaroslav@694
   345
        if(((int)(this.was)) != ((int)(this.need))){
jaroslav@694
   346
          z.msg = "incorrect data check";
jaroslav@694
   347
          // chack is delayed
jaroslav@694
   348
          /*
jaroslav@694
   349
          this.mode = BAD;
jaroslav@694
   350
          this.marker = 5;       // can't try inflateSync
jaroslav@694
   351
          break;
jaroslav@694
   352
	  */
jaroslav@694
   353
        }
jaroslav@694
   354
        else if(flags!=0 && gheader!=null){
jaroslav@694
   355
          gheader.crc = this.need; 
jaroslav@694
   356
        }
jaroslav@694
   357
jaroslav@694
   358
        this.mode = LENGTH;
jaroslav@694
   359
      case LENGTH:
jaroslav@694
   360
        if (wrap!=0 && flags!=0) {
jaroslav@694
   361
jaroslav@694
   362
          try { r=readBytes(4, r, f); }
jaroslav@694
   363
          catch(Return e){ return e.r; }
jaroslav@694
   364
jaroslav@694
   365
          if(z.msg!=null && z.msg.equals("incorrect data check")){
jaroslav@694
   366
            this.mode = BAD;
jaroslav@694
   367
            this.marker = 5;       // can't try inflateSync
jaroslav@694
   368
            break;
jaroslav@694
   369
          }
jaroslav@694
   370
jaroslav@694
   371
          if (this.need != (z.total_out & 0xffffffffL)) {
jaroslav@694
   372
            z.msg = "incorrect length check";
jaroslav@694
   373
            this.mode = BAD;
jaroslav@694
   374
            break;
jaroslav@694
   375
          }
jaroslav@694
   376
          z.msg = null;
jaroslav@694
   377
        }
jaroslav@694
   378
        else {
jaroslav@694
   379
          if(z.msg!=null && z.msg.equals("incorrect data check")){
jaroslav@694
   380
            this.mode = BAD;
jaroslav@694
   381
            this.marker = 5;       // can't try inflateSync
jaroslav@694
   382
            break;
jaroslav@694
   383
          }
jaroslav@694
   384
        }
jaroslav@694
   385
jaroslav@694
   386
        this.mode = DONE;
jaroslav@694
   387
      case DONE:
jaroslav@694
   388
        return Z_STREAM_END;
jaroslav@694
   389
      case BAD:
jaroslav@694
   390
        return Z_DATA_ERROR;
jaroslav@694
   391
jaroslav@694
   392
      case FLAGS:
jaroslav@694
   393
jaroslav@694
   394
        try { r=readBytes(2, r, f); }
jaroslav@694
   395
        catch(Return e){ return e.r; }
jaroslav@694
   396
jaroslav@694
   397
        flags = ((int)this.need)&0xffff;
jaroslav@694
   398
jaroslav@694
   399
        if ((flags & 0xff) != Z_DEFLATED) {
jaroslav@694
   400
          z.msg = "unknown compression method";
jaroslav@694
   401
          this.mode = BAD; 
jaroslav@694
   402
          break;
jaroslav@694
   403
        }
jaroslav@694
   404
        if ((flags & 0xe000)!=0) {
jaroslav@694
   405
          z.msg = "unknown header flags set";
jaroslav@694
   406
          this.mode = BAD; 
jaroslav@694
   407
          break;
jaroslav@694
   408
        }
jaroslav@694
   409
jaroslav@694
   410
        if ((flags & 0x0200)!=0){
jaroslav@694
   411
          checksum(2, this.need);
jaroslav@694
   412
        } 
jaroslav@694
   413
jaroslav@694
   414
        this.mode = TIME;
jaroslav@694
   415
jaroslav@694
   416
      case TIME:
jaroslav@694
   417
        try { r=readBytes(4, r, f); }
jaroslav@694
   418
        catch(Return e){ return e.r; }
jaroslav@694
   419
        if(gheader!=null)
jaroslav@694
   420
          gheader.time = this.need;
jaroslav@694
   421
        if ((flags & 0x0200)!=0){
jaroslav@694
   422
          checksum(4, this.need);
jaroslav@694
   423
        }
jaroslav@694
   424
        this.mode = OS;
jaroslav@694
   425
      case OS:
jaroslav@694
   426
        try { r=readBytes(2, r, f); }
jaroslav@694
   427
        catch(Return e){ return e.r; }
jaroslav@694
   428
        if(gheader!=null){
jaroslav@694
   429
          gheader.xflags = ((int)this.need)&0xff;
jaroslav@694
   430
          gheader.os = (((int)this.need)>>8)&0xff;
jaroslav@694
   431
        }
jaroslav@694
   432
        if ((flags & 0x0200)!=0){
jaroslav@694
   433
          checksum(2, this.need);
jaroslav@694
   434
        }
jaroslav@694
   435
        this.mode = EXLEN;
jaroslav@694
   436
      case EXLEN:
jaroslav@694
   437
        if ((flags & 0x0400)!=0) {
jaroslav@694
   438
          try { r=readBytes(2, r, f); }
jaroslav@694
   439
          catch(Return e){ return e.r; }
jaroslav@694
   440
          if(gheader!=null){
jaroslav@694
   441
            gheader.extra = new byte[((int)this.need)&0xffff];
jaroslav@694
   442
          }
jaroslav@694
   443
          if ((flags & 0x0200)!=0){
jaroslav@694
   444
            checksum(2, this.need);
jaroslav@694
   445
          }
jaroslav@694
   446
        }
jaroslav@694
   447
        else if(gheader!=null){
jaroslav@694
   448
          gheader.extra=null;
jaroslav@694
   449
        }
jaroslav@694
   450
        this.mode = EXTRA;
jaroslav@694
   451
jaroslav@694
   452
      case EXTRA:
jaroslav@694
   453
        if ((flags & 0x0400)!=0) {
jaroslav@694
   454
          try { 
jaroslav@694
   455
            r=readBytes(r, f);
jaroslav@694
   456
            if(gheader!=null){
jaroslav@694
   457
              byte[] foo = tmp_array;
jaroslav@694
   458
              tmp_array=null;
jaroslav@694
   459
              if(foo.length == gheader.extra.length){
jaroslav@694
   460
                System.arraycopy(foo, 0, gheader.extra, 0, foo.length);
jaroslav@694
   461
	      }
jaroslav@694
   462
              else{
jaroslav@694
   463
                z.msg = "bad extra field length";
jaroslav@694
   464
                this.mode = BAD; 
jaroslav@694
   465
                break;
jaroslav@694
   466
	      }
jaroslav@694
   467
            }
jaroslav@694
   468
          }
jaroslav@694
   469
          catch(Return e){ return e.r; }
jaroslav@694
   470
        }
jaroslav@694
   471
        else if(gheader!=null){
jaroslav@694
   472
          gheader.extra=null;
jaroslav@694
   473
	}
jaroslav@694
   474
	this.mode = NAME;
jaroslav@694
   475
      case NAME:
jaroslav@694
   476
	if ((flags & 0x0800)!=0) {
jaroslav@694
   477
          try { 
jaroslav@694
   478
            r=readString(r, f);
jaroslav@694
   479
            if(gheader!=null){
jaroslav@694
   480
              gheader.name=tmp_array;
jaroslav@694
   481
            }
jaroslav@694
   482
            tmp_array=null;
jaroslav@694
   483
          }
jaroslav@694
   484
          catch(Return e){ return e.r; }
jaroslav@694
   485
        }
jaroslav@694
   486
        else if(gheader!=null){
jaroslav@694
   487
          gheader.name=null;
jaroslav@694
   488
	}
jaroslav@694
   489
        this.mode = COMMENT;
jaroslav@694
   490
      case COMMENT:
jaroslav@694
   491
        if ((flags & 0x1000)!=0) {
jaroslav@694
   492
          try { 
jaroslav@694
   493
            r=readString(r, f);
jaroslav@694
   494
            if(gheader!=null){
jaroslav@694
   495
              gheader.comment=tmp_array;
jaroslav@694
   496
            }
jaroslav@694
   497
            tmp_array=null;
jaroslav@694
   498
          }
jaroslav@694
   499
          catch(Return e){ return e.r; }
jaroslav@694
   500
        }
jaroslav@694
   501
        else if(gheader!=null){
jaroslav@694
   502
          gheader.comment=null;
jaroslav@694
   503
	}
jaroslav@694
   504
        this.mode = HCRC;
jaroslav@694
   505
      case HCRC:
jaroslav@694
   506
	if ((flags & 0x0200)!=0) {
jaroslav@694
   507
          try { r=readBytes(2, r, f); }
jaroslav@694
   508
          catch(Return e){ return e.r; }
jaroslav@694
   509
          if(gheader!=null){
jaroslav@694
   510
            gheader.hcrc=(int)(this.need&0xffff);
jaroslav@694
   511
          }
jaroslav@694
   512
          if(this.need != (z.adler.getValue()&0xffffL)){
jaroslav@694
   513
            this.mode = BAD;
jaroslav@694
   514
            z.msg = "header crc mismatch";
jaroslav@694
   515
            this.marker = 5;       // can't try inflateSync
jaroslav@694
   516
            break;
jaroslav@694
   517
          }
jaroslav@694
   518
        }
jaroslav@694
   519
        z.adler = new CRC32();
jaroslav@694
   520
jaroslav@694
   521
        this.mode = BLOCKS;
jaroslav@694
   522
        break;
jaroslav@694
   523
      default:
jaroslav@694
   524
        return Z_STREAM_ERROR;
jaroslav@694
   525
      }
jaroslav@694
   526
    }
jaroslav@694
   527
  }
jaroslav@694
   528
jaroslav@694
   529
  int inflateSetDictionary(byte[] dictionary, int dictLength){
jaroslav@694
   530
    if(z==null || (this.mode != DICT0 && this.wrap != 0)){
jaroslav@694
   531
      return Z_STREAM_ERROR;
jaroslav@694
   532
    }
jaroslav@694
   533
jaroslav@694
   534
    int index=0;
jaroslav@694
   535
    int length = dictLength;
jaroslav@694
   536
jaroslav@694
   537
    if(this.mode==DICT0){
jaroslav@694
   538
      long adler_need=z.adler.getValue();
jaroslav@694
   539
      z.adler.reset();
jaroslav@694
   540
      z.adler.update(dictionary, 0, dictLength);
jaroslav@694
   541
      if(z.adler.getValue()!=adler_need){
jaroslav@694
   542
        return Z_DATA_ERROR;
jaroslav@694
   543
      }
jaroslav@694
   544
    }
jaroslav@694
   545
jaroslav@694
   546
    z.adler.reset();
jaroslav@694
   547
jaroslav@694
   548
    if(length >= (1<<this.wbits)){
jaroslav@694
   549
      length = (1<<this.wbits)-1;
jaroslav@694
   550
      index=dictLength - length;
jaroslav@694
   551
    }
jaroslav@694
   552
    this.blocks.set_dictionary(dictionary, index, length);
jaroslav@694
   553
    this.mode = BLOCKS;
jaroslav@694
   554
    return Z_OK;
jaroslav@694
   555
  }
jaroslav@694
   556
jaroslav@694
   557
  static private byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff};
jaroslav@694
   558
jaroslav@694
   559
  int inflateSync(){
jaroslav@694
   560
    int n;       // number of bytes to look at
jaroslav@694
   561
    int p;       // pointer to bytes
jaroslav@694
   562
    int m;       // number of marker bytes found in a row
jaroslav@694
   563
    long r, w;   // temporaries to save total_in and total_out
jaroslav@694
   564
jaroslav@694
   565
    // set up
jaroslav@694
   566
    if(z == null)
jaroslav@694
   567
      return Z_STREAM_ERROR;
jaroslav@694
   568
    if(this.mode != BAD){
jaroslav@694
   569
      this.mode = BAD;
jaroslav@694
   570
      this.marker = 0;
jaroslav@694
   571
    }
jaroslav@694
   572
    if((n=z.avail_in)==0)
jaroslav@694
   573
      return Z_BUF_ERROR;
jaroslav@694
   574
jaroslav@694
   575
    p=z.next_in_index;
jaroslav@694
   576
    m=this.marker;
jaroslav@694
   577
    // search
jaroslav@694
   578
    while (n!=0 && m < 4){
jaroslav@694
   579
      if(z.next_in[p] == mark[m]){
jaroslav@694
   580
        m++;
jaroslav@694
   581
      }
jaroslav@694
   582
      else if(z.next_in[p]!=0){
jaroslav@694
   583
        m = 0;
jaroslav@694
   584
      }
jaroslav@694
   585
      else{
jaroslav@694
   586
        m = 4 - m;
jaroslav@694
   587
      }
jaroslav@694
   588
      p++; n--;
jaroslav@694
   589
    }
jaroslav@694
   590
jaroslav@694
   591
    // restore
jaroslav@694
   592
    z.total_in += p-z.next_in_index;
jaroslav@694
   593
    z.next_in_index = p;
jaroslav@694
   594
    z.avail_in = n;
jaroslav@694
   595
    this.marker = m;
jaroslav@694
   596
jaroslav@694
   597
    // return no joy or set up to restart on a new block
jaroslav@694
   598
    if(m != 4){
jaroslav@694
   599
      return Z_DATA_ERROR;
jaroslav@694
   600
    }
jaroslav@694
   601
    r=z.total_in;  w=z.total_out;
jaroslav@694
   602
    inflateReset();
jaroslav@694
   603
    z.total_in=r;  z.total_out = w;
jaroslav@694
   604
    this.mode = BLOCKS;
jaroslav@694
   605
jaroslav@694
   606
    return Z_OK;
jaroslav@694
   607
  }
jaroslav@694
   608
jaroslav@694
   609
  // Returns true if inflate is currently at the end of a block generated
jaroslav@694
   610
  // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
jaroslav@694
   611
  // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
jaroslav@694
   612
  // but removes the length bytes of the resulting empty stored block. When
jaroslav@694
   613
  // decompressing, PPP checks that at the end of input packet, inflate is
jaroslav@694
   614
  // waiting for these length bytes.
jaroslav@694
   615
  int inflateSyncPoint(){
jaroslav@694
   616
    if(z == null || this.blocks == null)
jaroslav@694
   617
      return Z_STREAM_ERROR;
jaroslav@694
   618
    return this.blocks.sync_point();
jaroslav@694
   619
  }
jaroslav@694
   620
jaroslav@694
   621
  private int readBytes(int n, int r, int f) throws Return{
jaroslav@694
   622
    if(need_bytes == -1){
jaroslav@694
   623
      need_bytes=n;
jaroslav@694
   624
      this.need=0;
jaroslav@694
   625
    }
jaroslav@694
   626
    while(need_bytes>0){
jaroslav@694
   627
      if(z.avail_in==0){ throw new Return(r); }; r=f;
jaroslav@694
   628
      z.avail_in--; z.total_in++;
jaroslav@694
   629
      this.need = this.need | 
jaroslav@694
   630
	((z.next_in[z.next_in_index++]&0xff)<<((n-need_bytes)*8));
jaroslav@694
   631
      need_bytes--;
jaroslav@694
   632
    }
jaroslav@694
   633
    if(n==2){
jaroslav@694
   634
      this.need&=0xffffL;
jaroslav@694
   635
    }
jaroslav@694
   636
    else if(n==4) {
jaroslav@694
   637
      this.need&=0xffffffffL;
jaroslav@694
   638
    }
jaroslav@694
   639
    need_bytes=-1;
jaroslav@694
   640
    return r;
jaroslav@694
   641
  }
jaroslav@694
   642
  class Return extends Exception{
jaroslav@694
   643
    int r;
jaroslav@694
   644
    Return(int r){this.r=r; }
jaroslav@694
   645
  }
jaroslav@694
   646
jaroslav@694
   647
  private byte[] tmp_array;
jaroslav@694
   648
  private int readString(int r, int f) throws Return{
jaroslav@694
   649
    int b=0; 
jaroslav@694
   650
    byte[] arr = new byte[4092];
jaroslav@694
   651
    int at = 0;
jaroslav@694
   652
    do {
jaroslav@694
   653
      if(z.avail_in==0){ throw new Return(r); }; r=f;
jaroslav@694
   654
      z.avail_in--; z.total_in++;
jaroslav@694
   655
      b = z.next_in[z.next_in_index];
jaroslav@694
   656
      if(b!=0) arr = append(arr, z.next_in[z.next_in_index], at++);
jaroslav@694
   657
      z.adler.update(z.next_in, z.next_in_index, 1);
jaroslav@694
   658
      z.next_in_index++;
jaroslav@694
   659
    }while(b!=0);
jaroslav@694
   660
    
jaroslav@694
   661
    tmp_array = copy(arr, at);
jaroslav@694
   662
    
jaroslav@694
   663
    return r;
jaroslav@694
   664
  }
jaroslav@694
   665
jaroslav@694
   666
  private int readBytes(int r, int f) throws Return{
jaroslav@694
   667
    int b=0; 
jaroslav@694
   668
    byte[] arr = new byte[4092];
jaroslav@694
   669
    int at = 0;
jaroslav@694
   670
    while(this.need>0){
jaroslav@694
   671
      if(z.avail_in==0){ throw new Return(r); }; r=f;
jaroslav@694
   672
      z.avail_in--; z.total_in++;
jaroslav@694
   673
      b = z.next_in[z.next_in_index];
jaroslav@694
   674
      arr = append(arr, z.next_in[z.next_in_index], at++);
jaroslav@694
   675
      z.adler.update(z.next_in, z.next_in_index, 1);
jaroslav@694
   676
      z.next_in_index++;
jaroslav@694
   677
      this.need--;
jaroslav@694
   678
    }
jaroslav@694
   679
    
jaroslav@694
   680
    tmp_array = copy(arr, at);
jaroslav@694
   681
    
jaroslav@694
   682
    return r;
jaroslav@694
   683
  }
jaroslav@694
   684
  
jaroslav@694
   685
  private static byte[] copy(byte[] arr, int len) {
jaroslav@694
   686
      byte[] ret = new byte[len];
jaroslav@694
   687
      org.apidesign.bck2brwsr.emul.lang.System.arraycopy(arr, 0, ret, 0, len);
jaroslav@694
   688
      return ret;
jaroslav@694
   689
  }
jaroslav@694
   690
  private static byte[] append(byte[] arr, byte b, int index) {
jaroslav@694
   691
      arr[index] = b;
jaroslav@694
   692
      return arr;
jaroslav@694
   693
  }
jaroslav@694
   694
jaroslav@694
   695
  private void checksum(int n, long v){
jaroslav@694
   696
    for(int i=0; i<n; i++){
jaroslav@694
   697
      crcbuf[i]=(byte)(v&0xff);
jaroslav@694
   698
      v>>=8;
jaroslav@694
   699
    }
jaroslav@694
   700
    z.adler.update(crcbuf, 0, n);
jaroslav@694
   701
  }
jaroslav@694
   702
jaroslav@694
   703
  public GZIPHeader getGZIPHeader(){
jaroslav@694
   704
    return gheader;
jaroslav@694
   705
  }
jaroslav@694
   706
jaroslav@694
   707
  boolean inParsingHeader(){
jaroslav@694
   708
    switch(mode){
jaroslav@694
   709
      case HEAD:
jaroslav@694
   710
      case DICT4:
jaroslav@694
   711
      case DICT3:
jaroslav@694
   712
      case DICT2:
jaroslav@694
   713
      case DICT1:
jaroslav@694
   714
      case FLAGS:
jaroslav@694
   715
      case TIME:
jaroslav@694
   716
      case OS:
jaroslav@694
   717
      case EXLEN:
jaroslav@694
   718
      case EXTRA:
jaroslav@694
   719
      case NAME:
jaroslav@694
   720
      case COMMENT:
jaroslav@694
   721
      case HCRC:
jaroslav@694
   722
	return true;
jaroslav@694
   723
      default:
jaroslav@694
   724
	return false;
jaroslav@694
   725
    }
jaroslav@694
   726
  }
jaroslav@694
   727
}