Changeset 2771


Ignore:
Timestamp:
05/09/07 08:52:54 (13 years ago)
Author:
melissa
Message:

Added support for bz2-compressed files.

Location:
trunk/loci/formats
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/formats/FormatHandler.java

    r2738 r2771  
    124124      if (lname.endsWith("." + suffixes[i])) return true; 
    125125      if (lname.endsWith("." + suffixes[i] + ".gz")) return true; 
    126       //if (lname.endsWith("." + suffixes[i] + ".bz2")) return true; 
     126      if (lname.endsWith("." + suffixes[i] + ".bz2")) return true; 
    127127      if (lname.endsWith("." + suffixes[i] + ".zip")) return true; 
    128128    } 
  • trunk/loci/formats/RandomAccessStream.java

    r2753 r2771  
    2828import java.util.*; 
    2929import java.util.zip.*; 
     30import loci.formats.in.CBZip2InputStream; 
    3031 
    3132/** 
     
    154155        dis = new DataInputStream(zip);  
    155156      } 
    156       /* 
    157157      else if (path.endsWith(".bz2")) { 
     158        bis.skip(2); 
    158159        dis = new DataInputStream(new CBZip2InputStream(bis)); 
    159160        compressed = true; 
    160161 
    161162        length = 0; 
    162  
     163       
    163164        int s = 0; 
     165 
    164166        while (s != -1) { 
    165           s = dis.read();  
    166           length++;  
     167          s = dis.read(); 
     168          length++; 
    167169        } 
    168170 
    169171        bis = new BufferedInputStream( 
    170172          new FileInputStream(Location.getMappedId(file)), MAX_OVERHEAD); 
     173        bis.skip(2); 
    171174        dis = new DataInputStream(new CBZip2InputStream(bis)); 
    172175      } 
    173       */ 
    174176      else dis = new DataInputStream(bis); 
    175177 
     
    538540        } 
    539541        else if (path.endsWith(".zip")) { 
    540           //dis = new DataInputStream(new ZipInputStream(bis)); 
    541542          ZipFile zf = new ZipFile(Location.getMappedId(file)); 
    542543          InputStream zip = new BufferedInputStream(zf.getInputStream( 
     
    544545          dis = new DataInputStream(zip);  
    545546        } 
    546         /* 
    547547        else if (path.endsWith(".bz2")) { 
     548          bis.skip(2);  
    548549          dis = new DataInputStream(new CBZip2InputStream(bis)); 
    549550        } 
    550         */ 
    551551        fp = 0; 
    552552      } 
     
    675675        compressed = true; 
    676676      } 
    677       /* 
    678677      else if (path.endsWith(".bz2")) { 
     678        bis.skip(2);  
    679679        dis = new DataInputStream(new CBZip2InputStream(bis)); 
    680680        compressed = true; 
    681681      } 
    682       */ 
    683682      else dis = new DataInputStream(bis); 
    684683 
  • trunk/loci/formats/in/CBZip2InputStream.java

    r2178 r2771  
    1 // 
    2 // CBZip2InputStream.java 
    3 // 
    4  
    51/* 
    6 LOCI Bio-Formats package for reading and converting biological file formats. 
    7 Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden, Chris Allan, 
    8 Eric Kjellman and Brian Loranger. 
    9  
    10 This program is free software; you can redistribute it and/or modify 
    11 it under the terms of the GNU Library General Public License as published by 
    12 the Free Software Foundation; either version 2 of the License, or 
    13 (at your option) any later version. 
    14  
    15 This program is distributed in the hope that it will be useful, 
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of 
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    18 GNU Library General Public License for more details. 
    19  
    20 You should have received a copy of the GNU Library General Public License 
    21 along with this program; if not, write to the Free Software 
    22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
    23 */ 
    24  
    25 /* 
    26  * Copyright  2001-2004 The Apache Software Foundation 
     2 *  Licensed to the Apache Software Foundation (ASF) under one or more 
     3 *  contributor license agreements.  See the NOTICE file distributed with 
     4 *  this work for additional information regarding copyright ownership. 
     5 *  The ASF licenses this file to You under the Apache License, Version 2.0 
     6 *  (the "License"); you may not use this file except in compliance with 
     7 *  the License.  You may obtain a copy of the License at 
    278 * 
    28  *  Licensed under the Apache License, Version 2.0 (the "License"); 
    29  *  you may not use this file except in compliance with the License. 
    30  *  You may obtain a copy of the License at 
    31  * 
    32  *    http://www.apache.org/licenses/LICENSE-2.0 
     9 *      http://www.apache.org/licenses/LICENSE-2.0 
    3310 * 
    3411 *  Unless required by applicable law or agreed to in writing, software 
     
    4724package loci.formats.in; 
    4825 
     26import java.io.InputStream; 
    4927import java.io.IOException; 
    50 import java.io.InputStream; 
    5128 
    5229/** 
    5330 * An input stream that decompresses from the BZip2 format (without the file 
    5431 * header chars) to be read as any other stream. 
     32 * 
     33 * <p>The decompression requires large amounts of memory. Thus you 
     34 * should call the {@link #close() close()} method as soon as 
     35 * possible, to force <tt>CBZip2InputStream</tt> to release the 
     36 * allocated memory.  See {@link CBZip2OutputStream 
     37 * CBZip2OutputStream} for information about memory usage.</p> 
     38 * 
     39 * <p><tt>CBZip2InputStream</tt> reads bytes from the compressed 
     40 * source stream via the single byte {@link java.io.InputStream#read() 
     41 * read()} method exclusively. Thus you should consider to use a 
     42 * buffered source stream.</p> 
     43 *  
     44 * <p>Instances of this class are not threadsafe.</p> 
    5545 */ 
    5646public class CBZip2InputStream extends InputStream implements BZip2Constants { 
    57   private static void cadvise() { 
    58     System.out.println("CRC Error"); 
    59     //throw new CCoruptionError(); 
    60   } 
    61  
    62   private static void compressedStreamEOF() { 
    63     cadvise(); 
    64   } 
    65  
    66   private void makeMaps() { 
    67     int q; 
    68     nInUse = 0; 
    69     for (q = 0; q < 256; q++) { 
    70       if (inUse[q]) { 
    71         seqToUnseq[nInUse] = (char) q; 
    72         unseqToSeq[q] = (char) nInUse; 
    73         nInUse++; 
    74       } 
    75     } 
    76   } 
    77  
    78   /* 
    79     index of the last char in the block, so 
    80     the block size == last + 1. 
    81   */ 
    82   private int  last; 
    83  
    84   /* 
    85     index in zptr[] of original string after sorting. 
    86   */ 
    87   private int  origPtr; 
    88  
    89   /* 
    90     always: in the range 0 .. 9. 
    91     The current block size is 100000 * this number. 
    92   */ 
    93   private int blockSize100k; 
    94  
    95   private boolean blockRandomised; 
    96  
    97   private int bsBuff; 
    98   private int bsLive; 
    99   private CRC mCrc = new CRC(); 
    100  
    101   private boolean[] inUse = new boolean[256]; 
    102   private int nInUse; 
    103  
    104   private char[] seqToUnseq = new char[256]; 
    105   private char[] unseqToSeq = new char[256]; 
    106  
    107   private char[] selector = new char[MAX_SELECTORS]; 
    108   private char[] selectorMtf = new char[MAX_SELECTORS]; 
    109  
    110   private int[] tt; 
    111   private char[] ll8; 
    112  
    113   /* 
    114     freq table collected to save a pass over the data 
    115     during decompression. 
    116   */ 
    117   private int[] unzftab = new int[256]; 
    118  
    119   private int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; 
    120   private int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; 
    121   private int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; 
    122   private int[] minLens = new int[N_GROUPS]; 
    123  
    124   private InputStream bsStream; 
    125  
    126   private boolean streamEnd = false; 
    127  
    128   private int currentChar = -1; 
    129  
    130   private static final int START_BLOCK_STATE = 1; 
    131   private static final int RAND_PART_A_STATE = 2; 
    132   private static final int RAND_PART_B_STATE = 3; 
    133   private static final int RAND_PART_C_STATE = 4; 
    134   private static final int NO_RAND_PART_A_STATE = 5; 
    135   private static final int NO_RAND_PART_B_STATE = 6; 
    136   private static final int NO_RAND_PART_C_STATE = 7; 
    137  
    138   private int currentState = START_BLOCK_STATE; 
    139  
    140   private int storedBlockCRC, storedCombinedCRC; 
    141   private int computedBlockCRC, computedCombinedCRC; 
    142  
    143   protected int i2, count, chPrev, ch2; 
    144   protected int i, tPos; 
    145   protected int rNToGo = 0; 
    146   protected int rTPos  = 0; 
    147   protected int j2; 
    148   protected char z; 
    149  
    150   public CBZip2InputStream(InputStream zStream) { 
    151     ll8 = null; 
    152     tt = null; 
    153     bsSetStream(zStream); 
    154     initialize(); 
    155     initBlock(); 
    156     setupBlock(); 
    157   } 
    158  
    159   public int read() { 
    160     if (streamEnd) { 
    161       return -1; 
    162     } 
    163     else { 
    164       int retChar = currentChar; 
    165       switch (currentState) { 
     47 
     48    private static void reportCRCError() throws IOException { 
     49        // The clean way would be to throw an exception. 
     50        //throw new IOException("crc error"); 
     51 
     52        // Just print a message, like the previous versions of this class did 
     53        System.err.println("BZip2 CRC error"); 
     54    } 
     55 
     56    private void makeMaps() { 
     57        final boolean[] inUse   = this.data.inUse; 
     58        final byte[] seqToUnseq = this.data.seqToUnseq; 
     59 
     60        int nInUseShadow = 0; 
     61 
     62        for (int i = 0; i < 256; i++) { 
     63            if (inUse[i]) 
     64                seqToUnseq[nInUseShadow++] = (byte) i; 
     65        } 
     66 
     67        this.nInUse = nInUseShadow; 
     68    } 
     69 
     70    /** 
     71     * Index of the last char in the block, so the block size == last + 1. 
     72     */ 
     73    private int  last; 
     74 
     75    /** 
     76     * Index in zptr[] of original string after sorting. 
     77     */ 
     78    private int  origPtr; 
     79 
     80    /** 
     81     * always: in the range 0 .. 9. 
     82     * The current block size is 100000 * this number. 
     83     */ 
     84    private int blockSize100k; 
     85 
     86    private boolean blockRandomised; 
     87 
     88    private int bsBuff; 
     89    private int bsLive; 
     90    private final CRC crc = new CRC(); 
     91 
     92    private int nInUse; 
     93 
     94    private InputStream in; 
     95 
     96    private int currentChar = -1; 
     97 
     98    private static final int EOF                  = 0; 
     99    private static final int START_BLOCK_STATE = 1; 
     100    private static final int RAND_PART_A_STATE = 2; 
     101    private static final int RAND_PART_B_STATE = 3; 
     102    private static final int RAND_PART_C_STATE = 4; 
     103    private static final int NO_RAND_PART_A_STATE = 5; 
     104    private static final int NO_RAND_PART_B_STATE = 6; 
     105    private static final int NO_RAND_PART_C_STATE = 7; 
     106 
     107    private int currentState = START_BLOCK_STATE; 
     108 
     109    private int storedBlockCRC, storedCombinedCRC; 
     110    private int computedBlockCRC, computedCombinedCRC; 
     111 
     112    // Variables used by setup* methods exclusively 
     113 
     114    private int su_count; 
     115    private int su_ch2; 
     116    private int su_chPrev; 
     117    private int su_i2; 
     118    private int su_j2; 
     119    private int su_rNToGo; 
     120    private int su_rTPos; 
     121    private int su_tPos; 
     122    private char su_z; 
     123 
     124    /** 
     125     * All memory intensive stuff. 
     126     * This field is initialized by initBlock(). 
     127     */ 
     128    private CBZip2InputStream.Data data; 
     129 
     130    /** 
     131     * Constructs a new CBZip2InputStream which decompresses bytes read from 
     132     * the specified stream. 
     133     * 
     134     * <p>Although BZip2 headers are marked with the magic 
     135     * <tt>"Bz"</tt> this constructor expects the next byte in the 
     136     * stream to be the first one after the magic.  Thus callers have 
     137     * to skip the first two bytes. Otherwise this constructor will 
     138     * throw an exception. </p> 
     139     * 
     140     * @throws IOException 
     141     *  if the stream content is malformed or an I/O error occurs. 
     142     * @throws NullPointerException 
     143     *  if <tt>in == null</tt> 
     144     */ 
     145    public CBZip2InputStream(final InputStream in) throws IOException { 
     146        super(); 
     147 
     148        this.in = in; 
     149        init(); 
     150    } 
     151 
     152    public int read() throws IOException { 
     153        if (this.in != null) { 
     154            return read0(); 
     155        } else { 
     156            throw new IOException("stream closed"); 
     157        } 
     158    } 
     159 
     160    public int read(final byte[] dest, final int offs, final int len) 
     161        throws IOException { 
     162        if (offs < 0) { 
     163            throw new IndexOutOfBoundsException("offs(" + offs + ") < 0."); 
     164        } 
     165        if (len < 0) { 
     166            throw new IndexOutOfBoundsException("len(" + len + ") < 0."); 
     167        } 
     168        if (offs + len > dest.length) { 
     169            throw new IndexOutOfBoundsException("offs(" + offs + ") + len(" 
     170                                                + len + ") > dest.length(" 
     171                                                + dest.length + ")."); 
     172        } 
     173        if (this.in == null) { 
     174            throw new IOException("stream closed"); 
     175        } 
     176 
     177        final int hi = offs + len; 
     178        int destOffs = offs; 
     179        for (int b; (destOffs < hi) && ((b = read0()) >= 0);) { 
     180            dest[destOffs++] = (byte) b; 
     181        } 
     182 
     183        return (destOffs == offs) ? -1 : (destOffs - offs); 
     184    } 
     185 
     186    private int read0() throws IOException { 
     187        final int retChar = this.currentChar; 
     188 
     189        switch (this.currentState) { 
     190        case EOF: 
     191            return -1; 
     192 
    166193        case START_BLOCK_STATE: 
    167           break; 
     194            throw new IllegalStateException(); 
     195 
    168196        case RAND_PART_A_STATE: 
    169           break; 
     197            throw new IllegalStateException(); 
     198 
    170199        case RAND_PART_B_STATE: 
    171           setupRandPartB(); 
    172           break; 
     200            setupRandPartB(); 
     201            break; 
     202 
    173203        case RAND_PART_C_STATE: 
    174           setupRandPartC(); 
    175           break; 
     204            setupRandPartC(); 
     205            break; 
     206 
    176207        case NO_RAND_PART_A_STATE: 
    177           break; 
     208            throw new IllegalStateException(); 
     209 
    178210        case NO_RAND_PART_B_STATE: 
    179           setupNoRandPartB(); 
    180           break; 
     211            setupNoRandPartB(); 
     212            break; 
     213 
    181214        case NO_RAND_PART_C_STATE: 
    182           setupNoRandPartC(); 
    183           break; 
     215            setupNoRandPartC(); 
     216            break; 
     217 
    184218        default: 
    185           break; 
    186       } 
    187       return retChar; 
    188     } 
    189   } 
    190  
    191   private void initialize() { 
    192     char magic3, magic4; 
    193     magic3 = bsGetUChar(); 
    194     magic4 = bsGetUChar(); 
    195  
    196     if (magic3 != 'h' || magic4 < '1' || magic4 > '9') { 
    197       bsFinishedWithStream(); 
    198       streamEnd = true; 
    199       return; 
    200     } 
    201  
    202     setDecompressStructureSizes(magic4 - '0'); 
    203     computedCombinedCRC = 0; 
    204   } 
    205  
    206   private void initBlock() { 
    207     char magic1, magic2, magic3, magic4; 
    208     char magic5, magic6; 
    209     magic1 = bsGetUChar(); 
    210     magic2 = bsGetUChar(); 
    211     magic3 = bsGetUChar(); 
    212     magic4 = bsGetUChar(); 
    213     magic5 = bsGetUChar(); 
    214     magic6 = bsGetUChar(); 
    215     if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && 
    216       magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) 
    217     { 
    218       complete(); 
    219       return; 
    220     } 
    221  
    222     if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || 
    223       magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) 
    224     { 
    225       badBlockHeader(); 
    226       streamEnd = true; 
    227       return; 
    228     } 
    229  
    230     storedBlockCRC = bsGetInt32(); 
    231  
    232     if (bsR(1) == 1) { 
    233       blockRandomised = true; 
    234     } 
    235     else { 
    236       blockRandomised = false; 
    237     } 
    238  
    239     //currBlockNo++; 
    240     getAndMoveToFrontDecode(); 
    241  
    242     mCrc.initialiseCRC(); 
    243     currentState = START_BLOCK_STATE; 
    244   } 
    245  
    246   private void endBlock() { 
    247     computedBlockCRC = mCrc.getFinalCRC(); 
    248     // A bad CRC is considered a fatal error. 
    249     if (storedBlockCRC != computedBlockCRC) { 
    250       crcError(); 
    251     } 
    252  
    253     computedCombinedCRC = (computedCombinedCRC << 1) | 
    254       (computedCombinedCRC >>> 31); 
    255     computedCombinedCRC ^= computedBlockCRC; 
    256   } 
    257  
    258   private void complete() { 
    259     storedCombinedCRC = bsGetInt32(); 
    260     if (storedCombinedCRC != computedCombinedCRC) { 
    261       crcError(); 
    262     } 
    263  
    264     bsFinishedWithStream(); 
    265     streamEnd = true; 
    266   } 
    267  
    268   private static void blockOverrun() { 
    269     cadvise(); 
    270   } 
    271  
    272   private static void badBlockHeader() { 
    273     cadvise(); 
    274   } 
    275  
    276   private static void crcError() { 
    277     cadvise(); 
    278   } 
    279  
    280   private void bsFinishedWithStream() { 
    281     try { 
    282       if (this.bsStream != null) { 
    283         if (this.bsStream != System.in) { 
    284           this.bsStream.close(); 
    285           this.bsStream = null; 
    286         } 
    287       } 
    288     } 
    289     catch (IOException ioe) { 
    290       //ignore 
    291     } 
    292   } 
    293  
    294   private void bsSetStream(InputStream f) { 
    295     bsStream = f; 
    296     bsLive = 0; 
    297     bsBuff = 0; 
    298   } 
    299  
    300   private int bsR(int n) { 
    301     int v; 
    302     while (bsLive < n) { 
    303       int zzi; 
    304       char thech = 0; 
    305       try { 
    306         thech = (char) bsStream.read(); 
    307       } 
    308       catch (IOException e) { 
    309         compressedStreamEOF(); 
    310       } 
    311       if (thech == -1) { 
    312         compressedStreamEOF(); 
    313       } 
    314       zzi = thech; 
    315       bsBuff = (bsBuff << 8) | (zzi & 0xff); 
    316       bsLive += 8; 
    317     } 
    318  
    319     v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); 
    320     bsLive -= n; 
    321     return v; 
    322   } 
    323  
    324   private char bsGetUChar() { 
    325     return (char) bsR(8); 
    326   } 
    327  
    328   private int bsGetint() { 
    329     int u = 0; 
    330     u = (u << 8) | bsR(8); 
    331     u = (u << 8) | bsR(8); 
    332     u = (u << 8) | bsR(8); 
    333     u = (u << 8) | bsR(8); 
    334     return u; 
    335   } 
    336  
    337   private int bsGetIntVS(int numBits) { 
    338     return (int) bsR(numBits); 
    339   } 
    340  
    341   private int bsGetInt32() { 
    342     return (int) bsGetint(); 
    343   } 
    344  
    345   private void hbCreateDecodeTables(int[] tLimit, int[] tBase, 
    346     int[] tPerm, char[] length, int minLen, int maxLen, int alphaSize) 
    347   { 
    348     int pp, q, j, vec; 
    349  
    350     pp = 0; 
    351     for (q = minLen; q <= maxLen; q++) { 
    352       for (j = 0; j < alphaSize; j++) { 
    353         if (length[j] == q) { 
    354           tPerm[pp] = j; 
    355           pp++; 
    356         } 
    357       } 
    358     } 
    359  
    360     for (q = 0; q < MAX_CODE_LEN; q++) { 
    361       tBase[q] = 0; 
    362     } 
    363     for (q = 0; q < alphaSize; q++) { 
    364       tBase[length[q] + 1]++; 
    365     } 
    366  
    367     for (q = 1; q < MAX_CODE_LEN; q++) { 
    368       tBase[q] += tBase[q - 1]; 
    369     } 
    370  
    371     for (q = 0; q < MAX_CODE_LEN; q++) { 
    372       tLimit[q] = 0; 
    373     } 
    374     vec = 0; 
    375  
    376     for (q = minLen; q <= maxLen; q++) { 
    377       vec += (tBase[q + 1] - tBase[q]); 
    378       tLimit[q] = vec - 1; 
    379       vec <<= 1; 
    380     } 
    381     for (q = minLen + 1; q <= maxLen; q++) { 
    382       tBase[q] = ((tLimit[q - 1] + 1) << 1) - tBase[q]; 
    383     } 
    384   } 
    385  
    386   private void recvDecodingTables() { 
    387     char[][] len = new char[N_GROUPS][MAX_ALPHA_SIZE]; 
    388     int q, j, t, nGroups, nSelectors, alphaSize; 
    389     int minLen, maxLen; 
    390     boolean[] inUse16 = new boolean[16]; 
    391  
    392     /* Receive the mapping table */ 
    393     for (q = 0; q < 16; q++) { 
    394       if (bsR(1) == 1) { 
    395         inUse16[q] = true; 
    396       } 
    397       else { 
    398         inUse16[q] = false; 
    399       } 
    400     } 
    401  
    402     for (q = 0; q < 256; q++) { 
    403       inUse[q] = false; 
    404     } 
    405  
    406     for (q = 0; q < 16; q++) { 
    407       if (inUse16[q]) { 
    408         for (j = 0; j < 16; j++) { 
    409           if (bsR(1) == 1) { 
    410             inUse[q * 16 + j] = true; 
    411           } 
    412         } 
    413       } 
    414     } 
    415  
    416     makeMaps(); 
    417     alphaSize = nInUse + 2; 
    418  
    419     /* Now the selectors */ 
    420     nGroups = bsR(3); 
    421     nSelectors = bsR(15); 
    422     for (q = 0; q < nSelectors; q++) { 
    423       j = 0; 
    424       while (bsR(1) == 1) { 
    425         j++; 
    426       } 
    427       selectorMtf[q] = (char) j; 
    428     } 
    429  
    430     // undo the MTF values for the selectors. 
    431     char[] pos = new char[N_GROUPS]; 
    432     char tmp, v; 
    433     for (v = 0; v < nGroups; v++) { 
    434       pos[v] = v; 
    435     } 
    436  
    437     for (q = 0; q < nSelectors; q++) { 
    438       v = selectorMtf[q]; 
    439       tmp = pos[v]; 
    440       while (v > 0) { 
    441         pos[v] = pos[v - 1]; 
    442         v--; 
    443       } 
    444       pos[0] = tmp; 
    445       selector[q] = tmp; 
    446     } 
    447  
    448     /* Now the coding tables */ 
    449     for (t = 0; t < nGroups; t++) { 
    450       int curr = bsR(5); 
    451       for (q = 0; q < alphaSize; q++) { 
    452         while (bsR(1) == 1) { 
    453           if (bsR(1) == 0) { 
    454             curr++; 
    455           } 
    456           else { 
    457             curr--; 
    458           } 
    459         } 
    460         len[t][q] = (char) curr; 
    461       } 
    462     } 
    463  
    464     /* Create the Huffman decoding tables */ 
    465     for (t = 0; t < nGroups; t++) { 
    466       minLen = 32; 
    467       maxLen = 0; 
    468       for (q = 0; q < alphaSize; q++) { 
    469         if (len[t][q] > maxLen) { 
    470           maxLen = len[t][q]; 
    471         } 
    472         if (len[t][q] < minLen) { 
    473           minLen = len[t][q]; 
    474         } 
    475       } 
    476       hbCreateDecodeTables(limit[t], base[t], perm[t], 
    477         len[t], minLen, maxLen, alphaSize); 
    478       minLens[t] = minLen; 
    479     } 
    480   } 
    481  
    482   private void getAndMoveToFrontDecode() { 
    483     char[] yy = new char[256]; 
    484     int q, j, nextSym, limitLast; 
    485     int eob, groupNo, groupPos; 
    486  
    487     limitLast = BASE_BLOCK_SIZE * blockSize100k; 
    488     origPtr = bsGetIntVS(24); 
    489  
    490     recvDecodingTables(); 
    491     eob = nInUse + 1; 
    492     groupNo = -1; 
    493     groupPos = 0; 
    494  
    495     /* 
    496       Setting up the unzftab entries here is not strictly 
    497       necessary, but it does save having to do it later 
    498       in a separate pass, and so saves a block's worth of 
    499       cache misses. 
    500     */ 
    501     for (q = 0; q <= 255; q++) { 
    502       unzftab[i] = 0; 
    503     } 
    504  
    505     for (q = 0; q <= 255; q++) { 
    506       yy[q] = (char) q; 
    507     } 
    508  
    509     last = -1; 
    510  
    511     int zt, zn, zvec, zj; 
    512     if (groupPos == 0) { 
    513       groupNo++; 
    514       groupPos = G_SIZE; 
    515     } 
    516     groupPos--; 
    517     zt = selector[groupNo]; 
    518     zn = minLens[zt]; 
    519     zvec = bsR(zn); 
    520     while (zvec > limit[zt][zn]) { 
    521       zn++; 
    522       while (bsLive < 1) { 
    523         int zzi; 
    524         char thech = 0; 
    525         try { 
    526           thech = (char) bsStream.read(); 
    527         } 
    528         catch (IOException e) { 
    529           compressedStreamEOF(); 
    530         } 
    531         if (thech == -1) { 
    532           compressedStreamEOF(); 
    533         } 
    534         zzi = thech; 
    535         bsBuff = (bsBuff << 8) | (zzi & 0xff); 
    536         bsLive += 8; 
    537       } 
    538       zj = (bsBuff >> (bsLive - 1)) & 1; 
    539       bsLive--; 
    540       zvec = (zvec << 1) | zj; 
    541     } 
    542     nextSym = perm[zt][zvec - base[zt][zn]]; 
    543  
    544     while (true) { 
    545  
    546       if (nextSym == eob) { 
    547         break; 
    548       } 
    549  
    550       if (nextSym == RUNA || nextSym == RUNB) { 
    551         char ch; 
    552         int s = -1; 
    553         int n = 1; 
    554         do { 
    555           if (nextSym == RUNA) { 
    556             s = s + (0 + 1) * n; 
    557           } 
    558           else if (nextSym == RUNB) { 
    559             s = s + (1 + 1) * n; 
    560           } 
    561           n *= 2; 
    562  
    563           //int zt, zn, zvec, zj; 
    564           if (groupPos == 0) { 
    565             groupNo++; 
    566             groupPos = G_SIZE; 
    567           } 
    568           groupPos--; 
    569           zt = selector[groupNo]; 
    570           zn = minLens[zt]; 
    571           zvec = bsR(zn); 
    572           while (zvec > limit[zt][zn]) { 
     219            throw new IllegalStateException(); 
     220        } 
     221 
     222        return retChar; 
     223    } 
     224 
     225    private void init() throws IOException { 
     226        int magic2 = this.in.read(); 
     227        if (magic2 != 'h') { 
     228            throw new IOException("Stream is not BZip2 formatted: expected 'h'" 
     229                                  + " as first byte but got '" + (char) magic2 
     230                                  + "'"); 
     231        } 
     232 
     233        int blockSize = this.in.read(); 
     234        if ((blockSize < '1') || (blockSize > '9')) { 
     235            throw new IOException("Stream is not BZip2 formatted: illegal " 
     236                                  + "blocksize " + (char) blockSize); 
     237        } 
     238 
     239        this.blockSize100k = blockSize - '0'; 
     240 
     241        initBlock(); 
     242        setupBlock(); 
     243    } 
     244 
     245    private void initBlock() throws IOException { 
     246        char magic0 = bsGetUByte(); 
     247        char magic1 = bsGetUByte(); 
     248        char magic2 = bsGetUByte(); 
     249        char magic3 = bsGetUByte(); 
     250        char magic4 = bsGetUByte(); 
     251        char magic5 = bsGetUByte(); 
     252 
     253        if (magic0 == 0x17 && 
     254            magic1 == 0x72 && 
     255            magic2 == 0x45 && 
     256            magic3 == 0x38 && 
     257            magic4 == 0x50 && 
     258            magic5 == 0x90) { 
     259            complete(); // end of file 
     260        } else if (magic0 != 0x31 || // '1' 
     261                   magic1 != 0x41 || // ')' 
     262                   magic2 != 0x59 || // 'Y' 
     263                   magic3 != 0x26 || // '&' 
     264                   magic4 != 0x53 || // 'S' 
     265                   magic5 != 0x59   // 'Y' 
     266                   ) { 
     267            this.currentState = EOF; 
     268            throw new IOException("bad block header"); 
     269        } else { 
     270            this.storedBlockCRC = bsGetInt(); 
     271            this.blockRandomised = bsR(1) == 1; 
     272 
     273            /** 
     274             * Allocate data here instead in constructor, so we do not 
     275             * allocate it if the input file is empty. 
     276             */ 
     277            if (this.data == null) { 
     278                this.data = new Data(this.blockSize100k); 
     279            } 
     280 
     281            // currBlockNo++; 
     282            getAndMoveToFrontDecode(); 
     283 
     284            this.crc.initialiseCRC(); 
     285            this.currentState = START_BLOCK_STATE; 
     286        } 
     287    } 
     288 
     289    private void endBlock() throws IOException { 
     290        this.computedBlockCRC = this.crc.getFinalCRC(); 
     291 
     292        // A bad CRC is considered a fatal error. 
     293        if (this.storedBlockCRC != this.computedBlockCRC) { 
     294            // make next blocks readable without error 
     295            // (repair feature, not yet documented, not tested) 
     296            this.computedCombinedCRC 
     297                = (this.storedCombinedCRC << 1) 
     298                | (this.storedCombinedCRC >>> 31); 
     299            this.computedCombinedCRC ^= this.storedBlockCRC; 
     300 
     301            reportCRCError(); 
     302        } 
     303 
     304        this.computedCombinedCRC 
     305            = (this.computedCombinedCRC << 1) 
     306            | (this.computedCombinedCRC >>> 31); 
     307        this.computedCombinedCRC ^= this.computedBlockCRC; 
     308    } 
     309 
     310    private void complete() throws IOException { 
     311        this.storedCombinedCRC = bsGetInt(); 
     312        this.currentState = EOF; 
     313        this.data = null; 
     314 
     315        if (this.storedCombinedCRC != this.computedCombinedCRC) { 
     316            reportCRCError(); 
     317        } 
     318    } 
     319 
     320    public void close() throws IOException { 
     321        InputStream inShadow = this.in; 
     322        if (inShadow != null) { 
     323            try { 
     324                if (inShadow != System.in) { 
     325                    inShadow.close(); 
     326                } 
     327            } finally { 
     328                this.data = null; 
     329                this.in = null; 
     330            } 
     331        } 
     332    } 
     333 
     334    private int bsR(final int n) throws IOException { 
     335        int bsLiveShadow = this.bsLive; 
     336        int bsBuffShadow = this.bsBuff; 
     337 
     338        if (bsLiveShadow < n) { 
     339            final InputStream inShadow = this.in; 
     340            do { 
     341                int thech = inShadow.read(); 
     342 
     343                if (thech < 0) { 
     344                    throw new IOException("unexpected end of stream"); 
     345                } 
     346 
     347                bsBuffShadow = (bsBuffShadow << 8) | thech; 
     348                bsLiveShadow += 8; 
     349            } while (bsLiveShadow < n); 
     350 
     351            this.bsBuff = bsBuffShadow; 
     352        } 
     353 
     354        this.bsLive = bsLiveShadow - n; 
     355        return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1); 
     356    } 
     357 
     358    private boolean bsGetBit() throws IOException { 
     359        int bsLiveShadow = this.bsLive; 
     360        int bsBuffShadow = this.bsBuff; 
     361 
     362        if (bsLiveShadow < 1) { 
     363            int thech = this.in.read(); 
     364 
     365            if (thech < 0) { 
     366                throw new IOException("unexpected end of stream"); 
     367            } 
     368 
     369            bsBuffShadow = (bsBuffShadow << 8) | thech; 
     370            bsLiveShadow += 8; 
     371            this.bsBuff = bsBuffShadow; 
     372        } 
     373 
     374        this.bsLive = bsLiveShadow - 1; 
     375        return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0; 
     376    } 
     377 
     378    private char bsGetUByte() throws IOException { 
     379        return (char) bsR(8); 
     380    } 
     381 
     382    private int bsGetInt() throws IOException { 
     383        return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8); 
     384    } 
     385 
     386    /** 
     387     * Called by createHuffmanDecodingTables() exclusively. 
     388     */ 
     389    private static void hbCreateDecodeTables(final int[] limit, 
     390                                             final int[] base, 
     391                                             final int[] perm, 
     392                                             final char[] length, 
     393                                             final int minLen, 
     394                                             final int maxLen, 
     395                                             final int alphaSize) { 
     396        for (int i = minLen, pp = 0; i <= maxLen; i++) { 
     397            for (int j = 0; j < alphaSize; j++) { 
     398                if (length[j] == i) { 
     399                    perm[pp++] = j; 
     400                } 
     401            } 
     402        } 
     403 
     404        for (int i = MAX_CODE_LEN; --i > 0;) { 
     405            base[i] = 0; 
     406            limit[i] = 0; 
     407        } 
     408 
     409        for (int i = 0; i < alphaSize; i++) { 
     410            base[length[i] + 1]++; 
     411        } 
     412 
     413        for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) { 
     414            b += base[i]; 
     415            base[i] = b; 
     416        } 
     417 
     418        for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) { 
     419            final int nb = base[i + 1]; 
     420            vec += nb - b; 
     421            b = nb; 
     422            limit[i] = vec - 1; 
     423            vec <<= 1; 
     424        } 
     425 
     426        for (int i = minLen + 1; i <= maxLen; i++) { 
     427            base[i] = ((limit[i - 1] + 1) << 1) - base[i]; 
     428        } 
     429    } 
     430 
     431    private void recvDecodingTables() throws IOException { 
     432        final Data dataShadow     = this.data; 
     433        final boolean[] inUse     = dataShadow.inUse; 
     434        final byte[] pos          = dataShadow.recvDecodingTables_pos; 
     435        final byte[] selector     = dataShadow.selector; 
     436        final byte[] selectorMtf  = dataShadow.selectorMtf; 
     437 
     438        int inUse16 = 0; 
     439 
     440        /* Receive the mapping table */ 
     441        for (int i = 0; i < 16; i++) { 
     442            if (bsGetBit()) { 
     443                inUse16 |= 1 << i; 
     444            } 
     445        } 
     446 
     447        for (int i = 256; --i >= 0;) { 
     448            inUse[i] = false; 
     449        } 
     450 
     451        for (int i = 0; i < 16; i++) { 
     452            if ((inUse16 & (1 << i)) != 0) { 
     453                final int i16 = i << 4; 
     454                for (int j = 0; j < 16; j++) { 
     455                    if (bsGetBit()) { 
     456                        inUse[i16 + j] = true; 
     457                    } 
     458                } 
     459            } 
     460        } 
     461 
     462        makeMaps(); 
     463        final int alphaSize = this.nInUse + 2; 
     464 
     465        /* Now the selectors */ 
     466        final int nGroups = bsR(3); 
     467        final int nSelectors = bsR(15); 
     468 
     469        for (int i = 0; i < nSelectors; i++) { 
     470            int j = 0; 
     471            while (bsGetBit()) { 
     472                j++; 
     473            } 
     474            selectorMtf[i] = (byte) j; 
     475        } 
     476 
     477        /* Undo the MTF values for the selectors. */ 
     478        for (int v = nGroups; --v >= 0;) { 
     479            pos[v] = (byte) v; 
     480        } 
     481 
     482        for (int i = 0; i < nSelectors; i++) { 
     483            int v = selectorMtf[i] & 0xff; 
     484            final byte tmp = pos[v]; 
     485            while (v > 0) { 
     486                // nearly all times v is zero, 4 in most other cases 
     487                pos[v] = pos[v - 1]; 
     488                v--; 
     489            } 
     490            pos[0] = tmp; 
     491            selector[i] = tmp; 
     492        } 
     493 
     494        final char[][] len  = dataShadow.temp_charArray2d; 
     495 
     496        /* Now the coding tables */ 
     497        for (int t = 0; t < nGroups; t++) { 
     498            int curr = bsR(5); 
     499            final char[] len_t = len[t]; 
     500            for (int i = 0; i < alphaSize; i++) { 
     501                while (bsGetBit()) { 
     502                    curr += bsGetBit() ? -1 : 1; 
     503                } 
     504                len_t[i] = (char) curr; 
     505            } 
     506        } 
     507 
     508        // finally create the Huffman tables 
     509        createHuffmanDecodingTables(alphaSize, nGroups); 
     510    } 
     511 
     512    /** 
     513     * Called by recvDecodingTables() exclusively. 
     514     */ 
     515    private void createHuffmanDecodingTables(final int alphaSize, 
     516                                             final int nGroups) { 
     517        final Data dataShadow = this.data; 
     518        final char[][] len  = dataShadow.temp_charArray2d; 
     519        final int[] minLens = dataShadow.minLens; 
     520        final int[][] limit = dataShadow.limit; 
     521        final int[][] base  = dataShadow.base; 
     522        final int[][] perm  = dataShadow.perm; 
     523 
     524        for (int t = 0; t < nGroups; t++) { 
     525            int minLen = 32; 
     526            int maxLen = 0; 
     527            final char[] len_t = len[t]; 
     528            for (int i = alphaSize; --i >= 0;) { 
     529                final char lent = len_t[i]; 
     530                if (lent > maxLen) { 
     531                    maxLen = lent; 
     532                } 
     533                if (lent < minLen) { 
     534                    minLen = lent; 
     535                } 
     536            } 
     537            hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen, 
     538                                 maxLen, alphaSize); 
     539            minLens[t] = minLen; 
     540        } 
     541    } 
     542 
     543    private void getAndMoveToFrontDecode() throws IOException { 
     544        this.origPtr = bsR(24); 
     545        recvDecodingTables(); 
     546 
     547        final InputStream inShadow = this.in; 
     548        final Data dataShadow   = this.data; 
     549        final byte[] ll8        = dataShadow.ll8; 
     550        final int[] unzftab     = dataShadow.unzftab; 
     551        final byte[] selector   = dataShadow.selector; 
     552        final byte[] seqToUnseq = dataShadow.seqToUnseq; 
     553        final char[] yy         = dataShadow.getAndMoveToFrontDecode_yy; 
     554        final int[] minLens     = dataShadow.minLens; 
     555        final int[][] limit     = dataShadow.limit; 
     556        final int[][] base      = dataShadow.base; 
     557        final int[][] perm      = dataShadow.perm; 
     558        final int limitLast     = this.blockSize100k * 100000; 
     559 
     560        /* 
     561          Setting up the unzftab entries here is not strictly 
     562          necessary, but it does save having to do it later 
     563          in a separate pass, and so saves a block's worth of 
     564          cache misses. 
     565        */ 
     566        for (int i = 256; --i >= 0;) { 
     567            yy[i] = (char) i; 
     568            unzftab[i] = 0; 
     569        } 
     570 
     571        int groupNo     = 0; 
     572        int groupPos    = G_SIZE - 1; 
     573        final int eob   = this.nInUse + 1; 
     574        int nextSym     = getAndMoveToFrontDecode0(0); 
     575        int bsBuffShadow      = this.bsBuff; 
     576        int bsLiveShadow      = this.bsLive; 
     577        int lastShadow        = -1; 
     578        int zt          = selector[groupNo] & 0xff; 
     579        int[] base_zt   = base[zt]; 
     580        int[] limit_zt  = limit[zt]; 
     581        int[] perm_zt   = perm[zt]; 
     582        int minLens_zt  = minLens[zt]; 
     583 
     584        while (nextSym != eob) { 
     585            if ((nextSym == RUNA) || (nextSym == RUNB)) { 
     586                int s = -1; 
     587 
     588                for (int n = 1; true; n <<= 1) { 
     589                    if (nextSym == RUNA) { 
     590                        s += n; 
     591                    } else if (nextSym == RUNB) { 
     592                        s += n << 1; 
     593                    } else { 
     594                        break; 
     595                    } 
     596 
     597                    if (groupPos == 0) { 
     598                        groupPos    = G_SIZE - 1; 
     599                        zt          = selector[++groupNo] & 0xff; 
     600                        base_zt     = base[zt]; 
     601                        limit_zt    = limit[zt]; 
     602                        perm_zt     = perm[zt]; 
     603                        minLens_zt  = minLens[zt]; 
     604                    } else { 
     605                        groupPos--; 
     606                    } 
     607 
     608                    int zn = minLens_zt; 
     609 
     610                    // Inlined: 
     611                    // int zvec = bsR(zn); 
     612                    while (bsLiveShadow < zn) { 
     613                        final int thech = inShadow.read(); 
     614                        if (thech >= 0) { 
     615                            bsBuffShadow = (bsBuffShadow << 8) | thech; 
     616                            bsLiveShadow += 8; 
     617                            continue; 
     618                        } else { 
     619                            throw new IOException("unexpected end of stream"); 
     620                        } 
     621                    } 
     622                    int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1); 
     623                    bsLiveShadow -= zn; 
     624 
     625                    while (zvec > limit_zt[zn]) { 
     626                        zn++; 
     627                        while (bsLiveShadow < 1) { 
     628                            final int thech = inShadow.read(); 
     629                            if (thech >= 0) { 
     630                                bsBuffShadow = (bsBuffShadow << 8) | thech; 
     631                                bsLiveShadow += 8; 
     632                                continue; 
     633                            } else { 
     634                                throw new IOException("unexpected end of stream"); 
     635                            } 
     636                        } 
     637                        bsLiveShadow--; 
     638                        zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); 
     639                    } 
     640                    nextSym = perm_zt[zvec - base_zt[zn]]; 
     641                } 
     642 
     643                final byte ch = seqToUnseq[yy[0]]; 
     644                unzftab[ch & 0xff] += s + 1; 
     645 
     646                while (s-- >= 0) { 
     647                    ll8[++lastShadow] = ch; 
     648                } 
     649 
     650                if (lastShadow >= limitLast) { 
     651                    throw new IOException("block overrun"); 
     652                } 
     653            } else { 
     654                if (++lastShadow >= limitLast) { 
     655                    throw new IOException("block overrun"); 
     656                } 
     657 
     658                final char tmp = yy[nextSym - 1]; 
     659                unzftab[seqToUnseq[tmp] & 0xff]++; 
     660                ll8[lastShadow] = seqToUnseq[tmp]; 
     661 
     662                /* 
     663                  This loop is hammered during decompression, 
     664                  hence avoid native method call overhead of 
     665                  System.arraycopy for very small ranges to copy. 
     666                */ 
     667                if (nextSym <= 16) { 
     668                    for (int j = nextSym - 1; j > 0;) { 
     669                        yy[j] = yy[--j]; 
     670                    } 
     671                } else { 
     672                    System.arraycopy(yy, 0, yy, 1, nextSym - 1); 
     673                } 
     674 
     675                yy[0] = tmp; 
     676 
     677                if (groupPos == 0) { 
     678                    groupPos    = G_SIZE - 1; 
     679                    zt          = selector[++groupNo] & 0xff; 
     680                    base_zt     = base[zt]; 
     681                    limit_zt    = limit[zt]; 
     682                    perm_zt     = perm[zt]; 
     683                    minLens_zt  = minLens[zt]; 
     684                } else { 
     685                    groupPos--; 
     686                } 
     687 
     688                int zn = minLens_zt; 
     689 
     690                // Inlined: 
     691                // int zvec = bsR(zn); 
     692                while (bsLiveShadow < zn) { 
     693                    final int thech = inShadow.read(); 
     694                    if (thech >= 0) { 
     695                        bsBuffShadow = (bsBuffShadow << 8) | thech; 
     696                        bsLiveShadow += 8; 
     697                        continue; 
     698                    } else { 
     699                        throw new IOException("unexpected end of stream"); 
     700                    } 
     701                } 
     702                int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1); 
     703                bsLiveShadow -= zn; 
     704 
     705                while (zvec > limit_zt[zn]) { 
     706                    zn++; 
     707                    while (bsLiveShadow < 1) { 
     708                        final int thech = inShadow.read(); 
     709                        if (thech >= 0) { 
     710                            bsBuffShadow = (bsBuffShadow << 8) | thech; 
     711                            bsLiveShadow += 8; 
     712                            continue; 
     713                        } else { 
     714                            throw new IOException("unexpected end of stream"); 
     715                        } 
     716                    } 
     717                    bsLiveShadow--; 
     718                    zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); 
     719                } 
     720                nextSym = perm_zt[zvec - base_zt[zn]]; 
     721            } 
     722        } 
     723 
     724        this.last = lastShadow; 
     725        this.bsLive = bsLiveShadow; 
     726        this.bsBuff = bsBuffShadow; 
     727    } 
     728 
     729    private int getAndMoveToFrontDecode0(final int groupNo) 
     730        throws IOException { 
     731        final InputStream inShadow  = this.in; 
     732        final Data dataShadow  = this.data; 
     733        final int zt          = dataShadow.selector[groupNo] & 0xff; 
     734        final int[] limit_zt  = dataShadow.limit[zt]; 
     735        int zn = dataShadow.minLens[zt]; 
     736        int zvec = bsR(zn); 
     737        int bsLiveShadow = this.bsLive; 
     738        int bsBuffShadow = this.bsBuff; 
     739 
     740        while (zvec > limit_zt[zn]) { 
    573741            zn++; 
    574             while (bsLive < 1) { 
    575               int zzi; 
    576               char thech = 0; 
    577               try { 
    578                 thech = (char) bsStream.read(); 
    579               } 
    580               catch (IOException e) { 
    581                 compressedStreamEOF(); 
    582               } 
    583               if (thech == -1) { 
    584                 compressedStreamEOF(); 
    585               } 
    586               zzi = thech; 
    587               bsBuff = (bsBuff << 8) | (zzi & 0xff); 
    588               bsLive += 8; 
    589             } 
    590             zj = (bsBuff >> (bsLive - 1)) & 1; 
    591             bsLive--; 
    592             zvec = (zvec << 1) | zj; 
    593           } 
    594           nextSym = perm[zt][zvec - base[zt][zn]]; 
    595         } 
    596         while (nextSym == RUNA || nextSym == RUNB); 
    597  
    598         s++; 
    599         ch = seqToUnseq[yy[0]]; 
    600         unzftab[ch] += s; 
    601  
    602         while (s > 0) { 
    603           last++; 
    604           ll8[last] = ch; 
    605           s--; 
    606         } 
    607  
    608         if (last >= limitLast) { 
    609           blockOverrun(); 
    610         } 
    611         continue; 
    612       } 
    613       else { 
    614         char tmp; 
    615         last++; 
    616         if (last >= limitLast) { 
    617           blockOverrun(); 
    618         } 
    619  
    620         tmp = yy[nextSym - 1]; 
    621         unzftab[seqToUnseq[tmp]]++; 
    622         ll8[last] = seqToUnseq[tmp]; 
    623  
    624         /* 
    625           This loop is hammered during decompression, 
    626           hence the unrolling. 
    627  
    628           for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; 
    629         */ 
    630  
    631         j = nextSym - 1; 
    632         for (; j > 3; j -= 4) { 
    633           yy[j]   = yy[j - 1]; 
    634           yy[j - 1] = yy[j - 2]; 
    635           yy[j - 2] = yy[j - 3]; 
    636           yy[j - 3] = yy[j - 4]; 
    637         } 
    638         for (; j > 0; j--) { 
    639           yy[j] = yy[j - 1]; 
    640         } 
    641  
    642         yy[0] = tmp; 
    643  
    644         //int zt, zn, zvec, zj; 
    645         if (groupPos == 0) { 
    646           groupNo++; 
    647           groupPos = G_SIZE; 
    648         } 
    649         groupPos--; 
    650         zt = selector[groupNo]; 
    651         zn = minLens[zt]; 
    652         zvec = bsR(zn); 
    653         while (zvec > limit[zt][zn]) { 
    654           zn++; 
    655           while (bsLive < 1) { 
    656             int zzi; 
    657             char thech = 0; 
    658             try { 
    659               thech = (char) bsStream.read(); 
    660             } 
    661             catch (IOException e) { 
    662               compressedStreamEOF(); 
    663             } 
    664             zzi = thech; 
    665             bsBuff = (bsBuff << 8) | (zzi & 0xff); 
    666             bsLive += 8; 
    667           } 
    668           zj = (bsBuff >> (bsLive - 1)) & 1; 
    669           bsLive--; 
    670           zvec = (zvec << 1) | zj; 
    671         } 
    672         nextSym = perm[zt][zvec - base[zt][zn]]; 
    673  
    674         continue; 
    675       } 
    676     } 
    677   } 
    678  
    679   private void setupBlock() { 
    680     int[] cftab = new int[257]; 
    681     char ch; 
    682  
    683     cftab[0] = 0; 
    684     for (i = 1; i <= 256; i++) { 
    685       cftab[i] = unzftab[i - 1]; 
    686     } 
    687     for (i = 1; i <= 256; i++) { 
    688       cftab[i] += cftab[i - 1]; 
    689     } 
    690  
    691     for (i = 0; i <= last; i++) { 
    692       ch = (char) ll8[i]; 
    693       tt[cftab[ch]] = i; 
    694       cftab[ch]++; 
    695     } 
    696     cftab = null; 
    697  
    698     tPos = tt[origPtr]; 
    699  
    700     count = 0; 
    701     i2 = 0; 
    702     ch2 = 256;   /* not a char and not EOF */ 
    703  
    704     if (blockRandomised) { 
    705       rNToGo = 0; 
    706       rTPos = 0; 
    707       setupRandPartA(); 
    708     } 
    709     else { 
    710       setupNoRandPartA(); 
    711     } 
    712   } 
    713  
    714   private void setupRandPartA() { 
    715     if (i2 <= last) { 
    716       chPrev = ch2; 
    717       ch2 = ll8[tPos]; 
    718       tPos = tt[tPos]; 
    719       if (rNToGo == 0) { 
    720         rNToGo = R_NUMS[rTPos]; 
    721         rTPos++; 
    722         if (rTPos == 512) { 
    723           rTPos = 0; 
    724         } 
    725       } 
    726       rNToGo--; 
    727       ch2 ^= (int) ((rNToGo == 1) ? 1 : 0); 
    728       i2++; 
    729  
    730       currentChar = ch2; 
    731       currentState = RAND_PART_B_STATE; 
    732       mCrc.updateCRC(ch2); 
    733     } 
    734     else { 
    735       endBlock(); 
    736       initBlock(); 
    737       setupBlock(); 
    738     } 
    739   } 
    740  
    741   private void setupNoRandPartA() { 
    742     if (i2 <= last) { 
    743       chPrev = ch2; 
    744       ch2 = ll8[tPos]; 
    745       tPos = tt[tPos]; 
    746       i2++; 
    747  
    748       currentChar = ch2; 
    749       currentState = NO_RAND_PART_B_STATE; 
    750       mCrc.updateCRC(ch2); 
    751     } 
    752     else { 
    753       endBlock(); 
    754       initBlock(); 
    755       setupBlock(); 
    756     } 
    757   } 
    758  
    759   private void setupRandPartB() { 
    760     if (ch2 != chPrev) { 
    761       currentState = RAND_PART_A_STATE; 
    762       count = 1; 
    763       setupRandPartA(); 
    764     } 
    765     else { 
    766       count++; 
    767       if (count >= 4) { 
    768         z = ll8[tPos]; 
    769         tPos = tt[tPos]; 
    770         if (rNToGo == 0) { 
    771           rNToGo = R_NUMS[rTPos]; 
    772           rTPos++; 
    773           if (rTPos == 512) { 
    774             rTPos = 0; 
    775           } 
    776         } 
    777         rNToGo--; 
    778         z ^= ((rNToGo == 1) ? 1 : 0); 
    779         j2 = 0; 
    780         currentState = RAND_PART_C_STATE; 
    781         setupRandPartC(); 
    782       } 
    783       else { 
    784         currentState = RAND_PART_A_STATE; 
    785         setupRandPartA(); 
    786       } 
    787     } 
    788   } 
    789  
    790   private void setupRandPartC() { 
    791     if (j2 < (int) z) { 
    792       currentChar = ch2; 
    793       mCrc.updateCRC(ch2); 
    794       j2++; 
    795     } 
    796     else { 
    797       currentState = RAND_PART_A_STATE; 
    798       i2++; 
    799       count = 0; 
    800       setupRandPartA(); 
    801     } 
    802   } 
    803  
    804   private void setupNoRandPartB() { 
    805     if (ch2 != chPrev) { 
    806       currentState = NO_RAND_PART_A_STATE; 
    807       count = 1; 
    808       setupNoRandPartA(); 
    809     } 
    810     else { 
    811       count++; 
    812       if (count >= 4) { 
    813         z = ll8[tPos]; 
    814         tPos = tt[tPos]; 
    815         currentState = NO_RAND_PART_C_STATE; 
    816         j2 = 0; 
    817         setupNoRandPartC(); 
    818       } 
    819       else { 
    820         currentState = NO_RAND_PART_A_STATE; 
    821         setupNoRandPartA(); 
    822       } 
    823     } 
    824   } 
    825  
    826   private void setupNoRandPartC() { 
    827     if (j2 < (int) z) { 
    828       currentChar = ch2; 
    829       mCrc.updateCRC(ch2); 
    830       j2++; 
    831     } 
    832     else { 
    833       currentState = NO_RAND_PART_A_STATE; 
    834       i2++; 
    835       count = 0; 
    836       setupNoRandPartA(); 
    837     } 
    838   } 
    839  
    840   private void setDecompressStructureSizes(int newSize100k) { 
    841     if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && 
    842       blockSize100k <= 9)) 
    843     { 
    844       // throw new IOException("Invalid block size"); 
    845     } 
    846  
    847     blockSize100k = newSize100k; 
    848  
    849     if (newSize100k == 0) { 
    850       return; 
    851     } 
    852  
    853     int n = BASE_BLOCK_SIZE * newSize100k; 
    854     ll8 = new char[n]; 
    855     tt = new int[n]; 
    856   } 
     742            while (bsLiveShadow < 1) { 
     743                final int thech = inShadow.read(); 
     744 
     745                if (thech >= 0) { 
     746                    bsBuffShadow = (bsBuffShadow << 8) | thech; 
     747                    bsLiveShadow += 8; 
     748                    continue; 
     749                } else { 
     750                    throw new IOException("unexpected end of stream"); 
     751                } 
     752            } 
     753            bsLiveShadow--; 
     754            zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); 
     755        } 
     756 
     757        this.bsLive = bsLiveShadow; 
     758        this.bsBuff = bsBuffShadow; 
     759 
     760        return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]]; 
     761    } 
     762 
     763    private void setupBlock() throws IOException { 
     764        if (this.data == null) { 
     765            return; 
     766        } 
     767 
     768        final int[] cftab = this.data.cftab; 
     769        final int[] tt    = this.data.initTT(this.last + 1); 
     770        final byte[] ll8  = this.data.ll8; 
     771        cftab[0] = 0; 
     772        System.arraycopy(this.data.unzftab, 0, cftab, 1, 256); 
     773 
     774        for (int i = 1, c = cftab[0]; i <= 256; i++) { 
     775            c += cftab[i]; 
     776            cftab[i] = c; 
     777        } 
     778 
     779        for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) { 
     780            tt[cftab[ll8[i] & 0xff]++] = i; 
     781        } 
     782 
     783        if ((this.origPtr < 0) || (this.origPtr >= tt.length)) { 
     784            throw new IOException("stream corrupted"); 
     785        } 
     786 
     787        this.su_tPos = tt[this.origPtr]; 
     788        this.su_count = 0; 
     789        this.su_i2 = 0; 
     790        this.su_ch2 = 256;   /* not a char and not EOF */ 
     791 
     792        if (this.blockRandomised) { 
     793            this.su_rNToGo = 0; 
     794            this.su_rTPos = 0; 
     795            setupRandPartA(); 
     796        } else { 
     797            setupNoRandPartA(); 
     798        } 
     799    } 
     800 
     801    private void setupRandPartA() throws IOException { 
     802        if (this.su_i2 <= this.last) { 
     803            this.su_chPrev = this.su_ch2; 
     804            int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; 
     805            this.su_tPos = this.data.tt[this.su_tPos]; 
     806            if (this.su_rNToGo == 0) { 
     807                this.su_rNToGo = BZip2Constants.R_NUMS[this.su_rTPos] - 1; 
     808                if (++this.su_rTPos == 512) { 
     809                    this.su_rTPos = 0; 
     810                } 
     811            } else { 
     812                this.su_rNToGo--; 
     813            } 
     814            this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0; 
     815            this.su_i2++; 
     816            this.currentChar = su_ch2Shadow; 
     817            this.currentState = RAND_PART_B_STATE; 
     818            this.crc.updateCRC(su_ch2Shadow); 
     819        } else { 
     820            endBlock(); 
     821            initBlock(); 
     822            setupBlock(); 
     823        } 
     824    } 
     825 
     826    private void setupNoRandPartA() throws IOException { 
     827        if (this.su_i2 <= this.last) { 
     828            this.su_chPrev = this.su_ch2; 
     829            int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; 
     830            this.su_ch2 = su_ch2Shadow; 
     831            this.su_tPos = this.data.tt[this.su_tPos]; 
     832            this.su_i2++; 
     833            this.currentChar = su_ch2Shadow; 
     834            this.currentState = NO_RAND_PART_B_STATE; 
     835            this.crc.updateCRC(su_ch2Shadow); 
     836        } else { 
     837            this.currentState = NO_RAND_PART_A_STATE; 
     838            endBlock(); 
     839            initBlock(); 
     840            setupBlock(); 
     841        } 
     842    } 
     843 
     844    private void setupRandPartB() throws IOException { 
     845        if (this.su_ch2 != this.su_chPrev) { 
     846            this.currentState = RAND_PART_A_STATE; 
     847            this.su_count = 1; 
     848            setupRandPartA(); 
     849        } else if (++this.su_count >= 4) { 
     850            this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); 
     851            this.su_tPos = this.data.tt[this.su_tPos]; 
     852            if (this.su_rNToGo == 0) { 
     853                this.su_rNToGo = BZip2Constants.R_NUMS[this.su_rTPos] - 1; 
     854                if (++this.su_rTPos == 512) { 
     855                    this.su_rTPos = 0; 
     856                } 
     857            } else { 
     858                this.su_rNToGo--; 
     859            } 
     860            this.su_j2 = 0; 
     861            this.currentState = RAND_PART_C_STATE; 
     862            if (this.su_rNToGo == 1) { 
     863                this.su_z ^= 1; 
     864            } 
     865            setupRandPartC(); 
     866        } else { 
     867            this.currentState = RAND_PART_A_STATE; 
     868            setupRandPartA(); 
     869        } 
     870    } 
     871 
     872    private void setupRandPartC() throws IOException { 
     873        if (this.su_j2 < this.su_z) { 
     874            this.currentChar = this.su_ch2; 
     875            this.crc.updateCRC(this.su_ch2); 
     876            this.su_j2++; 
     877        } else { 
     878            this.currentState = RAND_PART_A_STATE; 
     879            this.su_i2++; 
     880            this.su_count = 0; 
     881            setupRandPartA(); 
     882        } 
     883    } 
     884 
     885    private void setupNoRandPartB() throws IOException { 
     886        if (this.su_ch2 != this.su_chPrev) { 
     887            this.su_count = 1; 
     888            setupNoRandPartA(); 
     889        } else if (++this.su_count >= 4) { 
     890            this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); 
     891            this.su_tPos = this.data.tt[this.su_tPos]; 
     892            this.su_j2 = 0; 
     893            setupNoRandPartC(); 
     894        } else { 
     895            setupNoRandPartA(); 
     896        } 
     897    } 
     898 
     899    private void setupNoRandPartC() throws IOException { 
     900        if (this.su_j2 < this.su_z) { 
     901            int su_ch2Shadow = this.su_ch2; 
     902            this.currentChar = su_ch2Shadow; 
     903            this.crc.updateCRC(su_ch2Shadow); 
     904            this.su_j2++; 
     905            this.currentState = NO_RAND_PART_C_STATE; 
     906        } else { 
     907            this.su_i2++; 
     908            this.su_count = 0; 
     909            setupNoRandPartA(); 
     910        } 
     911    } 
     912 
     913    private static final class Data extends Object { 
     914 
     915        // (with blockSize 900k) 
     916        final boolean[] inUse   = new boolean[256];                                   //      256 byte 
     917 
     918        final byte[] seqToUnseq   = new byte[256];                                    //      256 byte 
     919        final byte[] selector     = new byte[MAX_SELECTORS];                          //    18002 byte 
     920        final byte[] selectorMtf  = new byte[MAX_SELECTORS];                          //    18002 byte 
     921 
     922        /** 
     923         * Freq table collected to save a pass over the data during 
     924         * decompression. 
     925         */ 
     926        final int[] unzftab = new int[256];                                           //     1024 byte 
     927 
     928        final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte 
     929        final int[][] base  = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte 
     930        final int[][] perm  = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte 
     931        final int[] minLens = new int[N_GROUPS];                                      //       24 byte 
     932 
     933        final int[]     cftab     = new int[257];                                     //     1028 byte 
     934        final char[]    getAndMoveToFrontDecode_yy = new char[256];                   //      512 byte 
     935        final char[][]  temp_charArray2d  = new char[N_GROUPS][MAX_ALPHA_SIZE];       //     3096 byte 
     936        final byte[] recvDecodingTables_pos = new byte[N_GROUPS];                     //        6 byte 
     937        //--------------- 
     938        //    60798 byte 
     939 
     940        int[] tt;                                                                     //  3600000 byte 
     941        byte[] ll8;                                                                   //   900000 byte 
     942        //--------------- 
     943        //  4560782 byte 
     944        //=============== 
     945 
     946        Data(int blockSize100k) { 
     947            super(); 
     948 
     949            this.ll8 = new byte[blockSize100k * BZip2Constants.BASE_BLOCK_SIZE]; 
     950        } 
     951 
     952        /** 
     953         * Initializes the {@link #tt} array. 
     954         * 
     955         * This method is called when the required length of the array 
     956         * is known.  I don't initialize it at construction time to 
     957         * avoid unneccessary memory allocation when compressing small 
     958         * files. 
     959         */ 
     960        final int[] initTT(int length) { 
     961            int[] ttShadow = this.tt; 
     962 
     963            // tt.length should always be >= length, but theoretically 
     964            // it can happen, if the compressor mixed small and large 
     965            // blocks.  Normally only the last block will be smaller 
     966            // than others. 
     967            if ((ttShadow == null) || (ttShadow.length < length)) { 
     968                this.tt = ttShadow = new int[length]; 
     969            } 
     970 
     971            return ttShadow; 
     972        } 
     973 
     974    } 
    857975} 
    858976 
Note: See TracChangeset for help on using the changeset viewer.