CBZip2InputStream.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:26k
源码类别:

网格计算

开发平台:

Java

  1. /*
  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
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  *
  17.  */
  18. /*
  19.  * This package is based on the work done by Keiron Liddle, Aftex Software
  20.  * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
  21.  * great code.
  22.  */
  23. package org.apache.hadoop.io.compress.bzip2;
  24. import java.io.InputStream;
  25. import java.io.IOException;
  26. /**
  27.  * An input stream that decompresses from the BZip2 format (without the file
  28.  * header chars) to be read as any other stream.
  29.  *
  30.  * <p>
  31.  * The decompression requires large amounts of memory. Thus you should call the
  32.  * {@link #close() close()} method as soon as possible, to force
  33.  * <tt>CBZip2InputStream</tt> to release the allocated memory. See
  34.  * {@link CBZip2OutputStream CBZip2OutputStream} for information about memory
  35.  * usage.
  36.  * </p>
  37.  *
  38.  * <p>
  39.  * <tt>CBZip2InputStream</tt> reads bytes from the compressed source stream via
  40.  * the single byte {@link java.io.InputStream#read() read()} method exclusively.
  41.  * Thus you should consider to use a buffered source stream.
  42.  * </p>
  43.  *
  44.  * <p>
  45.  * Instances of this class are not threadsafe.
  46.  * </p>
  47.  */
  48. public class CBZip2InputStream extends InputStream implements BZip2Constants {
  49.   private static void reportCRCError() throws IOException {
  50.    throw new IOException("BZip2 CRC error");
  51.   }
  52.   private void makeMaps() {
  53.     final boolean[] inUse = this.data.inUse;
  54.     final byte[] seqToUnseq = this.data.seqToUnseq;
  55.     int nInUseShadow = 0;
  56.     for (int i = 0; i < 256; i++) {
  57.       if (inUse[i])
  58.         seqToUnseq[nInUseShadow++] = (byte) i;
  59.     }
  60.     this.nInUse = nInUseShadow;
  61.   }
  62.   /**
  63.   * Index of the last char in the block, so the block size == last + 1.
  64.   */
  65.   private int last;
  66.   /**
  67.   * Index in zptr[] of original string after sorting.
  68.   */
  69.   private int origPtr;
  70.   /**
  71.   * always: in the range 0 .. 9. The current block size is 100000 * this
  72.   * number.
  73.   */
  74.   private int blockSize100k;
  75.   private boolean blockRandomised;
  76.   private int bsBuff;
  77.   private int bsLive;
  78.   private final CRC crc = new CRC();
  79.   private int nInUse;
  80.   private InputStream in;
  81.   private int currentChar = -1;
  82.   private static final int EOF = 0;
  83.   private static final int START_BLOCK_STATE = 1;
  84.   private static final int RAND_PART_A_STATE = 2;
  85.   private static final int RAND_PART_B_STATE = 3;
  86.   private static final int RAND_PART_C_STATE = 4;
  87.   private static final int NO_RAND_PART_A_STATE = 5;
  88.   private static final int NO_RAND_PART_B_STATE = 6;
  89.   private static final int NO_RAND_PART_C_STATE = 7;
  90.   private int currentState = START_BLOCK_STATE;
  91.   private int storedBlockCRC, storedCombinedCRC;
  92.   private int computedBlockCRC, computedCombinedCRC;
  93.   // Variables used by setup* methods exclusively
  94.   private int su_count;
  95.   private int su_ch2;
  96.   private int su_chPrev;
  97.   private int su_i2;
  98.   private int su_j2;
  99.   private int su_rNToGo;
  100.   private int su_rTPos;
  101.   private int su_tPos;
  102.   private char su_z;
  103.   /**
  104.   * All memory intensive stuff. This field is initialized by initBlock().
  105.   */
  106.   private CBZip2InputStream.Data data;
  107.   /**
  108.   * Constructs a new CBZip2InputStream which decompresses bytes read from the
  109.   * specified stream.
  110.   *
  111.   * <p>
  112.   * Although BZip2 headers are marked with the magic <tt>"Bz"</tt> this
  113.   * constructor expects the next byte in the stream to be the first one after
  114.   * the magic. Thus callers have to skip the first two bytes. Otherwise this
  115.   * constructor will throw an exception.
  116.   * </p>
  117.   *
  118.   * @throws IOException
  119.   *             if the stream content is malformed or an I/O error occurs.
  120.   * @throws NullPointerException
  121.   *             if <tt>in == null</tt>
  122.   */
  123.   public CBZip2InputStream(final InputStream in) throws IOException {
  124.     super();
  125.     this.in = in;
  126.     init();
  127.   }
  128.   public int read() throws IOException {
  129.     if (this.in != null) {
  130.       return read0();
  131.     } else {
  132.       throw new IOException("stream closed");
  133.     }
  134.   }
  135.   public int read(final byte[] dest, final int offs, final int len)
  136.       throws IOException {
  137.     if (offs < 0) {
  138.       throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
  139.     }
  140.     if (len < 0) {
  141.       throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
  142.     }
  143.     if (offs + len > dest.length) {
  144.       throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
  145.           + len + ") > dest.length(" + dest.length + ").");
  146.     }
  147.     if (this.in == null) {
  148.       throw new IOException("stream closed");
  149.     }
  150.     final int hi = offs + len;
  151.     int destOffs = offs;
  152.     for (int b; (destOffs < hi) && ((b = read0()) >= 0);) {
  153.       dest[destOffs++] = (byte) b;
  154.     }
  155.     return (destOffs == offs) ? -1 : (destOffs - offs);
  156.   }
  157.   private int read0() throws IOException {
  158.     final int retChar = this.currentChar;
  159.     switch (this.currentState) {
  160.     case EOF:
  161.       return -1;
  162.     case START_BLOCK_STATE:
  163.       throw new IllegalStateException();
  164.     case RAND_PART_A_STATE:
  165.       throw new IllegalStateException();
  166.     case RAND_PART_B_STATE:
  167.       setupRandPartB();
  168.       break;
  169.     case RAND_PART_C_STATE:
  170.       setupRandPartC();
  171.       break;
  172.     case NO_RAND_PART_A_STATE:
  173.       throw new IllegalStateException();
  174.     case NO_RAND_PART_B_STATE:
  175.       setupNoRandPartB();
  176.       break;
  177.     case NO_RAND_PART_C_STATE:
  178.       setupNoRandPartC();
  179.       break;
  180.     default:
  181.       throw new IllegalStateException();
  182.     }
  183.     return retChar;
  184.   }
  185.   private void init() throws IOException {
  186.     int magic2 = this.in.read();
  187.     if (magic2 != 'h') {
  188.       throw new IOException("Stream is not BZip2 formatted: expected 'h'"
  189.           + " as first byte but got '" + (char) magic2 + "'");
  190.     }
  191.     int blockSize = this.in.read();
  192.     if ((blockSize < '1') || (blockSize > '9')) {
  193.       throw new IOException("Stream is not BZip2 formatted: illegal "
  194.           + "blocksize " + (char) blockSize);
  195.     }
  196.     this.blockSize100k = blockSize - '0';
  197.     initBlock();
  198.     setupBlock();
  199.   }
  200.   private void initBlock() throws IOException {
  201.     char magic0 = bsGetUByte();
  202.     char magic1 = bsGetUByte();
  203.     char magic2 = bsGetUByte();
  204.     char magic3 = bsGetUByte();
  205.     char magic4 = bsGetUByte();
  206.     char magic5 = bsGetUByte();
  207.     if (magic0 == 0x17 && magic1 == 0x72 && magic2 == 0x45
  208.         && magic3 == 0x38 && magic4 == 0x50 && magic5 == 0x90) {
  209.       complete(); // end of file
  210.     } else if (magic0 != 0x31 || // '1'
  211.         magic1 != 0x41 || // ')'
  212.         magic2 != 0x59 || // 'Y'
  213.         magic3 != 0x26 || // '&'
  214.         magic4 != 0x53 || // 'S'
  215.         magic5 != 0x59 // 'Y'
  216.     ) {
  217.       this.currentState = EOF;
  218.       throw new IOException("bad block header");
  219.     } else {
  220.       this.storedBlockCRC = bsGetInt();
  221.       this.blockRandomised = bsR(1) == 1;
  222.       /**
  223.       * Allocate data here instead in constructor, so we do not allocate
  224.       * it if the input file is empty.
  225.       */
  226.       if (this.data == null) {
  227.         this.data = new Data(this.blockSize100k);
  228.       }
  229.       // currBlockNo++;
  230.       getAndMoveToFrontDecode();
  231.       this.crc.initialiseCRC();
  232.       this.currentState = START_BLOCK_STATE;
  233.     }
  234.   }
  235.   private void endBlock() throws IOException {
  236.     this.computedBlockCRC = this.crc.getFinalCRC();
  237.     // A bad CRC is considered a fatal error.
  238.     if (this.storedBlockCRC != this.computedBlockCRC) {
  239.       // make next blocks readable without error
  240.       // (repair feature, not yet documented, not tested)
  241.       this.computedCombinedCRC = (this.storedCombinedCRC << 1)
  242.           | (this.storedCombinedCRC >>> 31);
  243.       this.computedCombinedCRC ^= this.storedBlockCRC;
  244.       reportCRCError();
  245.     }
  246.     this.computedCombinedCRC = (this.computedCombinedCRC << 1)
  247.         | (this.computedCombinedCRC >>> 31);
  248.     this.computedCombinedCRC ^= this.computedBlockCRC;
  249.   }
  250.   private void complete() throws IOException {
  251.     this.storedCombinedCRC = bsGetInt();
  252.     this.currentState = EOF;
  253.     this.data = null;
  254.     if (this.storedCombinedCRC != this.computedCombinedCRC) {
  255.       reportCRCError();
  256.     }
  257.   }
  258.   public void close() throws IOException {
  259.     InputStream inShadow = this.in;
  260.     if (inShadow != null) {
  261.       try {
  262.         if (inShadow != System.in) {
  263.           inShadow.close();
  264.         }
  265.       } finally {
  266.         this.data = null;
  267.         this.in = null;
  268.       }
  269.     }
  270.   }
  271.   private int bsR(final int n) throws IOException {
  272.     int bsLiveShadow = this.bsLive;
  273.     int bsBuffShadow = this.bsBuff;
  274.     if (bsLiveShadow < n) {
  275.       final InputStream inShadow = this.in;
  276.       do {
  277.         int thech = inShadow.read();
  278.         if (thech < 0) {
  279.           throw new IOException("unexpected end of stream");
  280.         }
  281.         bsBuffShadow = (bsBuffShadow << 8) | thech;
  282.         bsLiveShadow += 8;
  283.       } while (bsLiveShadow < n);
  284.       this.bsBuff = bsBuffShadow;
  285.     }
  286.     this.bsLive = bsLiveShadow - n;
  287.     return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
  288.   }
  289.   private boolean bsGetBit() throws IOException {
  290.     int bsLiveShadow = this.bsLive;
  291.     int bsBuffShadow = this.bsBuff;
  292.     if (bsLiveShadow < 1) {
  293.       int thech = this.in.read();
  294.       if (thech < 0) {
  295.         throw new IOException("unexpected end of stream");
  296.       }
  297.       bsBuffShadow = (bsBuffShadow << 8) | thech;
  298.       bsLiveShadow += 8;
  299.       this.bsBuff = bsBuffShadow;
  300.     }
  301.     this.bsLive = bsLiveShadow - 1;
  302.     return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0;
  303.   }
  304.   private char bsGetUByte() throws IOException {
  305.     return (char) bsR(8);
  306.   }
  307.   private int bsGetInt() throws IOException {
  308.     return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
  309.   }
  310.   /**
  311.   * Called by createHuffmanDecodingTables() exclusively.
  312.   */
  313.   private static void hbCreateDecodeTables(final int[] limit,
  314.       final int[] base, final int[] perm, final char[] length,
  315.       final int minLen, final int maxLen, final int alphaSize) {
  316.     for (int i = minLen, pp = 0; i <= maxLen; i++) {
  317.       for (int j = 0; j < alphaSize; j++) {
  318.         if (length[j] == i) {
  319.           perm[pp++] = j;
  320.         }
  321.       }
  322.     }
  323.     for (int i = MAX_CODE_LEN; --i > 0;) {
  324.       base[i] = 0;
  325.       limit[i] = 0;
  326.     }
  327.     for (int i = 0; i < alphaSize; i++) {
  328.       base[length[i] + 1]++;
  329.     }
  330.     for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
  331.       b += base[i];
  332.       base[i] = b;
  333.     }
  334.     for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {
  335.       final int nb = base[i + 1];
  336.       vec += nb - b;
  337.       b = nb;
  338.       limit[i] = vec - 1;
  339.       vec <<= 1;
  340.     }
  341.     for (int i = minLen + 1; i <= maxLen; i++) {
  342.       base[i] = ((limit[i - 1] + 1) << 1) - base[i];
  343.     }
  344.   }
  345.   private void recvDecodingTables() throws IOException {
  346.     final Data dataShadow = this.data;
  347.     final boolean[] inUse = dataShadow.inUse;
  348.     final byte[] pos = dataShadow.recvDecodingTables_pos;
  349.     final byte[] selector = dataShadow.selector;
  350.     final byte[] selectorMtf = dataShadow.selectorMtf;
  351.     int inUse16 = 0;
  352.     /* Receive the mapping table */
  353.     for (int i = 0; i < 16; i++) {
  354.       if (bsGetBit()) {
  355.         inUse16 |= 1 << i;
  356.       }
  357.     }
  358.     for (int i = 256; --i >= 0;) {
  359.       inUse[i] = false;
  360.     }
  361.     for (int i = 0; i < 16; i++) {
  362.       if ((inUse16 & (1 << i)) != 0) {
  363.         final int i16 = i << 4;
  364.         for (int j = 0; j < 16; j++) {
  365.           if (bsGetBit()) {
  366.             inUse[i16 + j] = true;
  367.           }
  368.         }
  369.       }
  370.     }
  371.     makeMaps();
  372.     final int alphaSize = this.nInUse + 2;
  373.     /* Now the selectors */
  374.     final int nGroups = bsR(3);
  375.     final int nSelectors = bsR(15);
  376.     for (int i = 0; i < nSelectors; i++) {
  377.       int j = 0;
  378.       while (bsGetBit()) {
  379.         j++;
  380.       }
  381.       selectorMtf[i] = (byte) j;
  382.     }
  383.     /* Undo the MTF values for the selectors. */
  384.     for (int v = nGroups; --v >= 0;) {
  385.       pos[v] = (byte) v;
  386.     }
  387.     for (int i = 0; i < nSelectors; i++) {
  388.       int v = selectorMtf[i] & 0xff;
  389.       final byte tmp = pos[v];
  390.       while (v > 0) {
  391.         // nearly all times v is zero, 4 in most other cases
  392.         pos[v] = pos[v - 1];
  393.         v--;
  394.       }
  395.       pos[0] = tmp;
  396.       selector[i] = tmp;
  397.     }
  398.     final char[][] len = dataShadow.temp_charArray2d;
  399.     /* Now the coding tables */
  400.     for (int t = 0; t < nGroups; t++) {
  401.       int curr = bsR(5);
  402.       final char[] len_t = len[t];
  403.       for (int i = 0; i < alphaSize; i++) {
  404.         while (bsGetBit()) {
  405.           curr += bsGetBit() ? -1 : 1;
  406.         }
  407.         len_t[i] = (char) curr;
  408.       }
  409.     }
  410.     // finally create the Huffman tables
  411.     createHuffmanDecodingTables(alphaSize, nGroups);
  412.   }
  413.   /**
  414.   * Called by recvDecodingTables() exclusively.
  415.   */
  416.   private void createHuffmanDecodingTables(final int alphaSize,
  417.       final int nGroups) {
  418.     final Data dataShadow = this.data;
  419.     final char[][] len = dataShadow.temp_charArray2d;
  420.     final int[] minLens = dataShadow.minLens;
  421.     final int[][] limit = dataShadow.limit;
  422.     final int[][] base = dataShadow.base;
  423.     final int[][] perm = dataShadow.perm;
  424.     for (int t = 0; t < nGroups; t++) {
  425.       int minLen = 32;
  426.       int maxLen = 0;
  427.       final char[] len_t = len[t];
  428.       for (int i = alphaSize; --i >= 0;) {
  429.         final char lent = len_t[i];
  430.         if (lent > maxLen) {
  431.           maxLen = lent;
  432.         }
  433.         if (lent < minLen) {
  434.           minLen = lent;
  435.         }
  436.       }
  437.       hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
  438.           maxLen, alphaSize);
  439.       minLens[t] = minLen;
  440.     }
  441.   }
  442.   private void getAndMoveToFrontDecode() throws IOException {
  443.     this.origPtr = bsR(24);
  444.     recvDecodingTables();
  445.     final InputStream inShadow = this.in;
  446.     final Data dataShadow = this.data;
  447.     final byte[] ll8 = dataShadow.ll8;
  448.     final int[] unzftab = dataShadow.unzftab;
  449.     final byte[] selector = dataShadow.selector;
  450.     final byte[] seqToUnseq = dataShadow.seqToUnseq;
  451.     final char[] yy = dataShadow.getAndMoveToFrontDecode_yy;
  452.     final int[] minLens = dataShadow.minLens;
  453.     final int[][] limit = dataShadow.limit;
  454.     final int[][] base = dataShadow.base;
  455.     final int[][] perm = dataShadow.perm;
  456.     final int limitLast = this.blockSize100k * 100000;
  457.     /*
  458.     * Setting up the unzftab entries here is not strictly necessary, but it
  459.     * does save having to do it later in a separate pass, and so saves a
  460.     * block's worth of cache misses.
  461.     */
  462.     for (int i = 256; --i >= 0;) {
  463.       yy[i] = (char) i;
  464.       unzftab[i] = 0;
  465.     }
  466.     int groupNo = 0;
  467.     int groupPos = G_SIZE - 1;
  468.     final int eob = this.nInUse + 1;
  469.     int nextSym = getAndMoveToFrontDecode0(0);
  470.     int bsBuffShadow = this.bsBuff;
  471.     int bsLiveShadow = this.bsLive;
  472.     int lastShadow = -1;
  473.     int zt = selector[groupNo] & 0xff;
  474.     int[] base_zt = base[zt];
  475.     int[] limit_zt = limit[zt];
  476.     int[] perm_zt = perm[zt];
  477.     int minLens_zt = minLens[zt];
  478.     while (nextSym != eob) {
  479.       if ((nextSym == RUNA) || (nextSym == RUNB)) {
  480.         int s = -1;
  481.         for (int n = 1; true; n <<= 1) {
  482.           if (nextSym == RUNA) {
  483.             s += n;
  484.           } else if (nextSym == RUNB) {
  485.             s += n << 1;
  486.           } else {
  487.             break;
  488.           }
  489.           if (groupPos == 0) {
  490.             groupPos = G_SIZE - 1;
  491.             zt = selector[++groupNo] & 0xff;
  492.             base_zt = base[zt];
  493.             limit_zt = limit[zt];
  494.             perm_zt = perm[zt];
  495.             minLens_zt = minLens[zt];
  496.           } else {
  497.             groupPos--;
  498.           }
  499.           int zn = minLens_zt;
  500.           // Inlined:
  501.           // int zvec = bsR(zn);
  502.           while (bsLiveShadow < zn) {
  503.             final int thech = inShadow.read();
  504.             if (thech >= 0) {
  505.               bsBuffShadow = (bsBuffShadow << 8) | thech;
  506.               bsLiveShadow += 8;
  507.               continue;
  508.             } else {
  509.               throw new IOException("unexpected end of stream");
  510.             }
  511.           }
  512.           int zvec = (bsBuffShadow >> (bsLiveShadow - zn))
  513.               & ((1 << zn) - 1);
  514.           bsLiveShadow -= zn;
  515.           while (zvec > limit_zt[zn]) {
  516.             zn++;
  517.             while (bsLiveShadow < 1) {
  518.               final int thech = inShadow.read();
  519.               if (thech >= 0) {
  520.                 bsBuffShadow = (bsBuffShadow << 8) | thech;
  521.                 bsLiveShadow += 8;
  522.                 continue;
  523.               } else {
  524.                 throw new IOException(
  525.                     "unexpected end of stream");
  526.               }
  527.             }
  528.             bsLiveShadow--;
  529.             zvec = (zvec << 1)
  530.                 | ((bsBuffShadow >> bsLiveShadow) & 1);
  531.           }
  532.           nextSym = perm_zt[zvec - base_zt[zn]];
  533.         }
  534.         final byte ch = seqToUnseq[yy[0]];
  535.         unzftab[ch & 0xff] += s + 1;
  536.         while (s-- >= 0) {
  537.           ll8[++lastShadow] = ch;
  538.         }
  539.         if (lastShadow >= limitLast) {
  540.           throw new IOException("block overrun");
  541.         }
  542.       } else {
  543.         if (++lastShadow >= limitLast) {
  544.           throw new IOException("block overrun");
  545.         }
  546.         final char tmp = yy[nextSym - 1];
  547.         unzftab[seqToUnseq[tmp] & 0xff]++;
  548.         ll8[lastShadow] = seqToUnseq[tmp];
  549.         /*
  550.         * This loop is hammered during decompression, hence avoid
  551.         * native method call overhead of System.arraycopy for very
  552.         * small ranges to copy.
  553.         */
  554.         if (nextSym <= 16) {
  555.           for (int j = nextSym - 1; j > 0;) {
  556.             yy[j] = yy[--j];
  557.           }
  558.         } else {
  559.           System.arraycopy(yy, 0, yy, 1, nextSym - 1);
  560.         }
  561.         yy[0] = tmp;
  562.         if (groupPos == 0) {
  563.           groupPos = G_SIZE - 1;
  564.           zt = selector[++groupNo] & 0xff;
  565.           base_zt = base[zt];
  566.           limit_zt = limit[zt];
  567.           perm_zt = perm[zt];
  568.           minLens_zt = minLens[zt];
  569.         } else {
  570.           groupPos--;
  571.         }
  572.         int zn = minLens_zt;
  573.         // Inlined:
  574.         // int zvec = bsR(zn);
  575.         while (bsLiveShadow < zn) {
  576.           final int thech = inShadow.read();
  577.           if (thech >= 0) {
  578.             bsBuffShadow = (bsBuffShadow << 8) | thech;
  579.             bsLiveShadow += 8;
  580.             continue;
  581.           } else {
  582.             throw new IOException("unexpected end of stream");
  583.           }
  584.         }
  585.         int zvec = (bsBuffShadow >> (bsLiveShadow - zn))
  586.             & ((1 << zn) - 1);
  587.         bsLiveShadow -= zn;
  588.         while (zvec > limit_zt[zn]) {
  589.           zn++;
  590.           while (bsLiveShadow < 1) {
  591.             final int thech = inShadow.read();
  592.             if (thech >= 0) {
  593.               bsBuffShadow = (bsBuffShadow << 8) | thech;
  594.               bsLiveShadow += 8;
  595.               continue;
  596.             } else {
  597.               throw new IOException("unexpected end of stream");
  598.             }
  599.           }
  600.           bsLiveShadow--;
  601.           zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
  602.         }
  603.         nextSym = perm_zt[zvec - base_zt[zn]];
  604.       }
  605.     }
  606.     this.last = lastShadow;
  607.     this.bsLive = bsLiveShadow;
  608.     this.bsBuff = bsBuffShadow;
  609.   }
  610.   private int getAndMoveToFrontDecode0(final int groupNo) throws IOException {
  611.     final InputStream inShadow = this.in;
  612.     final Data dataShadow = this.data;
  613.     final int zt = dataShadow.selector[groupNo] & 0xff;
  614.     final int[] limit_zt = dataShadow.limit[zt];
  615.     int zn = dataShadow.minLens[zt];
  616.     int zvec = bsR(zn);
  617.     int bsLiveShadow = this.bsLive;
  618.     int bsBuffShadow = this.bsBuff;
  619.     while (zvec > limit_zt[zn]) {
  620.       zn++;
  621.       while (bsLiveShadow < 1) {
  622.         final int thech = inShadow.read();
  623.         if (thech >= 0) {
  624.           bsBuffShadow = (bsBuffShadow << 8) | thech;
  625.           bsLiveShadow += 8;
  626.           continue;
  627.         } else {
  628.           throw new IOException("unexpected end of stream");
  629.         }
  630.       }
  631.       bsLiveShadow--;
  632.       zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
  633.     }
  634.     this.bsLive = bsLiveShadow;
  635.     this.bsBuff = bsBuffShadow;
  636.     return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]];
  637.   }
  638.   private void setupBlock() throws IOException {
  639.     if (this.data == null) {
  640.       return;
  641.     }
  642.     final int[] cftab = this.data.cftab;
  643.     final int[] tt = this.data.initTT(this.last + 1);
  644.     final byte[] ll8 = this.data.ll8;
  645.     cftab[0] = 0;
  646.     System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);
  647.     for (int i = 1, c = cftab[0]; i <= 256; i++) {
  648.       c += cftab[i];
  649.       cftab[i] = c;
  650.     }
  651.     for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
  652.       tt[cftab[ll8[i] & 0xff]++] = i;
  653.     }
  654.     if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
  655.       throw new IOException("stream corrupted");
  656.     }
  657.     this.su_tPos = tt[this.origPtr];
  658.     this.su_count = 0;
  659.     this.su_i2 = 0;
  660.     this.su_ch2 = 256; /* not a char and not EOF */
  661.     if (this.blockRandomised) {
  662.       this.su_rNToGo = 0;
  663.       this.su_rTPos = 0;
  664.       setupRandPartA();
  665.     } else {
  666.       setupNoRandPartA();
  667.     }
  668.   }
  669.   private void setupRandPartA() throws IOException {
  670.     if (this.su_i2 <= this.last) {
  671.       this.su_chPrev = this.su_ch2;
  672.       int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
  673.       this.su_tPos = this.data.tt[this.su_tPos];
  674.       if (this.su_rNToGo == 0) {
  675.         this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
  676.         if (++this.su_rTPos == 512) {
  677.           this.su_rTPos = 0;
  678.         }
  679.       } else {
  680.         this.su_rNToGo--;
  681.       }
  682.       this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;
  683.       this.su_i2++;
  684.       this.currentChar = su_ch2Shadow;
  685.       this.currentState = RAND_PART_B_STATE;
  686.       this.crc.updateCRC(su_ch2Shadow);
  687.     } else {
  688.       endBlock();
  689.       initBlock();
  690.       setupBlock();
  691.     }
  692.   }
  693.   private void setupNoRandPartA() throws IOException {
  694.     if (this.su_i2 <= this.last) {
  695.       this.su_chPrev = this.su_ch2;
  696.       int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
  697.       this.su_ch2 = su_ch2Shadow;
  698.       this.su_tPos = this.data.tt[this.su_tPos];
  699.       this.su_i2++;
  700.       this.currentChar = su_ch2Shadow;
  701.       this.currentState = NO_RAND_PART_B_STATE;
  702.       this.crc.updateCRC(su_ch2Shadow);
  703.     } else {
  704.       this.currentState = NO_RAND_PART_A_STATE;
  705.       endBlock();
  706.       initBlock();
  707.       setupBlock();
  708.     }
  709.   }
  710.   private void setupRandPartB() throws IOException {
  711.     if (this.su_ch2 != this.su_chPrev) {
  712.       this.currentState = RAND_PART_A_STATE;
  713.       this.su_count = 1;
  714.       setupRandPartA();
  715.     } else if (++this.su_count >= 4) {
  716.       this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
  717.       this.su_tPos = this.data.tt[this.su_tPos];
  718.       if (this.su_rNToGo == 0) {
  719.         this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
  720.         if (++this.su_rTPos == 512) {
  721.           this.su_rTPos = 0;
  722.         }
  723.       } else {
  724.         this.su_rNToGo--;
  725.       }
  726.       this.su_j2 = 0;
  727.       this.currentState = RAND_PART_C_STATE;
  728.       if (this.su_rNToGo == 1) {
  729.         this.su_z ^= 1;
  730.       }
  731.       setupRandPartC();
  732.     } else {
  733.       this.currentState = RAND_PART_A_STATE;
  734.       setupRandPartA();
  735.     }
  736.   }
  737.   private void setupRandPartC() throws IOException {
  738.     if (this.su_j2 < this.su_z) {
  739.       this.currentChar = this.su_ch2;
  740.       this.crc.updateCRC(this.su_ch2);
  741.       this.su_j2++;
  742.     } else {
  743.       this.currentState = RAND_PART_A_STATE;
  744.       this.su_i2++;
  745.       this.su_count = 0;
  746.       setupRandPartA();
  747.     }
  748.   }
  749.   private void setupNoRandPartB() throws IOException {
  750.     if (this.su_ch2 != this.su_chPrev) {
  751.       this.su_count = 1;
  752.       setupNoRandPartA();
  753.     } else if (++this.su_count >= 4) {
  754.       this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
  755.       this.su_tPos = this.data.tt[this.su_tPos];
  756.       this.su_j2 = 0;
  757.       setupNoRandPartC();
  758.     } else {
  759.       setupNoRandPartA();
  760.     }
  761.   }
  762.   private void setupNoRandPartC() throws IOException {
  763.     if (this.su_j2 < this.su_z) {
  764.       int su_ch2Shadow = this.su_ch2;
  765.       this.currentChar = su_ch2Shadow;
  766.       this.crc.updateCRC(su_ch2Shadow);
  767.       this.su_j2++;
  768.       this.currentState = NO_RAND_PART_C_STATE;
  769.     } else {
  770.       this.su_i2++;
  771.       this.su_count = 0;
  772.       setupNoRandPartA();
  773.     }
  774.   }
  775.   private static final class Data extends Object {
  776.     // (with blockSize 900k)
  777.     final boolean[] inUse = new boolean[256]; // 256 byte
  778.     final byte[] seqToUnseq = new byte[256]; // 256 byte
  779.     final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte
  780.     final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte
  781.     /**
  782.     * Freq table collected to save a pass over the data during
  783.     * decompression.
  784.     */
  785.     final int[] unzftab = new int[256]; // 1024 byte
  786.     final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  787.     final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  788.     final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
  789.     final int[] minLens = new int[N_GROUPS]; // 24 byte
  790.     final int[] cftab = new int[257]; // 1028 byte
  791.     final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte
  792.     final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096
  793.                                         // byte
  794.     final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte
  795.     // ---------------
  796.     // 60798 byte
  797.     int[] tt; // 3600000 byte
  798.     byte[] ll8; // 900000 byte
  799.     // ---------------
  800.     // 4560782 byte
  801.     // ===============
  802.     Data(int blockSize100k) {
  803.       super();
  804.       this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize];
  805.     }
  806.     /**
  807.     * Initializes the {@link #tt} array.
  808.     *
  809.     * This method is called when the required length of the array is known.
  810.     * I don't initialize it at construction time to avoid unneccessary
  811.     * memory allocation when compressing small files.
  812.     */
  813.     final int[] initTT(int length) {
  814.       int[] ttShadow = this.tt;
  815.       // tt.length should always be >= length, but theoretically
  816.       // it can happen, if the compressor mixed small and large
  817.       // blocks. Normally only the last block will be smaller
  818.       // than others.
  819.       if ((ttShadow == null) || (ttShadow.length < length)) {
  820.         this.tt = ttShadow = new int[length];
  821.       }
  822.       return ttShadow;
  823.     }
  824.   }
  825. }