CBZip2InputStream.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:26k
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- /*
- * This package is based on the work done by Keiron Liddle, Aftex Software
- * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
- * great code.
- */
- package org.apache.hadoop.io.compress.bzip2;
- import java.io.InputStream;
- import java.io.IOException;
- /**
- * An input stream that decompresses from the BZip2 format (without the file
- * header chars) to be read as any other stream.
- *
- * <p>
- * The decompression requires large amounts of memory. Thus you should call the
- * {@link #close() close()} method as soon as possible, to force
- * <tt>CBZip2InputStream</tt> to release the allocated memory. See
- * {@link CBZip2OutputStream CBZip2OutputStream} for information about memory
- * usage.
- * </p>
- *
- * <p>
- * <tt>CBZip2InputStream</tt> reads bytes from the compressed source stream via
- * the single byte {@link java.io.InputStream#read() read()} method exclusively.
- * Thus you should consider to use a buffered source stream.
- * </p>
- *
- * <p>
- * Instances of this class are not threadsafe.
- * </p>
- */
- public class CBZip2InputStream extends InputStream implements BZip2Constants {
- private static void reportCRCError() throws IOException {
- throw new IOException("BZip2 CRC error");
- }
- private void makeMaps() {
- final boolean[] inUse = this.data.inUse;
- final byte[] seqToUnseq = this.data.seqToUnseq;
- int nInUseShadow = 0;
- for (int i = 0; i < 256; i++) {
- if (inUse[i])
- seqToUnseq[nInUseShadow++] = (byte) i;
- }
- this.nInUse = nInUseShadow;
- }
- /**
- * Index of the last char in the block, so the block size == last + 1.
- */
- private int last;
- /**
- * Index in zptr[] of original string after sorting.
- */
- private int origPtr;
- /**
- * always: in the range 0 .. 9. The current block size is 100000 * this
- * number.
- */
- private int blockSize100k;
- private boolean blockRandomised;
- private int bsBuff;
- private int bsLive;
- private final CRC crc = new CRC();
- private int nInUse;
- private InputStream in;
- private int currentChar = -1;
- private static final int EOF = 0;
- private static final int START_BLOCK_STATE = 1;
- private static final int RAND_PART_A_STATE = 2;
- private static final int RAND_PART_B_STATE = 3;
- private static final int RAND_PART_C_STATE = 4;
- private static final int NO_RAND_PART_A_STATE = 5;
- private static final int NO_RAND_PART_B_STATE = 6;
- private static final int NO_RAND_PART_C_STATE = 7;
- private int currentState = START_BLOCK_STATE;
- private int storedBlockCRC, storedCombinedCRC;
- private int computedBlockCRC, computedCombinedCRC;
- // Variables used by setup* methods exclusively
- private int su_count;
- private int su_ch2;
- private int su_chPrev;
- private int su_i2;
- private int su_j2;
- private int su_rNToGo;
- private int su_rTPos;
- private int su_tPos;
- private char su_z;
- /**
- * All memory intensive stuff. This field is initialized by initBlock().
- */
- private CBZip2InputStream.Data data;
- /**
- * Constructs a new CBZip2InputStream which decompresses bytes read from the
- * specified stream.
- *
- * <p>
- * Although BZip2 headers are marked with the magic <tt>"Bz"</tt> this
- * constructor expects the next byte in the stream to be the first one after
- * the magic. Thus callers have to skip the first two bytes. Otherwise this
- * constructor will throw an exception.
- * </p>
- *
- * @throws IOException
- * if the stream content is malformed or an I/O error occurs.
- * @throws NullPointerException
- * if <tt>in == null</tt>
- */
- public CBZip2InputStream(final InputStream in) throws IOException {
- super();
- this.in = in;
- init();
- }
- public int read() throws IOException {
- if (this.in != null) {
- return read0();
- } else {
- throw new IOException("stream closed");
- }
- }
- public int read(final byte[] dest, final int offs, final int len)
- throws IOException {
- if (offs < 0) {
- throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
- }
- if (len < 0) {
- throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
- }
- if (offs + len > dest.length) {
- throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
- + len + ") > dest.length(" + dest.length + ").");
- }
- if (this.in == null) {
- throw new IOException("stream closed");
- }
- final int hi = offs + len;
- int destOffs = offs;
- for (int b; (destOffs < hi) && ((b = read0()) >= 0);) {
- dest[destOffs++] = (byte) b;
- }
- return (destOffs == offs) ? -1 : (destOffs - offs);
- }
- private int read0() throws IOException {
- final int retChar = this.currentChar;
- switch (this.currentState) {
- case EOF:
- return -1;
- case START_BLOCK_STATE:
- throw new IllegalStateException();
- case RAND_PART_A_STATE:
- throw new IllegalStateException();
- case RAND_PART_B_STATE:
- setupRandPartB();
- break;
- case RAND_PART_C_STATE:
- setupRandPartC();
- break;
- case NO_RAND_PART_A_STATE:
- throw new IllegalStateException();
- case NO_RAND_PART_B_STATE:
- setupNoRandPartB();
- break;
- case NO_RAND_PART_C_STATE:
- setupNoRandPartC();
- break;
- default:
- throw new IllegalStateException();
- }
- return retChar;
- }
- private void init() throws IOException {
- int magic2 = this.in.read();
- if (magic2 != 'h') {
- throw new IOException("Stream is not BZip2 formatted: expected 'h'"
- + " as first byte but got '" + (char) magic2 + "'");
- }
- int blockSize = this.in.read();
- if ((blockSize < '1') || (blockSize > '9')) {
- throw new IOException("Stream is not BZip2 formatted: illegal "
- + "blocksize " + (char) blockSize);
- }
- this.blockSize100k = blockSize - '0';
- initBlock();
- setupBlock();
- }
- private void initBlock() throws IOException {
- char magic0 = bsGetUByte();
- char magic1 = bsGetUByte();
- char magic2 = bsGetUByte();
- char magic3 = bsGetUByte();
- char magic4 = bsGetUByte();
- char magic5 = bsGetUByte();
- if (magic0 == 0x17 && magic1 == 0x72 && magic2 == 0x45
- && magic3 == 0x38 && magic4 == 0x50 && magic5 == 0x90) {
- complete(); // end of file
- } else if (magic0 != 0x31 || // '1'
- magic1 != 0x41 || // ')'
- magic2 != 0x59 || // 'Y'
- magic3 != 0x26 || // '&'
- magic4 != 0x53 || // 'S'
- magic5 != 0x59 // 'Y'
- ) {
- this.currentState = EOF;
- throw new IOException("bad block header");
- } else {
- this.storedBlockCRC = bsGetInt();
- this.blockRandomised = bsR(1) == 1;
- /**
- * Allocate data here instead in constructor, so we do not allocate
- * it if the input file is empty.
- */
- if (this.data == null) {
- this.data = new Data(this.blockSize100k);
- }
- // currBlockNo++;
- getAndMoveToFrontDecode();
- this.crc.initialiseCRC();
- this.currentState = START_BLOCK_STATE;
- }
- }
- private void endBlock() throws IOException {
- this.computedBlockCRC = this.crc.getFinalCRC();
- // A bad CRC is considered a fatal error.
- if (this.storedBlockCRC != this.computedBlockCRC) {
- // make next blocks readable without error
- // (repair feature, not yet documented, not tested)
- this.computedCombinedCRC = (this.storedCombinedCRC << 1)
- | (this.storedCombinedCRC >>> 31);
- this.computedCombinedCRC ^= this.storedBlockCRC;
- reportCRCError();
- }
- this.computedCombinedCRC = (this.computedCombinedCRC << 1)
- | (this.computedCombinedCRC >>> 31);
- this.computedCombinedCRC ^= this.computedBlockCRC;
- }
- private void complete() throws IOException {
- this.storedCombinedCRC = bsGetInt();
- this.currentState = EOF;
- this.data = null;
- if (this.storedCombinedCRC != this.computedCombinedCRC) {
- reportCRCError();
- }
- }
- public void close() throws IOException {
- InputStream inShadow = this.in;
- if (inShadow != null) {
- try {
- if (inShadow != System.in) {
- inShadow.close();
- }
- } finally {
- this.data = null;
- this.in = null;
- }
- }
- }
- private int bsR(final int n) throws IOException {
- int bsLiveShadow = this.bsLive;
- int bsBuffShadow = this.bsBuff;
- if (bsLiveShadow < n) {
- final InputStream inShadow = this.in;
- do {
- int thech = inShadow.read();
- if (thech < 0) {
- throw new IOException("unexpected end of stream");
- }
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- } while (bsLiveShadow < n);
- this.bsBuff = bsBuffShadow;
- }
- this.bsLive = bsLiveShadow - n;
- return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
- }
- private boolean bsGetBit() throws IOException {
- int bsLiveShadow = this.bsLive;
- int bsBuffShadow = this.bsBuff;
- if (bsLiveShadow < 1) {
- int thech = this.in.read();
- if (thech < 0) {
- throw new IOException("unexpected end of stream");
- }
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- this.bsBuff = bsBuffShadow;
- }
- this.bsLive = bsLiveShadow - 1;
- return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0;
- }
- private char bsGetUByte() throws IOException {
- return (char) bsR(8);
- }
- private int bsGetInt() throws IOException {
- return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
- }
- /**
- * Called by createHuffmanDecodingTables() exclusively.
- */
- private static void hbCreateDecodeTables(final int[] limit,
- final int[] base, final int[] perm, final char[] length,
- final int minLen, final int maxLen, final int alphaSize) {
- for (int i = minLen, pp = 0; i <= maxLen; i++) {
- for (int j = 0; j < alphaSize; j++) {
- if (length[j] == i) {
- perm[pp++] = j;
- }
- }
- }
- for (int i = MAX_CODE_LEN; --i > 0;) {
- base[i] = 0;
- limit[i] = 0;
- }
- for (int i = 0; i < alphaSize; i++) {
- base[length[i] + 1]++;
- }
- for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
- b += base[i];
- base[i] = b;
- }
- for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {
- final int nb = base[i + 1];
- vec += nb - b;
- b = nb;
- limit[i] = vec - 1;
- vec <<= 1;
- }
- for (int i = minLen + 1; i <= maxLen; i++) {
- base[i] = ((limit[i - 1] + 1) << 1) - base[i];
- }
- }
- private void recvDecodingTables() throws IOException {
- final Data dataShadow = this.data;
- final boolean[] inUse = dataShadow.inUse;
- final byte[] pos = dataShadow.recvDecodingTables_pos;
- final byte[] selector = dataShadow.selector;
- final byte[] selectorMtf = dataShadow.selectorMtf;
- int inUse16 = 0;
- /* Receive the mapping table */
- for (int i = 0; i < 16; i++) {
- if (bsGetBit()) {
- inUse16 |= 1 << i;
- }
- }
- for (int i = 256; --i >= 0;) {
- inUse[i] = false;
- }
- for (int i = 0; i < 16; i++) {
- if ((inUse16 & (1 << i)) != 0) {
- final int i16 = i << 4;
- for (int j = 0; j < 16; j++) {
- if (bsGetBit()) {
- inUse[i16 + j] = true;
- }
- }
- }
- }
- makeMaps();
- final int alphaSize = this.nInUse + 2;
- /* Now the selectors */
- final int nGroups = bsR(3);
- final int nSelectors = bsR(15);
- for (int i = 0; i < nSelectors; i++) {
- int j = 0;
- while (bsGetBit()) {
- j++;
- }
- selectorMtf[i] = (byte) j;
- }
- /* Undo the MTF values for the selectors. */
- for (int v = nGroups; --v >= 0;) {
- pos[v] = (byte) v;
- }
- for (int i = 0; i < nSelectors; i++) {
- int v = selectorMtf[i] & 0xff;
- final byte tmp = pos[v];
- while (v > 0) {
- // nearly all times v is zero, 4 in most other cases
- pos[v] = pos[v - 1];
- v--;
- }
- pos[0] = tmp;
- selector[i] = tmp;
- }
- final char[][] len = dataShadow.temp_charArray2d;
- /* Now the coding tables */
- for (int t = 0; t < nGroups; t++) {
- int curr = bsR(5);
- final char[] len_t = len[t];
- for (int i = 0; i < alphaSize; i++) {
- while (bsGetBit()) {
- curr += bsGetBit() ? -1 : 1;
- }
- len_t[i] = (char) curr;
- }
- }
- // finally create the Huffman tables
- createHuffmanDecodingTables(alphaSize, nGroups);
- }
- /**
- * Called by recvDecodingTables() exclusively.
- */
- private void createHuffmanDecodingTables(final int alphaSize,
- final int nGroups) {
- final Data dataShadow = this.data;
- final char[][] len = dataShadow.temp_charArray2d;
- final int[] minLens = dataShadow.minLens;
- final int[][] limit = dataShadow.limit;
- final int[][] base = dataShadow.base;
- final int[][] perm = dataShadow.perm;
- for (int t = 0; t < nGroups; t++) {
- int minLen = 32;
- int maxLen = 0;
- final char[] len_t = len[t];
- for (int i = alphaSize; --i >= 0;) {
- final char lent = len_t[i];
- if (lent > maxLen) {
- maxLen = lent;
- }
- if (lent < minLen) {
- minLen = lent;
- }
- }
- hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
- maxLen, alphaSize);
- minLens[t] = minLen;
- }
- }
- private void getAndMoveToFrontDecode() throws IOException {
- this.origPtr = bsR(24);
- recvDecodingTables();
- final InputStream inShadow = this.in;
- final Data dataShadow = this.data;
- final byte[] ll8 = dataShadow.ll8;
- final int[] unzftab = dataShadow.unzftab;
- final byte[] selector = dataShadow.selector;
- final byte[] seqToUnseq = dataShadow.seqToUnseq;
- final char[] yy = dataShadow.getAndMoveToFrontDecode_yy;
- final int[] minLens = dataShadow.minLens;
- final int[][] limit = dataShadow.limit;
- final int[][] base = dataShadow.base;
- final int[][] perm = dataShadow.perm;
- final int limitLast = this.blockSize100k * 100000;
- /*
- * Setting up the unzftab entries here is not strictly necessary, but it
- * does save having to do it later in a separate pass, and so saves a
- * block's worth of cache misses.
- */
- for (int i = 256; --i >= 0;) {
- yy[i] = (char) i;
- unzftab[i] = 0;
- }
- int groupNo = 0;
- int groupPos = G_SIZE - 1;
- final int eob = this.nInUse + 1;
- int nextSym = getAndMoveToFrontDecode0(0);
- int bsBuffShadow = this.bsBuff;
- int bsLiveShadow = this.bsLive;
- int lastShadow = -1;
- int zt = selector[groupNo] & 0xff;
- int[] base_zt = base[zt];
- int[] limit_zt = limit[zt];
- int[] perm_zt = perm[zt];
- int minLens_zt = minLens[zt];
- while (nextSym != eob) {
- if ((nextSym == RUNA) || (nextSym == RUNB)) {
- int s = -1;
- for (int n = 1; true; n <<= 1) {
- if (nextSym == RUNA) {
- s += n;
- } else if (nextSym == RUNB) {
- s += n << 1;
- } else {
- break;
- }
- if (groupPos == 0) {
- groupPos = G_SIZE - 1;
- zt = selector[++groupNo] & 0xff;
- base_zt = base[zt];
- limit_zt = limit[zt];
- perm_zt = perm[zt];
- minLens_zt = minLens[zt];
- } else {
- groupPos--;
- }
- int zn = minLens_zt;
- // Inlined:
- // int zvec = bsR(zn);
- while (bsLiveShadow < zn) {
- final int thech = inShadow.read();
- if (thech >= 0) {
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- continue;
- } else {
- throw new IOException("unexpected end of stream");
- }
- }
- int zvec = (bsBuffShadow >> (bsLiveShadow - zn))
- & ((1 << zn) - 1);
- bsLiveShadow -= zn;
- while (zvec > limit_zt[zn]) {
- zn++;
- while (bsLiveShadow < 1) {
- final int thech = inShadow.read();
- if (thech >= 0) {
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- continue;
- } else {
- throw new IOException(
- "unexpected end of stream");
- }
- }
- bsLiveShadow--;
- zvec = (zvec << 1)
- | ((bsBuffShadow >> bsLiveShadow) & 1);
- }
- nextSym = perm_zt[zvec - base_zt[zn]];
- }
- final byte ch = seqToUnseq[yy[0]];
- unzftab[ch & 0xff] += s + 1;
- while (s-- >= 0) {
- ll8[++lastShadow] = ch;
- }
- if (lastShadow >= limitLast) {
- throw new IOException("block overrun");
- }
- } else {
- if (++lastShadow >= limitLast) {
- throw new IOException("block overrun");
- }
- final char tmp = yy[nextSym - 1];
- unzftab[seqToUnseq[tmp] & 0xff]++;
- ll8[lastShadow] = seqToUnseq[tmp];
- /*
- * This loop is hammered during decompression, hence avoid
- * native method call overhead of System.arraycopy for very
- * small ranges to copy.
- */
- if (nextSym <= 16) {
- for (int j = nextSym - 1; j > 0;) {
- yy[j] = yy[--j];
- }
- } else {
- System.arraycopy(yy, 0, yy, 1, nextSym - 1);
- }
- yy[0] = tmp;
- if (groupPos == 0) {
- groupPos = G_SIZE - 1;
- zt = selector[++groupNo] & 0xff;
- base_zt = base[zt];
- limit_zt = limit[zt];
- perm_zt = perm[zt];
- minLens_zt = minLens[zt];
- } else {
- groupPos--;
- }
- int zn = minLens_zt;
- // Inlined:
- // int zvec = bsR(zn);
- while (bsLiveShadow < zn) {
- final int thech = inShadow.read();
- if (thech >= 0) {
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- continue;
- } else {
- throw new IOException("unexpected end of stream");
- }
- }
- int zvec = (bsBuffShadow >> (bsLiveShadow - zn))
- & ((1 << zn) - 1);
- bsLiveShadow -= zn;
- while (zvec > limit_zt[zn]) {
- zn++;
- while (bsLiveShadow < 1) {
- final int thech = inShadow.read();
- if (thech >= 0) {
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- continue;
- } else {
- throw new IOException("unexpected end of stream");
- }
- }
- bsLiveShadow--;
- zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
- }
- nextSym = perm_zt[zvec - base_zt[zn]];
- }
- }
- this.last = lastShadow;
- this.bsLive = bsLiveShadow;
- this.bsBuff = bsBuffShadow;
- }
- private int getAndMoveToFrontDecode0(final int groupNo) throws IOException {
- final InputStream inShadow = this.in;
- final Data dataShadow = this.data;
- final int zt = dataShadow.selector[groupNo] & 0xff;
- final int[] limit_zt = dataShadow.limit[zt];
- int zn = dataShadow.minLens[zt];
- int zvec = bsR(zn);
- int bsLiveShadow = this.bsLive;
- int bsBuffShadow = this.bsBuff;
- while (zvec > limit_zt[zn]) {
- zn++;
- while (bsLiveShadow < 1) {
- final int thech = inShadow.read();
- if (thech >= 0) {
- bsBuffShadow = (bsBuffShadow << 8) | thech;
- bsLiveShadow += 8;
- continue;
- } else {
- throw new IOException("unexpected end of stream");
- }
- }
- bsLiveShadow--;
- zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
- }
- this.bsLive = bsLiveShadow;
- this.bsBuff = bsBuffShadow;
- return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]];
- }
- private void setupBlock() throws IOException {
- if (this.data == null) {
- return;
- }
- final int[] cftab = this.data.cftab;
- final int[] tt = this.data.initTT(this.last + 1);
- final byte[] ll8 = this.data.ll8;
- cftab[0] = 0;
- System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);
- for (int i = 1, c = cftab[0]; i <= 256; i++) {
- c += cftab[i];
- cftab[i] = c;
- }
- for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
- tt[cftab[ll8[i] & 0xff]++] = i;
- }
- if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
- throw new IOException("stream corrupted");
- }
- this.su_tPos = tt[this.origPtr];
- this.su_count = 0;
- this.su_i2 = 0;
- this.su_ch2 = 256; /* not a char and not EOF */
- if (this.blockRandomised) {
- this.su_rNToGo = 0;
- this.su_rTPos = 0;
- setupRandPartA();
- } else {
- setupNoRandPartA();
- }
- }
- private void setupRandPartA() throws IOException {
- if (this.su_i2 <= this.last) {
- this.su_chPrev = this.su_ch2;
- int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
- this.su_tPos = this.data.tt[this.su_tPos];
- if (this.su_rNToGo == 0) {
- this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
- if (++this.su_rTPos == 512) {
- this.su_rTPos = 0;
- }
- } else {
- this.su_rNToGo--;
- }
- this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;
- this.su_i2++;
- this.currentChar = su_ch2Shadow;
- this.currentState = RAND_PART_B_STATE;
- this.crc.updateCRC(su_ch2Shadow);
- } else {
- endBlock();
- initBlock();
- setupBlock();
- }
- }
- private void setupNoRandPartA() throws IOException {
- if (this.su_i2 <= this.last) {
- this.su_chPrev = this.su_ch2;
- int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
- this.su_ch2 = su_ch2Shadow;
- this.su_tPos = this.data.tt[this.su_tPos];
- this.su_i2++;
- this.currentChar = su_ch2Shadow;
- this.currentState = NO_RAND_PART_B_STATE;
- this.crc.updateCRC(su_ch2Shadow);
- } else {
- this.currentState = NO_RAND_PART_A_STATE;
- endBlock();
- initBlock();
- setupBlock();
- }
- }
- private void setupRandPartB() throws IOException {
- if (this.su_ch2 != this.su_chPrev) {
- this.currentState = RAND_PART_A_STATE;
- this.su_count = 1;
- setupRandPartA();
- } else if (++this.su_count >= 4) {
- this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
- this.su_tPos = this.data.tt[this.su_tPos];
- if (this.su_rNToGo == 0) {
- this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
- if (++this.su_rTPos == 512) {
- this.su_rTPos = 0;
- }
- } else {
- this.su_rNToGo--;
- }
- this.su_j2 = 0;
- this.currentState = RAND_PART_C_STATE;
- if (this.su_rNToGo == 1) {
- this.su_z ^= 1;
- }
- setupRandPartC();
- } else {
- this.currentState = RAND_PART_A_STATE;
- setupRandPartA();
- }
- }
- private void setupRandPartC() throws IOException {
- if (this.su_j2 < this.su_z) {
- this.currentChar = this.su_ch2;
- this.crc.updateCRC(this.su_ch2);
- this.su_j2++;
- } else {
- this.currentState = RAND_PART_A_STATE;
- this.su_i2++;
- this.su_count = 0;
- setupRandPartA();
- }
- }
- private void setupNoRandPartB() throws IOException {
- if (this.su_ch2 != this.su_chPrev) {
- this.su_count = 1;
- setupNoRandPartA();
- } else if (++this.su_count >= 4) {
- this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
- this.su_tPos = this.data.tt[this.su_tPos];
- this.su_j2 = 0;
- setupNoRandPartC();
- } else {
- setupNoRandPartA();
- }
- }
- private void setupNoRandPartC() throws IOException {
- if (this.su_j2 < this.su_z) {
- int su_ch2Shadow = this.su_ch2;
- this.currentChar = su_ch2Shadow;
- this.crc.updateCRC(su_ch2Shadow);
- this.su_j2++;
- this.currentState = NO_RAND_PART_C_STATE;
- } else {
- this.su_i2++;
- this.su_count = 0;
- setupNoRandPartA();
- }
- }
- private static final class Data extends Object {
- // (with blockSize 900k)
- final boolean[] inUse = new boolean[256]; // 256 byte
- final byte[] seqToUnseq = new byte[256]; // 256 byte
- final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte
- final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte
- /**
- * Freq table collected to save a pass over the data during
- * decompression.
- */
- final int[] unzftab = new int[256]; // 1024 byte
- final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
- final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
- final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte
- final int[] minLens = new int[N_GROUPS]; // 24 byte
- final int[] cftab = new int[257]; // 1028 byte
- final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte
- final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096
- // byte
- final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte
- // ---------------
- // 60798 byte
- int[] tt; // 3600000 byte
- byte[] ll8; // 900000 byte
- // ---------------
- // 4560782 byte
- // ===============
- Data(int blockSize100k) {
- super();
- this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize];
- }
- /**
- * Initializes the {@link #tt} array.
- *
- * This method is called when the required length of the array is known.
- * I don't initialize it at construction time to avoid unneccessary
- * memory allocation when compressing small files.
- */
- final int[] initTT(int length) {
- int[] ttShadow = this.tt;
- // tt.length should always be >= length, but theoretically
- // it can happen, if the compressor mixed small and large
- // blocks. Normally only the last block will be smaller
- // than others.
- if ((ttShadow == null) || (ttShadow.length < length)) {
- this.tt = ttShadow = new int[length];
- }
- return ttShadow;
- }
- }
- }