expand BitInputStream to allow reading of up to 63 bits at once

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1654638 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
index 3064641..d40c1ad 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
@@ -42,7 +42,7 @@
      * @return The next bit (0 or 1) or -1 if the end of the stream has been reached
      */
     int nextBit() throws IOException {
-        return readBits(1);
+        return (int) readBits(1);
     }
 
     /**
@@ -51,11 +51,11 @@
      * @param n the number of bits read (up to 8)
      * @return The value formed by the n bits, or -1 if the end of the stream has been reached
      */
-    int nextBits(final int n) throws IOException {
+    long nextBits(final int n) throws IOException {
         return readBits(n);
     }
 
     int nextByte() throws IOException {
-        return readBits(8);
+        return (int) readBits(8);
     }
 }
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
index aa9a5ce..87d3c52 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
@@ -124,7 +124,7 @@
             if (literalTree != null) {
                 literal = literalTree.read(bits);
             } else {
-                literal = bits.nextBits(8);
+                literal = bits.nextByte();
             }
 
             if (literal == -1) {
@@ -137,7 +137,7 @@
         } else if (bit == 0) {
             // back reference
             int distanceLowSize = dictionarySize == 4096 ? 6 : 7;
-            int distanceLow = bits.nextBits(distanceLowSize);
+            int distanceLow = (int) bits.nextBits(distanceLowSize);
             int distanceHigh = distanceTree.read(bits);
             if (distanceHigh == -1 && distanceLow <= 0) {
                 // end of stream reached, nothing left to decode
diff --git a/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java b/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java
index df866e5..6900b7c 100644
--- a/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java
+++ b/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java
@@ -121,7 +121,10 @@
      * Reads the next code from the stream.
      */
     protected int readNextCode() throws IOException {
-        return in.readBits(codeSize);
+        if (codeSize > 31) {
+            throw new IllegalArgumentException("code size must not be bigger than 31");
+        }
+        return (int) in.readBits(codeSize);
     }
     
     /**
diff --git a/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java b/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
index fb41052..1bb65b5 100644
--- a/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
+++ b/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
@@ -40,9 +40,9 @@
     
     public ZCompressorInputStream(InputStream inputStream) throws IOException {
         super(inputStream, ByteOrder.LITTLE_ENDIAN);
-        int firstByte = in.readBits(8);
-        int secondByte = in.readBits(8);
-        int thirdByte = in.readBits(8);
+        int firstByte = (int) in.readBits(8);
+        int secondByte = (int) in.readBits(8);
+        int thirdByte = (int) in.readBits(8);
         if (firstByte != MAGIC_1 || secondByte != MAGIC_2 || thirdByte < 0) {
             throw new IOException("Input is not in .Z format");
         }
diff --git a/src/main/java/org/apache/commons/compress/utils/BitInputStream.java b/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
index d8988c7..dd1d9b6 100644
--- a/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
+++ b/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
@@ -29,8 +29,8 @@
  * @NotThreadSafe
  */
 public class BitInputStream implements Closeable {
-    private static final int MAXIMUM_CACHE_SIZE = 31; // bits in int minus sign bit
-    private static final int[] MASKS = new int[MAXIMUM_CACHE_SIZE + 1];
+    private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit
+    private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1];
 
     static {
         for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) {
@@ -40,7 +40,7 @@
 
     private final InputStream in;
     private final ByteOrder byteOrder;
-    private int bitsCached = 0;
+    private long bitsCached = 0;
     private int bitsCachedSize = 0;
 
     /**
@@ -68,20 +68,20 @@
     }
     
     /**
-     * Returns at most 31 bits read from the underlying stream.
+     * Returns at most 63 bits read from the underlying stream.
      *
      * @param count the number of bits to read, must be a positive
-     * number not bigger than 31.
-     * @return the bits concatenated as an integer using the stream's byte order.
+     * number not bigger than 63.
+     * @return the bits concatenated as a long using the stream's byte order.
      *         -1 if the end of the underlying stream has been reached before reading
      *         the requested number of bits
      */
-    public int readBits(final int count) throws IOException {
+    public long readBits(final int count) throws IOException {
         if (count < 0 || count > MAXIMUM_CACHE_SIZE) {
             throw new IllegalArgumentException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE);
         }
         while (bitsCachedSize < count) {
-            final int nextByte = in.read();
+            final long nextByte = in.read();
             if (nextByte < 0) {
                 return nextByte;
             }
@@ -94,7 +94,7 @@
             bitsCachedSize += 8;
         }
         
-        final int bitsOut;
+        final long bitsOut;
         if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
             bitsOut = (bitsCached & MASKS[count]);
             bitsCached >>>= count;
diff --git a/src/test/java/org/apache/commons/compress/utils/BitInputStreamTest.java b/src/test/java/org/apache/commons/compress/utils/BitInputStreamTest.java
index ed146cf..9c1eeca 100644
--- a/src/test/java/org/apache/commons/compress/utils/BitInputStreamTest.java
+++ b/src/test/java/org/apache/commons/compress/utils/BitInputStreamTest.java
@@ -35,9 +35,9 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void shouldNotAllowReadingOfMoreThan31BitsAtATime() throws IOException {
+    public void shouldNotAllowReadingOfMoreThan63BitsAtATime() throws IOException {
         BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN);
-        bis.readBits(32);
+        bis.readBits(64);
     }
 
     @Test