commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tcu...@apache.org
Subject svn commit: r732685 - in /commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2: BZip2CompressorInputStream.java BZip2CompressorOutputStream.java BZip2Constants.java CRC.java
Date Thu, 08 Jan 2009 11:13:52 GMT
Author: tcurdt
Date: Thu Jan  8 03:13:50 2009
New Revision: 732685

URL: http://svn.apache.org/viewvc?rev=732685&view=rev
Log:
applied patch from Christian Grobmeier

updated bzip2 streams
https://issues.apache.org/jira/browse/SANDBOX-195


Modified:
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java?rev=732685&r1=732684&r2=732685&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java Thu Jan  8 03:13:50 2009
@@ -16,6 +16,12 @@
  * 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.commons.compress.compressors.bzip2;
 
 import java.io.IOException;
@@ -28,90 +34,57 @@
  * header chars) to be read as any other stream.
  */
 public class BZip2CompressorInputStream extends CompressorInputStream implements BZip2Constants {
+    private static void reportCRCError() throws IOException {
+        // The clean way would be to throw an exception.
+        //throw new IOException("crc error");
 
-    private static void cadvise() {
-        System.out.println("CRC Error");
-        //throw new CCoruptionError();
+        // Just print a message, like the previous versions of this class did
+        System.err.println("BZip2 CRC error");
     }
 
-    /*
-    private static void badBGLengths() {
-        cadvise();
-    }
+    private void makeMaps() {
+        final boolean[] inUse   = this.data.inUse;
+        final byte[] seqToUnseq = this.data.seqToUnseq;
 
-    private static void bitStreamEOF() {
-        cadvise();
-    }
-    */
+        int nInUseShadow = 0;
 
-    private static void compressedStreamEOF() {
-        cadvise();
-    }
-
-    private void makeMaps() {
-        int i;
-        nInUse = 0;
-        for (i = 0; i < 256; i++) {
-            if (inUse[i]) {
-                seqToUnseq[nInUse] = (char) i;
-                unseqToSeq[i] = (char) nInUse;
-                nInUse++;
-            }
+        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.
-    */
+    /**
+     * 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.
-    */
+    /**
+     * 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.
-    */
+    /**
+     * 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 CRC mCrc = new CRC();
+    private final CRC crc = new CRC();
 
-    private boolean[] inUse = new boolean[256];
     private int nInUse;
 
-    private char[] seqToUnseq = new char[256];
-    private char[] unseqToSeq = new char[256];
-
-    private char[] selector = new char[MAX_SELECTORS];
-    private char[] selectorMtf = new char[MAX_SELECTORS];
-
-    private int[] tt;
-    private char[] ll8;
-
-    /*
-      freq table collected to save a pass over the data
-      during decompression.
-    */
-    private int[] unzftab = new int[256];
-
-    private int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE];
-    private int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE];
-    private int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE];
-    private int[] minLens = new int[N_GROUPS];
-
-    private InputStream bsStream;
-
-    private boolean streamEnd = false;
+    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;
@@ -125,330 +98,435 @@
     private int storedBlockCRC, storedCombinedCRC;
     private int computedBlockCRC, computedCombinedCRC;
 
-    int i2, count, chPrev, ch2;
-    int i, tPos;
-    int rNToGo = 0;
-    int rTPos  = 0;
-    int j2;
-    char z;
-
-    public BZip2CompressorInputStream(InputStream zStream) {
-        ll8 = null;
-        tt = null;
-        bsSetStream(zStream);
-        initialize();
-        initBlock();
-        setupBlock();
-    }
+    // Variables used by setup* methods exclusively
 
-    public int read() {
-        if (streamEnd) {
-            return -1;
+    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 BZip2CompressorInputStream.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 BZip2CompressorInputStream(final InputStream in) throws IOException {
+        super();
+
+        this.in = in;
+        init();
+    }
+
+    public int read() throws IOException {
+        if (this.in != null) {
+            return read0();
         } else {
-            int retChar = currentChar;
-            switch(currentState) {
-            case START_BLOCK_STATE:
-                break;
-            case RAND_PART_A_STATE:
-                break;
-            case RAND_PART_B_STATE:
-                setupRandPartB();
-                break;
-            case RAND_PART_C_STATE:
-                setupRandPartC();
-                break;
-            case NO_RAND_PART_A_STATE:
-                break;
-            case NO_RAND_PART_B_STATE:
-                setupNoRandPartB();
-                break;
-            case NO_RAND_PART_C_STATE:
-                setupNoRandPartC();
-                break;
-            default:
-                break;
-            }
-            return retChar;
+            throw new IOException("stream closed");
         }
     }
 
-    private void initialize() {
-        char magic3, magic4;
-        magic3 = bsGetUChar();
-        magic4 = bsGetUChar();
-        if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {
-            bsFinishedWithStream();
-            streamEnd = true;
-            return;
+    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");
         }
 
-        setDecompressStructureSizes(magic4 - '0');
-        computedCombinedCRC = 0;
+        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 void initBlock() {
-        char magic1, magic2, magic3, magic4;
-        char magic5, magic6;
-        magic1 = bsGetUChar();
-        magic2 = bsGetUChar();
-        magic3 = bsGetUChar();
-        magic4 = bsGetUChar();
-        magic5 = bsGetUChar();
-        magic6 = bsGetUChar();
-        if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45
-            && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
-            complete();
-            return;
-        }
+    private int read0() throws IOException {
+        final int retChar = this.currentChar;
 
-        if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59
-            || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
-            badBlockHeader();
-            streamEnd = true;
-            return;
-        }
+        switch (this.currentState) {
+        case EOF:
+            return -1;
 
-        storedBlockCRC = bsGetInt32();
+        case START_BLOCK_STATE:
+            throw new IllegalStateException();
 
-        if (bsR(1) == 1) {
-            blockRandomised = true;
-        } else {
-            blockRandomised = false;
-        }
+        case RAND_PART_A_STATE:
+            throw new IllegalStateException();
 
-        //        currBlockNo++;
-        getAndMoveToFrontDecode();
+        case RAND_PART_B_STATE:
+            setupRandPartB();
+            break;
 
-        mCrc.initialiseCRC();
-        currentState = START_BLOCK_STATE;
-    }
+        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;
 
-    private void endBlock() {
-        computedBlockCRC = mCrc.getFinalCRC();
-        /* A bad CRC is considered a fatal error. */
-        if (storedBlockCRC != computedBlockCRC) {
-            crcError();
+        default:
+            throw new IllegalStateException();
         }
 
-        computedCombinedCRC = (computedCombinedCRC << 1)
-            | (computedCombinedCRC >>> 31);
-        computedCombinedCRC ^= computedBlockCRC;
+        return retChar;
     }
 
-    private void complete() {
-        storedCombinedCRC = bsGetInt32();
-        if (storedCombinedCRC != computedCombinedCRC) {
-            crcError();
+    private void init() throws IOException {
+        if (null == in) {
+            throw new IOException("No InputStream");
         }
+        if (in.available() == 0) {
+            throw new IOException("Empty InputStream");
+        }
+        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';
 
-        bsFinishedWithStream();
-        streamEnd = true;
+        initBlock();
+        setupBlock();
     }
 
-    private static void blockOverrun() {
-        cadvise();
+    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 static void badBlockHeader() {
-        cadvise();
+    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 static void crcError() {
-        cadvise();
+    private void complete() throws IOException {
+        this.storedCombinedCRC = bsGetInt();
+        this.currentState = EOF;
+        this.data = null;
+
+        if (this.storedCombinedCRC != this.computedCombinedCRC) {
+            reportCRCError();
+        }
     }
 
-    private void bsFinishedWithStream() {
-        try {
-            if (this.bsStream != null) {
-                if (this.bsStream != System.in) {
-                    this.bsStream.close();
-                    this.bsStream = null;
+    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;
             }
-        } catch (IOException ioe) {
-            //ignore
         }
     }
 
-    private void bsSetStream(InputStream f) {
-        bsStream = f;
-        bsLive = 0;
-        bsBuff = 0;
-    }
+    private int bsR(final int n) throws IOException {
+        int bsLiveShadow = this.bsLive;
+        int bsBuffShadow = this.bsBuff;
 
-    private int bsR(int n) {
-        int v;
-        while (bsLive < n) {
-            int zzi;
-            char thech = 0;
-            try {
-                thech = (char) bsStream.read();
-            } catch (IOException e) {
-                compressedStreamEOF();
-            }
-            if (thech == -1) {
-                compressedStreamEOF();
-            }
-            zzi = thech;
-            bsBuff = (bsBuff << 8) | (zzi & 0xff);
-            bsLive += 8;
+        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;
         }
 
-        v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
-        bsLive -= n;
-        return v;
+        this.bsLive = bsLiveShadow - n;
+        return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
     }
 
-    private char bsGetUChar() {
-        return (char) bsR(8);
-    }
+    private boolean bsGetBit() throws IOException {
+        int bsLiveShadow = this.bsLive;
+        int bsBuffShadow = this.bsBuff;
 
-    private int bsGetint() {
-        int u = 0;
-        u = (u << 8) | bsR(8);
-        u = (u << 8) | bsR(8);
-        u = (u << 8) | bsR(8);
-        u = (u << 8) | bsR(8);
-        return u;
-    }
+        if (bsLiveShadow < 1) {
+            int thech = this.in.read();
 
-    private int bsGetIntVS(int numBits) {
-        return (int) bsR(numBits);
+            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 int bsGetInt32() {
-        return (int) bsGetint();
+    private char bsGetUByte() throws IOException {
+        return (char) bsR(8);
     }
 
-    private void hbCreateDecodeTables(int[] limit, int[] base,
-                                      int[] perm, char[] length,
-                                      int minLen, int maxLen, int alphaSize) {
-        int pp, i, j, vec;
+    private int bsGetInt() throws IOException {
+        return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
+    }
 
-        pp = 0;
-        for (i = minLen; i <= maxLen; i++) {
-            for (j = 0; j < alphaSize; j++) {
+    /**
+     * 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;
-                    pp++;
+                    perm[pp++] = j;
                 }
             }
         }
 
-        for (i = 0; i < MAX_CODE_LEN; i++) {
+        for (int i = MAX_CODE_LEN; --i > 0;) {
             base[i] = 0;
-        }
-        for (i = 0; i < alphaSize; i++) {
-            base[length[i] + 1]++;
+            limit[i] = 0;
         }
 
-        for (i = 1; i < MAX_CODE_LEN; i++) {
-            base[i] += base[i - 1];
+        for (int i = 0; i < alphaSize; i++) {
+            base[length[i] + 1]++;
         }
 
-        for (i = 0; i < MAX_CODE_LEN; i++) {
-            limit[i] = 0;
+        for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
+            b += base[i];
+            base[i] = b;
         }
-        vec = 0;
 
-        for (i = minLen; i <= maxLen; i++) {
-            vec += (base[i + 1] - base[i]);
+        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 (i = minLen + 1; i <= maxLen; i++) {
+
+        for (int i = minLen + 1; i <= maxLen; i++) {
             base[i] = ((limit[i - 1] + 1) << 1) - base[i];
         }
     }
 
-    private void recvDecodingTables() {
-        char len[][] = new char[N_GROUPS][MAX_ALPHA_SIZE];
-        int i, j, t, nGroups, nSelectors, alphaSize;
-        int minLen, maxLen;
-        boolean[] inUse16 = new boolean[16];
+    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 (i = 0; i < 16; i++) {
-            if (bsR(1) == 1) {
-                inUse16[i] = true;
-            } else {
-                inUse16[i] = false;
+        for (int i = 0; i < 16; i++) {
+            if (bsGetBit()) {
+                inUse16 |= 1 << i;
             }
         }
 
-        for (i = 0; i < 256; i++) {
+        for (int i = 256; --i >= 0;) {
             inUse[i] = false;
         }
 
-        for (i = 0; i < 16; i++) {
-            if (inUse16[i]) {
-                for (j = 0; j < 16; j++) {
-                    if (bsR(1) == 1) {
-                        inUse[i * 16 + j] = true;
+        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();
-        alphaSize = nInUse + 2;
+        final int alphaSize = this.nInUse + 2;
 
         /* Now the selectors */
-        nGroups = bsR(3);
-        nSelectors = bsR(15);
-        for (i = 0; i < nSelectors; i++) {
-            j = 0;
-            while (bsR(1) == 1) {
+        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] = (char) j;
+            selectorMtf[i] = (byte) j;
         }
 
         /* Undo the MTF values for the selectors. */
-        {
-            char[] pos = new char[N_GROUPS];
-            char tmp, v;
-            for (v = 0; v < nGroups; v++) {
-                pos[v] = v;
-            }
-
-            for (i = 0; i < nSelectors; i++) {
-                v = selectorMtf[i];
-                tmp = pos[v];
-                while (v > 0) {
-                    pos[v] = pos[v - 1];
-                    v--;
-                }
-                pos[0] = tmp;
-                selector[i] = tmp;
+        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 (t = 0; t < nGroups; t++) {
+        for (int t = 0; t < nGroups; t++) {
             int curr = bsR(5);
-            for (i = 0; i < alphaSize; i++) {
-                while (bsR(1) == 1) {
-                    if (bsR(1) == 0) {
-                        curr++;
-                    } else {
-                        curr--;
-                    }
-                }
-                len[t][i] = (char) curr;
+            final char[] len_t = len[t];
+            for (int i = 0; i < alphaSize; i++) {
+                while (bsGetBit()) {
+                    curr += bsGetBit() ? -1 : 1;
+                }
+                len_t[i] = (char) curr;
             }
         }
 
-        /* Create the Huffman decoding tables */
-        for (t = 0; t < nGroups; t++) {
-            minLen = 32;
-            maxLen = 0;
-            for (i = 0; i < alphaSize; i++) {
-                if (len[t][i] > maxLen) {
-                    maxLen = len[t][i];
+        // 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 (len[t][i] < minLen) {
-                    minLen = len[t][i];
+                if (lent < minLen) {
+                    minLen = lent;
                 }
             }
             hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
@@ -457,18 +535,22 @@
         }
     }
 
-    private void getAndMoveToFrontDecode() {
-        char[] yy = new char[256];
-        int i, j, nextSym, limitLast;
-        int EOB, groupNo, groupPos;
-
-        limitLast = baseBlockSize * blockSize100k;
-        origPtr = bsGetIntVS(24);
-
+    private void getAndMoveToFrontDecode() throws IOException {
+        this.origPtr = bsR(24);
         recvDecodingTables();
-        EOB = nInUse + 1;
-        groupNo = -1;
-        groupPos = 0;
+
+        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
@@ -476,246 +558,259 @@
           in a separate pass, and so saves a block's worth of
           cache misses.
         */
-        for (i = 0; i <= 255; i++) {
+        for (int i = 256; --i >= 0;) {
+            yy[i] = (char) i;
             unzftab[i] = 0;
         }
 
-        for (i = 0; i <= 255; i++) {
-            yy[i] = (char) i;
-        }
+        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];
 
-        last = -1;
+        while (nextSym != eob) {
+            if ((nextSym == RUNA) || (nextSym == RUNB)) {
+                int s = -1;
 
-        {
-            int zt, zn, zvec, zj;
-            if (groupPos == 0) {
-                groupNo++;
-                groupPos = G_SIZE;
-            }
-            groupPos--;
-            zt = selector[groupNo];
-            zn = minLens[zt];
-            zvec = bsR(zn);
-            while (zvec > limit[zt][zn]) {
-                zn++;
-                {
-                    {
-                        while (bsLive < 1) {
-                            int zzi;
-                            char thech = 0;
-                            try {
-                                thech = (char) bsStream.read();
-                            } catch (IOException e) {
-                                compressedStreamEOF();
-                            }
-                            if (thech == -1) {
-                                compressedStreamEOF();
-                            }
-                            zzi = thech;
-                            bsBuff = (bsBuff << 8) | (zzi & 0xff);
-                            bsLive += 8;
-                        }
+                for (int n = 1; true; n <<= 1) {
+                    if (nextSym == RUNA) {
+                        s += n;
+                    } else if (nextSym == RUNB) {
+                        s += n << 1;
+                    } else {
+                        break;
                     }
-                    zj = (bsBuff >> (bsLive - 1)) & 1;
-                    bsLive--;
-                }
-                zvec = (zvec << 1) | zj;
-            }
-            nextSym = perm[zt][zvec - base[zt][zn]];
-        }
 
-        while (true) {
+                    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--;
+                    }
 
-            if (nextSym == EOB) {
-                break;
-            }
+                    int zn = minLens_zt;
 
-            if (nextSym == RUNA || nextSym == RUNB) {
-                char ch;
-                int s = -1;
-                int N = 1;
-                do {
-                    if (nextSym == RUNA) {
-                        s = s + (0 + 1) * N;
-                    } else if (nextSym == RUNB) {
-                        s = s + (1 + 1) * N;
-                           }
-                    N = N * 2;
-                    {
-                        int zt, zn, zvec, zj;
-                        if (groupPos == 0) {
-                            groupNo++;
-                            groupPos = G_SIZE;
+                    // 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");
                         }
-                        groupPos--;
-                        zt = selector[groupNo];
-                        zn = minLens[zt];
-                        zvec = bsR(zn);
-                        while (zvec > limit[zt][zn]) {
-                            zn++;
-                            {
-                                {
-                                    while (bsLive < 1) {
-                                        int zzi;
-                                        char thech = 0;
-                                        try {
-                                            thech = (char) bsStream.read();
-                                        } catch (IOException e) {
-                                            compressedStreamEOF();
-                                        }
-                                        if (thech == -1) {
-                                            compressedStreamEOF();
-                                        }
-                                        zzi = thech;
-                                        bsBuff = (bsBuff << 8) | (zzi & 0xff);
-                                        bsLive += 8;
-                                    }
-                                }
-                                zj = (bsBuff >> (bsLive - 1)) & 1;
-                                bsLive--;
+                    }
+                    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");
                             }
-                            zvec = (zvec << 1) | zj;
                         }
-                        nextSym = perm[zt][zvec - base[zt][zn]];
+                        bsLiveShadow--;
+                        zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
                     }
-                } while (nextSym == RUNA || nextSym == RUNB);
+                    nextSym = perm_zt[zvec - base_zt[zn]];
+                }
 
-                s++;
-                ch = seqToUnseq[yy[0]];
-                unzftab[ch] += s;
+                final byte ch = seqToUnseq[yy[0]];
+                unzftab[ch & 0xff] += s + 1;
 
-                while (s > 0) {
-                    last++;
-                    ll8[last] = ch;
-                    s--;
+                while (s-- >= 0) {
+                    ll8[++lastShadow] = ch;
                 }
 
-                if (last >= limitLast) {
-                    blockOverrun();
+                if (lastShadow >= limitLast) {
+                    throw new IOException("block overrun");
                 }
-                continue;
             } else {
-                char tmp;
-                last++;
-                if (last >= limitLast) {
-                    blockOverrun();
+                if (++lastShadow >= limitLast) {
+                    throw new IOException("block overrun");
                 }
 
-                tmp = yy[nextSym - 1];
-                unzftab[seqToUnseq[tmp]]++;
-                ll8[last] = seqToUnseq[tmp];
+                final char tmp = yy[nextSym - 1];
+                unzftab[seqToUnseq[tmp] & 0xff]++;
+                ll8[lastShadow] = seqToUnseq[tmp];
 
                 /*
                   This loop is hammered during decompression,
-                  hence the unrolling.
-
-                  for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+                  hence avoid native method call overhead of
+                  System.arraycopy for very small ranges to copy.
                 */
-
-                j = nextSym - 1;
-                for (; j > 3; j -= 4) {
-                    yy[j]     = yy[j - 1];
-                    yy[j - 1] = yy[j - 2];
-                    yy[j - 2] = yy[j - 3];
-                    yy[j - 3] = yy[j - 4];
-                }
-                for (; j > 0; j--) {
-                    yy[j] = yy[j - 1];
+                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;
-                {
-                    int zt, zn, zvec, zj;
-                    if (groupPos == 0) {
-                        groupNo++;
-                        groupPos = G_SIZE;
-                    }
+
+                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--;
-                    zt = selector[groupNo];
-                    zn = minLens[zt];
-                    zvec = bsR(zn);
-                    while (zvec > limit[zt][zn]) {
-                        zn++;
-                        {
-                            {
-                                while (bsLive < 1) {
-                                    int zzi;
-                                    char thech = 0;
-                                    try {
-                                        thech = (char) bsStream.read();
-                                    } catch (IOException e) {
-                                        compressedStreamEOF();
-                                    }
-                                    zzi = thech;
-                                    bsBuff = (bsBuff << 8) | (zzi & 0xff);
-                                    bsLive += 8;
-                                }
-                            }
-                            zj = (bsBuff >> (bsLive - 1)) & 1;
-                            bsLive--;
+                }
+
+                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");
                         }
-                        zvec = (zvec << 1) | zj;
                     }
-                    nextSym = perm[zt][zvec - base[zt][zn]];
+                    bsLiveShadow--;
+                    zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
                 }
-                continue;
+                nextSym = perm_zt[zvec - base_zt[zn]];
             }
         }
+
+        this.last = lastShadow;
+        this.bsLive = bsLiveShadow;
+        this.bsBuff = bsBuffShadow;
     }
 
-    private void setupBlock() {
-        int[] cftab = new int[257];
-        char ch;
+    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;
 
-        cftab[0] = 0;
-        for (i = 1; i <= 256; i++) {
-            cftab[i] = unzftab[i - 1];
+        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);
         }
-        for (i = 1; i <= 256; i++) {
-            cftab[i] += cftab[i - 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;
         }
 
-        for (i = 0; i <= last; i++) {
-            ch = (char) ll8[i];
-            tt[cftab[ch]] = i;
-            cftab[ch]++;
+        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;
         }
-        cftab = null;
 
-        tPos = tt[origPtr];
+        for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
+            tt[cftab[ll8[i] & 0xff]++] = i;
+        }
 
-        count = 0;
-        i2 = 0;
-        ch2 = 256;   /* not a char and not EOF */
+        if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
+            throw new IOException("stream corrupted");
+        }
 
-        if (blockRandomised) {
-            rNToGo = 0;
-            rTPos = 0;
+        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() {
-        if (i2 <= last) {
-            chPrev = ch2;
-            ch2 = ll8[tPos];
-            tPos = tt[tPos];
-            if (rNToGo == 0) {
-                rNToGo = rNums[rTPos];
-                rTPos++;
-                if (rTPos == 512) {
-                    rTPos = 0;
-                }
-            }
-            rNToGo--;
-            ch2 ^= (int) ((rNToGo == 1) ? 1 : 0);
-            i2++;
-
-            currentChar = ch2;
-            currentState = RAND_PART_B_STATE;
-            mCrc.updateCRC(ch2);
+    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();
@@ -723,113 +818,155 @@
         }
     }
 
-    private void setupNoRandPartA() {
-        if (i2 <= last) {
-            chPrev = ch2;
-            ch2 = ll8[tPos];
-            tPos = tt[tPos];
-            i2++;
-
-            currentChar = ch2;
-            currentState = NO_RAND_PART_B_STATE;
-            mCrc.updateCRC(ch2);
+    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() {
-        if (ch2 != chPrev) {
-            currentState = RAND_PART_A_STATE;
-            count = 1;
+    private void setupRandPartB() throws IOException {
+        if (this.su_ch2 != this.su_chPrev) {
+            this.currentState = RAND_PART_A_STATE;
+            this.su_count = 1;
             setupRandPartA();
-        } else {
-            count++;
-            if (count >= 4) {
-                z = ll8[tPos];
-                tPos = tt[tPos];
-                if (rNToGo == 0) {
-                    rNToGo = rNums[rTPos];
-                    rTPos++;
-                    if (rTPos == 512) {
-                        rTPos = 0;
-                    }
+        } 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;
                 }
-                rNToGo--;
-                z ^= ((rNToGo == 1) ? 1 : 0);
-                j2 = 0;
-                currentState = RAND_PART_C_STATE;
-                setupRandPartC();
             } else {
-                currentState = RAND_PART_A_STATE;
-                setupRandPartA();
+                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() {
-        if (j2 < (int) z) {
-            currentChar = ch2;
-            mCrc.updateCRC(ch2);
-            j2++;
+    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 {
-            currentState = RAND_PART_A_STATE;
-            i2++;
-            count = 0;
+            this.currentState = RAND_PART_A_STATE;
+            this.su_i2++;
+            this.su_count = 0;
             setupRandPartA();
         }
     }
 
-    private void setupNoRandPartB() {
-        if (ch2 != chPrev) {
-            currentState = NO_RAND_PART_A_STATE;
-            count = 1;
+    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 {
-            count++;
-            if (count >= 4) {
-                z = ll8[tPos];
-                tPos = tt[tPos];
-                currentState = NO_RAND_PART_C_STATE;
-                j2 = 0;
-                setupNoRandPartC();
-            } else {
-                currentState = NO_RAND_PART_A_STATE;
-                setupNoRandPartA();
-            }
+            setupNoRandPartA();
         }
     }
 
-    private void setupNoRandPartC() {
-        if (j2 < (int) z) {
-            currentChar = ch2;
-            mCrc.updateCRC(ch2);
-            j2++;
+    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 {
-            currentState = NO_RAND_PART_A_STATE;
-            i2++;
-            count = 0;
+            this.su_i2++;
+            this.su_count = 0;
             setupNoRandPartA();
         }
     }
 
-    private void setDecompressStructureSizes(int newSize100k) {
-        if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k
-               && blockSize100k <= 9)) {
-            // throw new IOException("Invalid block size");
-        }
+    private static final class Data extends Object {
 
-        blockSize100k = newSize100k;
+        // (with blockSize 900k)
+        final boolean[] inUse   = new boolean[256];                                   //      256 byte
 
-        if (newSize100k == 0) {
-            return;
+        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;
         }
 
-        int n = baseBlockSize * newSize100k;
-        ll8 = new char[n];
-        tt = new int[n];
     }
+
 }
 

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java?rev=732685&r1=732684&r2=732685&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java Thu Jan  8 03:13:50 2009
@@ -160,10 +160,10 @@
 
                 weight[nNodes] = ((weight[n1] & 0xffffff00)
                                   + (weight[n2] & 0xffffff00))
-                    | (1 + (((weight[n1] & 0x000000ff) >
-                             (weight[n2] & 0x000000ff)) ?
-                            (weight[n1] & 0x000000ff) :
-                            (weight[n2] & 0x000000ff)));
+                    | (1 + (((weight[n1] & 0x000000ff)
+                            > (weight[n2] & 0x000000ff))
+                            ? (weight[n1] & 0x000000ff)
+                            : (weight[n2] & 0x000000ff)));
 
                 parent[nNodes] = -1;
                 nHeap++;
@@ -428,6 +428,12 @@
         combinedCRC = (combinedCRC << 1) | (combinedCRC >>> 31);
         combinedCRC ^= blockCRC;
 
+        // If the stream was empty we must skip the rest of this method.
+        // See bug#32200.
+        if (last == -1) {
+	    return;
+        }
+        
         /* sort the block and establish posn of original string */
         doReversibleTransformation();
 
@@ -497,7 +503,7 @@
                     code[i] = vec;
                     vec++;
                 }
-            };
+            }
             vec <<= 1;
         }
     }
@@ -559,8 +565,7 @@
 
         int v, t, i, j, gs, ge, totc, bt, bc, iter;
         int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
-        int nGroups;
-        //int nBytes;
+        int nGroups, nBytes;
 
         alphaSize = nInUse + 2;
         for (t = 0; t < N_GROUPS; t++) {
@@ -698,7 +703,7 @@
                         bc = cost[t];
                         bt = t;
                     }
-                };
+                }
                 totc += bc;
                 fave[bt]++;
                 selector[nSelectors] = (char) bt;
@@ -791,7 +796,7 @@
                 }
             }
 
-            //nBytes = bytesOut;
+            nBytes = bytesOut;
             for (i = 0; i < 16; i++) {
                 if (inUse16[i]) {
                     bsW(1, 1);
@@ -815,7 +820,7 @@
         }
 
         /* Now the selectors. */
-        //nBytes = bytesOut;
+        nBytes = bytesOut;
         bsW (3, nGroups);
         bsW (15, nSelectors);
         for (i = 0; i < nSelectors; i++) {
@@ -826,7 +831,7 @@
         }
 
         /* Now the coding tables. */
-        //nBytes = bytesOut;
+        nBytes = bytesOut;
 
         for (t = 0; t < nGroups; t++) {
             int curr = len[t][0];
@@ -845,7 +850,7 @@
         }
 
         /* And finally, the block data proper */
-        //nBytes = bytesOut;
+        nBytes = bytesOut;
         selCtr = 0;
         gs = 0;
         while (true) {
@@ -988,13 +993,9 @@
         int dd;
     }
 
-    private void qSort3(int loSt, int hiSt, int dSt) {
+    private void qSort3(int loSt, int hiSt, int dSt, StackElem[] stack) {
         int unLo, unHi, ltLo, gtHi, med, n, m;
         int sp, lo, hi, d;
-        StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
-        for (int count = 0; count < QSORT_STACK_SIZE; count++) {
-            stack[count] = new StackElem();
-        }
 
         sp = 0;
 
@@ -1042,7 +1043,7 @@
                         ltLo++;
                         unLo++;
                         continue;
-                    };
+                    }
                     if (n >  0) {
                         break;
                     }
@@ -1061,7 +1062,7 @@
                         gtHi--;
                         unHi--;
                         continue;
-                    };
+                    }
                     if (n <  0) {
                         break;
                     }
@@ -1126,6 +1127,7 @@
         */
 
         //   if (verbosity >= 4) fprintf ( stderr, "   sort initialise ...\n" );
+
         for (i = 0; i < NUM_OVERSHOOT_BYTES; i++) {
             block[last + i + 2] = block[(i % (last + 1)) + 1];
         }
@@ -1203,8 +1205,8 @@
                         vv = runningOrder[i];
                         j = i;
                         while ((ftab[((runningOrder[j - h]) + 1) << 8]
-                                - ftab[(runningOrder[j - h]) << 8]) >
-                               (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
+                                - ftab[(runningOrder[j - h]) << 8])
+                                > (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
                             runningOrder[j] = runningOrder[j - h];
                             j = j - h;
                             if (j <= (h - 1)) {
@@ -1216,6 +1218,11 @@
                 } while (h != 1);
             }
 
+            StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+            for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+                stack[count] = new StackElem();
+            }
+
             /*
               The main sorting loop.
             */
@@ -1239,7 +1246,7 @@
                         int lo = ftab[sb] & CLEARMASK;
                         int hi = (ftab[sb + 1] & CLEARMASK) - 1;
                         if (hi > lo) {
-                            qSort3(lo, hi, 2);
+                            qSort3(lo, hi, 2, stack);
                             numQSorted += (hi - lo + 1);
                             if (workDone > workLimit && firstAttempt) {
                                 return;
@@ -1355,7 +1362,7 @@
                 origPtr = i;
                 break;
             }
-        };
+        }
 
         if (origPtr == -1) {
             panic();
@@ -1473,11 +1480,11 @@
             if (i1 > last) {
                 i1 -= last;
                 i1--;
-            };
+            }
             if (i2 > last) {
                 i2 -= last;
                 i2--;
-            };
+            }
 
             k -= 4;
             workDone++;
@@ -1492,9 +1499,9 @@
       because the number of elems to sort is
       usually small, typically <= 20.
     */
-    private int[] incs = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+    private int[] incs = {1, 4, 13, 40, 121, 364, 1093, 3280,
                            9841, 29524, 88573, 265720,
-                           797161, 2391484 };
+                           797161, 2391484};
 
     private void allocateCompressStructures () {
         int n = baseBlockSize * blockSize100k;
@@ -1560,7 +1567,7 @@
                 tmp2 = tmp;
                 tmp = yy[j];
                 yy[j] = tmp2;
-            };
+            }
             yy[0] = tmp;
 
             if (j == 0) {
@@ -1580,12 +1587,12 @@
                             wr++;
                             mtfFreq[RUNB]++;
                             break;
-                        };
+                        }
                         if (zPend < 2) {
                             break;
                         }
                         zPend = (zPend - 2) / 2;
-                    };
+                    }
                     zPend = 0;
                 }
                 szptr[wr] = (short) (j + 1);

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java?rev=732685&r1=732684&r2=732685&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java Thu Jan  8 03:13:50 2009
@@ -36,6 +36,13 @@
     int MAX_SELECTORS = (2 + (900000 / G_SIZE));
     int NUM_OVERSHOOT_BYTES = 20;
 
+    /**
+     * This array really shouldn't be here.
+     * Again, for historical purposes it is.
+     *
+     * <p>FIXME: This array should be in a private or package private
+     * location, since it could be modified by malicious code.</p>
+     */
     int[] rNums = {
         619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
         985, 724, 205, 454, 863, 491, 741, 242, 949, 214,

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java?rev=732685&r1=732684&r2=732685&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java Thu Jan  8 03:13:50 2009
@@ -23,78 +23,111 @@
  * data.
  */
 class CRC {
-	private static int[] CRC32_TABLE = new int[] { 0x00000000, 0x04c11db7,
-			0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2,
-			0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
-			0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70,
-			0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b,
-			0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6,
-			0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
-			0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c,
-			0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
-			0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea,
-			0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
-			0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028,
-			0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43,
-			0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19,
-			0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
-			0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13,
-			0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0,
-			0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5,
-			0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
-			0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697,
-			0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
-			0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041,
-			0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
-			0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b,
-			0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8,
-			0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded,
-			0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
-			0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56,
-			0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d,
-			0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0,
-			0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
-			0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa,
-			0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
-			0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc,
-			0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
-			0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e,
-			0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615,
-			0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8,
-			0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
-			0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645,
-			0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096,
-			0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093,
-			0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
-			0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651,
-			0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
-			0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17,
-			0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
-			0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d,
-			0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be,
-			0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb,
-			0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
-			0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };
-
-	private int m_globalCrc;
-
-	protected CRC() {
-		initialiseCRC();
-	}
-
-	int getFinalCRC() {
-		return ~m_globalCrc;
-	}
-
-	void initialiseCRC() {
-		m_globalCrc = 0xffffffff;
-	}
-
-	void updateCRC(final int inCh) {
-		int temp = (m_globalCrc >> 24) ^ inCh;
-		if (temp < 0) {
-			temp = 256 + temp;
-		}
-		m_globalCrc = (m_globalCrc << 8) ^ CRC32_TABLE[temp];
-	}
+	 static final int crc32Table[] = {
+	        0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+	        0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+	        0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+	        0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+	        0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+	        0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+	        0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+	        0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+	        0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+	        0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+	        0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+	        0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+	        0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+	        0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+	        0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+	        0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+	        0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+	        0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+	        0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+	        0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+	        0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+	        0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+	        0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+	        0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+	        0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+	        0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+	        0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+	        0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+	        0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+	        0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+	        0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+	        0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+	        0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+	        0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+	        0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+	        0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+	        0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+	        0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+	        0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+	        0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+	        0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+	        0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+	        0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+	        0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+	        0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+	        0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+	        0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+	        0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+	        0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+	        0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+	        0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+	        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+	    };
+
+	    CRC() {
+	        initialiseCRC();
+	    }
+
+	    void initialiseCRC() {
+	        globalCrc = 0xffffffff;
+	    }
+
+	    int getFinalCRC() {
+	        return ~globalCrc;
+	    }
+
+	    int getGlobalCRC() {
+	        return globalCrc;
+	    }
+
+	    void setGlobalCRC(int newCrc) {
+	        globalCrc = newCrc;
+	    }
+
+	    void updateCRC(int inCh) {
+	        int temp = (globalCrc >> 24) ^ inCh;
+	        if (temp < 0) {
+	            temp = 256 + temp;
+	        }
+	        globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
+	    }
+
+	    void updateCRC(int inCh, int repeat) {
+	        int globalCrcShadow = this.globalCrc;
+	        while (repeat-- > 0) {
+	            int temp = (globalCrcShadow >> 24) ^ inCh;
+	            globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0)
+	                                                      ? temp
+	                                                      : (temp + 256)];
+	        }
+	        this.globalCrc = globalCrcShadow;
+	    }
+
+	    int globalCrc;
 }
\ No newline at end of file



Mime
View raw message