View Javadoc

    1   /*
    2    * Copyright 2009 Red Hat, Inc.
    3    *
    4    * Red Hat licenses this file to you under the Apache License, version 2.0
    5    * (the "License"); you may not use this file except in compliance with the
    6    * License.  You may obtain a copy of the License at:
    7    *
    8    *    http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  /*
    17  Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
    18
    19  Redistribution and use in source and binary forms, with or without
    20  modification, are permitted provided that the following conditions are met:
    21
    22    1. Redistributions of source code must retain the above copyright notice,
    23       this list of conditions and the following disclaimer.
    24
    25    2. Redistributions in binary form must reproduce the above copyright
    26       notice, this list of conditions and the following disclaimer in
    27       the documentation and/or other materials provided with the distribution.
    28
    29    3. The names of the authors may not be used to endorse or promote products
    30       derived from this software without specific prior written permission.
    31
    32  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
    33  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    34  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
    35  INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
    36  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    37  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
    38  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    39  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    40  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    41  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    42   */
    43  /*
    44   * This program is based on zlib-1.1.3, so all credit should go authors
    45   * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
    46   * and contributors of zlib.
    47   */
    48
    49  package org.jboss.netty.util.internal.jzlib;
    50
    51  import org.jboss.netty.util.internal.jzlib.JZlib.WrapperType;
    52
    53  final class Inflate {
    54
    55      private static final int METHOD = 0; // waiting for method byte
    56      private static final int FLAG = 1; // waiting for flag byte
    57      private static final int DICT4 = 2; // four dictionary check bytes to go
    58      private static final int DICT3 = 3; // three dictionary check bytes to go
    59      private static final int DICT2 = 4; // two dictionary check bytes to go
    60      private static final int DICT1 = 5; // one dictionary check byte to go
    61      private static final int DICT0 = 6; // waiting for inflateSetDictionary
    62      private static final int BLOCKS = 7; // decompressing blocks
    63      private static final int CHECK4 = 8; // four check bytes to go
    64      private static final int CHECK3 = 9; // three check bytes to go
    65      private static final int CHECK2 = 10; // two check bytes to go
    66      private static final int CHECK1 = 11; // one check byte to go
    67      private static final int DONE = 12; // finished check, done
    68      private static final int BAD = 13; // got an error--stay here
    69
    70      private static final int GZIP_ID1 = 14;
    71      private static final int GZIP_ID2 = 15;
    72      private static final int GZIP_CM = 16;
    73      private static final int GZIP_FLG = 17;
    74      private static final int GZIP_MTIME_XFL_OS = 18;
    75      private static final int GZIP_XLEN = 19;
    76      private static final int GZIP_FEXTRA = 20;
    77      private static final int GZIP_FNAME = 21;
    78      private static final int GZIP_FCOMMENT = 22;
    79      private static final int GZIP_FHCRC = 23;
    80      private static final int GZIP_CRC32= 24;
    81      private static final int GZIP_ISIZE = 25;
    82
    83      private int mode; // current inflate mode
    84      // mode dependent information
    85      private int method; // if FLAGS, method byte
    86      // if CHECK, check values to compare
    87      private final long[] was = new long[1]; // computed check value
    88      private long need; // stream check value
    89      // if BAD, inflateSync's marker bytes count
    90      private int marker;
    91      // mode independent information
    92      private WrapperType wrapperType;
    93      private int wbits; // log2(window size)  (8..15, defaults to 15)
    94      private InfBlocks blocks; // current inflate_blocks state
    95      private int gzipFlag;
    96      private int gzipBytesToRead;
    97      private int gzipXLen;
    98      private int gzipUncompressedBytes;
    99      private int gzipCRC32;
    100     private int gzipISize;
    101
    102     private int inflateReset(ZStream z) {
    103         if (z == null || z.istate == null) {
    104             return JZlib.Z_STREAM_ERROR;
    105         }
    106
    107         z.total_in = z.total_out = 0;
    108         z.msg = null;
    109         switch (wrapperType) {
    110         case NONE:
    111             z.istate.mode = BLOCKS;
    112             break;
    113         case ZLIB:
    114             z.istate.mode = METHOD;
    115             break;
    116         case GZIP:
    117             z.istate.mode = GZIP_ID1;
    118             break;
    119         }
    120         z.istate.blocks.reset(z, null);
    121         gzipUncompressedBytes = 0;
    122         return JZlib.Z_OK;
    123     }
    124
    125     int inflateEnd(ZStream z) {
    126         if (blocks != null) {
    127             blocks.free(z);
    128         }
    129         blocks = null;
    130         //    ZFREE(z, z->state);
    131         return JZlib.Z_OK;
    132     }
    133
    134     int inflateInit(ZStream z, int w, WrapperType wrapperType) {
    135         z.msg = null;
    136         blocks = null;
    137
    138         this.wrapperType = wrapperType;
    139
    140         if (w < 0) {
    141             throw new IllegalArgumentException("w: " + w);
    142         }
    143
    144         // set window size
    145         if (w < 8 || w > 15) {
    146             inflateEnd(z);
    147             return JZlib.Z_STREAM_ERROR;
    148         }
    149         wbits = w;
    150
    151         z.istate.blocks = new InfBlocks(
    152                 z, z.istate.wrapperType == WrapperType.NONE? null : this,
    153                 1 << w);
    154
    155         // reset state
    156         inflateReset(z);
    157         return JZlib.Z_OK;
    158     }
    159
    160     int inflate(ZStream z, int f) {
    161         int r;
    162         int b;
    163
    164         if (z == null || z.istate == null || z.next_in == null) {
    165             return JZlib.Z_STREAM_ERROR;
    166         }
    167         f = f == JZlib.Z_FINISH? JZlib.Z_BUF_ERROR : JZlib.Z_OK;
    168         r = JZlib.Z_BUF_ERROR;
    169         while (true) {
    170             //System.out.println("mode: "+z.istate.mode);
    171             switch (z.istate.mode) {
    172             case METHOD:
    173
    174                 if (z.avail_in == 0) {
    175                     return r;
    176                 }
    177                 r = f;
    178
    179                 z.avail_in --;
    180                 z.total_in ++;
    181                 if (((z.istate.method = z.next_in[z.next_in_index ++]) & 0xf) != JZlib.Z_DEFLATED) {
    182                     z.istate.mode = BAD;
    183                     z.msg = "unknown compression method";
    184                     z.istate.marker = 5; // can't try inflateSync
    185                     break;
    186                 }
    187                 if ((z.istate.method >> 4) + 8 > z.istate.wbits) {
    188                     z.istate.mode = BAD;
    189                     z.msg = "invalid window size";
    190                     z.istate.marker = 5; // can't try inflateSync
    191                     break;
    192                 }
    193                 z.istate.mode = FLAG;
    194             case FLAG:
    195
    196                 if (z.avail_in == 0) {
    197                     return r;
    198                 }
    199                 r = f;
    200
    201                 z.avail_in --;
    202                 z.total_in ++;
    203                 b = z.next_in[z.next_in_index ++] & 0xff;
    204
    205                 if (((z.istate.method << 8) + b) % 31 != 0) {
    206                     z.istate.mode = BAD;
    207                     z.msg = "incorrect header check";
    208                     z.istate.marker = 5; // can't try inflateSync
    209                     break;
    210                 }
    211
    212                 if ((b & JZlib.PRESET_DICT) == 0) {
    213                     z.istate.mode = BLOCKS;
    214                     break;
    215                 }
    216                 z.istate.mode = DICT4;
    217             case DICT4:
    218
    219                 if (z.avail_in == 0) {
    220                     return r;
    221                 }
    222                 r = f;
    223
    224                 z.avail_in --;
    225                 z.total_in ++;
    226                 z.istate.need = (z.next_in[z.next_in_index ++] & 0xff) << 24 & 0xff000000L;
    227                 z.istate.mode = DICT3;
    228             case DICT3:
    229
    230                 if (z.avail_in == 0) {
    231                     return r;
    232                 }
    233                 r = f;
    234
    235                 z.avail_in --;
    236                 z.total_in ++;
    237                 z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 16 & 0xff0000L;
    238                 z.istate.mode = DICT2;
    239             case DICT2:
    240
    241                 if (z.avail_in == 0) {
    242                     return r;
    243                 }
    244                 r = f;
    245
    246                 z.avail_in --;
    247                 z.total_in ++;
    248                 z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 8 & 0xff00L;
    249                 z.istate.mode = DICT1;
    250             case DICT1:
    251
    252                 if (z.avail_in == 0) {
    253                     return r;
    254                 }
    255
    256                 z.avail_in --;
    257                 z.total_in ++;
    258                 z.istate.need += z.next_in[z.next_in_index ++] & 0xffL;
    259                 z.adler = z.istate.need;
    260                 z.istate.mode = DICT0;
    261                 return JZlib.Z_NEED_DICT;
    262             case DICT0:
    263                 z.istate.mode = BAD;
    264                 z.msg = "need dictionary";
    265                 z.istate.marker = 0; // can try inflateSync
    266                 return JZlib.Z_STREAM_ERROR;
    267             case BLOCKS:
    268                 int old_next_out_index = z.next_out_index;
    269                 try {
    270                     r = z.istate.blocks.proc(z, r);
    271                     if (r == JZlib.Z_DATA_ERROR) {
    272                         z.istate.mode = BAD;
    273                         z.istate.marker = 0; // can try inflateSync
    274                         break;
    275                     }
    276                     if (r == JZlib.Z_OK) {
    277                         r = f;
    278                     }
    279                     if (r != JZlib.Z_STREAM_END) {
    280                         return r;
    281                     }
    282                     r = f;
    283                     z.istate.blocks.reset(z, z.istate.was);
    284                 } finally {
    285                     int decompressedBytes = z.next_out_index - old_next_out_index;
    286                     gzipUncompressedBytes += decompressedBytes;
    287                     z.crc32 = CRC32.crc32(z.crc32, z.next_out, old_next_out_index, decompressedBytes);
    288                 }
    289                 if (z.istate.wrapperType == WrapperType.NONE) {
    290                     z.istate.mode = DONE;
    291                     break;
    292                 } else if (z.istate.wrapperType == WrapperType.ZLIB) {
    293                     z.istate.mode = CHECK4;
    294                 } else {
    295                     gzipCRC32 = 0;
    296                     gzipISize = 0;
    297                     gzipBytesToRead = 4;
    298                     z.istate.mode = GZIP_CRC32;
    299                     break;
    300                 }
    301             case CHECK4:
    302                 if (z.avail_in == 0) {
    303                     return r;
    304                 }
    305                 r = f;
    306
    307                 z.avail_in --;
    308                 z.total_in ++;
    309                 z.istate.need = (z.next_in[z.next_in_index ++] & 0xff) << 24 & 0xff000000L;
    310                 z.istate.mode = CHECK3;
    311             case CHECK3:
    312                 if (z.avail_in == 0) {
    313                     return r;
    314                 }
    315                 r = f;
    316
    317                 z.avail_in --;
    318                 z.total_in ++;
    319                 z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 16 & 0xff0000L;
    320                 z.istate.mode = CHECK2;
    321             case CHECK2:
    322                 if (z.avail_in == 0) {
    323                     return r;
    324                 }
    325                 r = f;
    326
    327                 z.avail_in --;
    328                 z.total_in ++;
    329                 z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 8 & 0xff00L;
    330                 z.istate.mode = CHECK1;
    331             case CHECK1:
    332                 if (z.avail_in == 0) {
    333                     return r;
    334                 }
    335                 r = f;
    336
    337                 z.avail_in --;
    338                 z.total_in ++;
    339                 z.istate.need += z.next_in[z.next_in_index ++] & 0xffL;
    340
    341                 if ((int) z.istate.was[0] != (int) z.istate.need) {
    342                     z.istate.mode = BAD;
    343                     z.msg = "incorrect data check";
    344                     z.istate.marker = 5; // can't try inflateSync
    345                     break;
    346                 }
    347
    348                 z.istate.mode = DONE;
    349             case DONE:
    350                 return JZlib.Z_STREAM_END;
    351             case BAD:
    352                 return JZlib.Z_DATA_ERROR;
    353             case GZIP_ID1:
    354                 if (z.avail_in == 0) {
    355                     return r;
    356                 }
    357                 r = f;
    358                 z.avail_in --;
    359                 z.total_in ++;
    360
    361                 if ((z.next_in[z.next_in_index ++] & 0xff) != 31) {
    362                     z.istate.mode = BAD;
    363                     z.msg = "not a gzip stream";
    364                     z.istate.marker = 5; // can't try inflateSync
    365                     break;
    366                 }
    367                 z.istate.mode = GZIP_ID2;
    368             case GZIP_ID2:
    369                 if (z.avail_in == 0) {
    370                     return r;
    371                 }
    372                 r = f;
    373                 z.avail_in --;
    374                 z.total_in ++;
    375
    376                 if ((z.next_in[z.next_in_index ++] & 0xff) != 139) {
    377                     z.istate.mode = BAD;
    378                     z.msg = "not a gzip stream";
    379                     z.istate.marker = 5; // can't try inflateSync
    380                     break;
    381                 }
    382                 z.istate.mode = GZIP_CM;
    383             case GZIP_CM:
    384                 if (z.avail_in == 0) {
    385                     return r;
    386                 }
    387                 r = f;
    388                 z.avail_in --;
    389                 z.total_in ++;
    390
    391                 if ((z.next_in[z.next_in_index ++] & 0xff) != JZlib.Z_DEFLATED) {
    392                     z.istate.mode = BAD;
    393                     z.msg = "unknown compression method";
    394                     z.istate.marker = 5; // can't try inflateSync
    395                     break;
    396                 }
    397                 z.istate.mode = GZIP_FLG;
    398             case GZIP_FLG:
    399                 if (z.avail_in == 0) {
    400                     return r;
    401                 }
    402                 r = f;
    403                 z.avail_in --;
    404                 z.total_in ++;
    405                 gzipFlag = z.next_in[z.next_in_index ++] & 0xff;
    406
    407                 if ((gzipFlag & 0xE2) != 0) {
    408                     z.istate.mode = BAD;
    409                     z.msg = "unsupported flag";
    410                     z.istate.marker = 5; // can't try inflateSync
    411                     break;
    412                 }
    413                 gzipBytesToRead = 6;
    414                 z.istate.mode = GZIP_MTIME_XFL_OS;
    415             case GZIP_MTIME_XFL_OS:
    416                 while (gzipBytesToRead > 0) {
    417                     if (z.avail_in == 0) {
    418                         return r;
    419                     }
    420                     r = f;
    421                     z.avail_in --;
    422                     z.total_in ++;
    423                     z.next_in_index ++;
    424                     gzipBytesToRead --;
    425                 }
    426                 z.istate.mode = GZIP_XLEN;
    427                 gzipXLen = 0;
    428                 gzipBytesToRead = 2;
    429             case GZIP_XLEN:
    430                 if ((gzipFlag & 4) != 0) {
    431                     while (gzipBytesToRead > 0) {
    432                         if (z.avail_in == 0) {
    433                             return r;
    434                         }
    435                         r = f;
    436                         z.avail_in --;
    437                         z.total_in ++;
    438                         gzipXLen |= (z.next_in[z.next_in_index ++] & 0xff) << (1 - gzipBytesToRead) * 8;
    439                         gzipBytesToRead --;
    440                     }
    441                     gzipBytesToRead = gzipXLen;
    442                     z.istate.mode = GZIP_FEXTRA;
    443                 } else {
    444                     z.istate.mode = GZIP_FNAME;
    445                     break;
    446                 }
    447             case GZIP_FEXTRA:
    448                 while (gzipBytesToRead > 0) {
    449                     if (z.avail_in == 0) {
    450                         return r;
    451                     }
    452                     r = f;
    453                     z.avail_in --;
    454                     z.total_in ++;
    455                     z.next_in_index ++;
    456                     gzipBytesToRead --;
    457                 }
    458                 z.istate.mode = GZIP_FNAME;
    459             case GZIP_FNAME:
    460                 if ((gzipFlag & 8) != 0) {
    461                     do {
    462                         if (z.avail_in == 0) {
    463                             return r;
    464                         }
    465                         r = f;
    466                         z.avail_in --;
    467                         z.total_in ++;
    468                     } while (z.next_in[z.next_in_index ++] != 0);
    469                 }
    470                 z.istate.mode = GZIP_FCOMMENT;
    471             case GZIP_FCOMMENT:
    472                 if ((gzipFlag & 16) != 0) {
    473                     do {
    474                         if (z.avail_in == 0) {
    475                             return r;
    476                         }
    477                         r = f;
    478                         z.avail_in --;
    479                         z.total_in ++;
    480                     } while (z.next_in[z.next_in_index ++] != 0);
    481                 }
    482                 gzipBytesToRead = 2;
    483                 z.istate.mode = GZIP_FHCRC;
    484             case GZIP_FHCRC:
    485                 if ((gzipFlag & 2) != 0) {
    486                     while (gzipBytesToRead > 0) {
    487                         if (z.avail_in == 0) {
    488                             return r;
    489                         }
    490                         r = f;
    491                         z.avail_in --;
    492                         z.total_in ++;
    493                         z.next_in_index ++;
    494                         gzipBytesToRead --;
    495                     }
    496                 }
    497                 z.istate.mode = BLOCKS;
    498                 break;
    499             case GZIP_CRC32:
    500                 while (gzipBytesToRead > 0) {
    501                     if (z.avail_in == 0) {
    502                         return r;
    503                     }
    504                     r = f;
    505                     z.avail_in --;
    506                     z.total_in ++;
    507                     gzipBytesToRead --;
    508                     z.istate.gzipCRC32 |= (z.next_in[z.next_in_index ++] & 0xff) << (3 - gzipBytesToRead) * 8;
    509                 }
    510
    511                 if (z.crc32 != z.istate.gzipCRC32) {
    512                     z.istate.mode = BAD;
    513                     z.msg = "incorrect CRC32 checksum";
    514                     z.istate.marker = 5; // can't try inflateSync
    515                     break;
    516                 }
    517                 gzipBytesToRead = 4;
    518                 z.istate.mode = GZIP_ISIZE;
    519             case GZIP_ISIZE:
    520                 while (gzipBytesToRead > 0) {
    521                     if (z.avail_in == 0) {
    522                         return r;
    523                     }
    524                     r = f;
    525                     z.avail_in --;
    526                     z.total_in ++;
    527                     gzipBytesToRead --;
    528                     z.istate.gzipISize |= (z.next_in[z.next_in_index ++] & 0xff) << (3 - gzipBytesToRead) * 8;
    529                 }
    530
    531                 if (gzipUncompressedBytes != z.istate.gzipISize) {
    532                     z.istate.mode = BAD;
    533                     z.msg = "incorrect ISIZE checksum";
    534                     z.istate.marker = 5; // can't try inflateSync
    535                     break;
    536                 }
    537
    538                 z.istate.mode = DONE;
    539                 break;
    540             default:
    541                 return JZlib.Z_STREAM_ERROR;
    542             }
    543         }
    544     }
    545
    546     int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength) {
    547         int index = 0;
    548         int length = dictLength;
    549         if (z == null || z.istate == null || z.istate.mode != DICT0) {
    550             return JZlib.Z_STREAM_ERROR;
    551         }
    552
    553         if (Adler32.adler32(1L, dictionary, 0, dictLength) != z.adler) {
    554             return JZlib.Z_DATA_ERROR;
    555         }
    556
    557         z.adler = Adler32.adler32(0, null, 0, 0);
    558
    559         if (length >= 1 << z.istate.wbits) {
    560             length = (1 << z.istate.wbits) - 1;
    561             index = dictLength - length;
    562         }
    563         z.istate.blocks.set_dictionary(dictionary, index, length);
    564         z.istate.mode = BLOCKS;
    565         return JZlib.Z_OK;
    566     }
    567
    568     private static final byte[] mark = { (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff };
    569
    570     int inflateSync(ZStream z) {
    571         int n; // number of bytes to look at
    572         int p; // pointer to bytes
    573         int m; // number of marker bytes found in a row
    574         long r, w; // temporaries to save total_in and total_out
    575
    576         // set up
    577         if (z == null || z.istate == null) {
    578             return JZlib.Z_STREAM_ERROR;
    579         }
    580         if (z.istate.mode != BAD) {
    581             z.istate.mode = BAD;
    582             z.istate.marker = 0;
    583         }
    584         if ((n = z.avail_in) == 0) {
    585             return JZlib.Z_BUF_ERROR;
    586         }
    587         p = z.next_in_index;
    588         m = z.istate.marker;
    589
    590         // search
    591         while (n != 0 && m < 4) {
    592             if (z.next_in[p] == mark[m]) {
    593                 m ++;
    594             } else if (z.next_in[p] != 0) {
    595                 m = 0;
    596             } else {
    597                 m = 4 - m;
    598             }
    599             p ++;
    600             n --;
    601         }
    602
    603         // restore
    604         z.total_in += p - z.next_in_index;
    605         z.next_in_index = p;
    606         z.avail_in = n;
    607         z.istate.marker = m;
    608
    609         // return no joy or set up to restart on a new block
    610         if (m != 4) {
    611             return JZlib.Z_DATA_ERROR;
    612         }
    613         r = z.total_in;
    614         w = z.total_out;
    615         inflateReset(z);
    616         z.total_in = r;
    617         z.total_out = w;
    618         z.istate.mode = BLOCKS;
    619         return JZlib.Z_OK;
    620     }
    621 }