Author: bodewig
Date: Sat Jun 16 08:08:51 2012
New Revision: 1350882
URL: http://svn.apache.org/viewvc?rev=1350882&view=rev
Log:
Merge bzip2 input from Compress, bringing support for files with multiple
streams
Modified:
ant/core/trunk/WHATSNEW
ant/core/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java
Modified: ant/core/trunk/WHATSNEW
URL:
http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=1350882&r1=1350881&r2=1350882&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Sat Jun 16 08:08:51 2012
@@ -52,6 +52,9 @@ Other changes:
* merged the TAR package from Commons Compress, it can now read
archives using POSIX extension headers and STAR extensions.
+ * merged the BZIP2 package from Commons Compress, it can now
+ optionally read files that contain multiple streams properly.
+
Changes from Ant 1.8.3 TO Ant 1.8.4
===================================
Modified: ant/core/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java?rev=1350882&r1=1350881&r2=1350882&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java Sat
Jun 16 08:08:51 2012
@@ -45,28 +45,6 @@ import java.io.InputStream;
*/
public class CBZip2InputStream extends InputStream implements BZip2Constants {
- private static void reportCRCError() throws IOException {
- // The clean way would be to throw an exception.
- //throw new IOException("crc error");
-
- // Just print a message, like the previous versions of this class did
- System.err.println("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.
*/
@@ -92,6 +70,7 @@ public class CBZip2InputStream extends I
private int nInUse;
private InputStream in;
+ private final boolean decompressConcatenated;
private int currentChar = -1;
@@ -129,7 +108,8 @@ public class CBZip2InputStream extends I
/**
* Constructs a new CBZip2InputStream which decompresses bytes read from
- * the specified stream.
+ * the specified stream. This doesn't suppprt decompressing
+ * concatenated .bz2 files.
*
* <p>Although BZip2 headers are marked with the magic
* <tt>"Bz"</tt> this constructor expects the next byte in the
@@ -143,12 +123,46 @@ public class CBZip2InputStream extends I
* if <tt>in == null</tt>
*/
public CBZip2InputStream(final InputStream in) throws IOException {
+ this(in, false);
+ }
+
+ /**
+ * 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>
+ *
+ * @param in the InputStream from which this object should be created
+ * @param decompressConcatenated
+ * if true, decompress until the end of the input;
+ * if false, stop after the first .bz2 stream and
+ * leave the input position to point to the next
+ * byte after the .bz2 stream
+ *
+ * @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,
+ final boolean decompressConcatenated)
+ throws IOException {
super();
this.in = in;
- init();
+ this.decompressConcatenated = decompressConcatenated;
+
+ init(true);
+ initBlock();
+ setupBlock();
}
+ /** {@inheritDoc} */
+ @Override
public int read() throws IOException {
if (this.in != null) {
return read0();
@@ -157,6 +171,12 @@ public class CBZip2InputStream extends I
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ @Override
public int read(final byte[] dest, final int offs, final int len)
throws IOException {
if (offs < 0) {
@@ -183,6 +203,21 @@ public class CBZip2InputStream extends I
return (destOffs == offs) ? -1 : (destOffs - offs);
}
+ 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;
+ }
+
private int read0() throws IOException {
final int retChar = this.currentChar;
@@ -222,18 +257,31 @@ public class CBZip2InputStream extends I
return retChar;
}
- private void init() throws IOException {
+ private boolean init(boolean isFirstStream) throws IOException {
if (null == in) {
throw new IOException("No InputStream");
}
- if (in.available() == 0) {
- throw new IOException("Empty InputStream");
+
+ if (isFirstStream) {
+ if (in.available() == 0) {
+ throw new IOException("Empty InputStream");
+ }
+ } else {
+ int magic0 = this.in.read();
+ if (magic0 == -1) {
+ return false;
+ }
+ int magic1 = this.in.read();
+ if (magic0 != 'B' || magic1 != 'Z') {
+ throw new IOException("Garbage after a valid BZip2 stream");
+ }
}
+
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
- + "'");
+ throw new IOException(isFirstStream
+ ? "Stream is not in the BZip2 format"
+ : "Garbage after a valid BZip2 stream");
}
int blockSize = this.in.read();
@@ -244,32 +292,50 @@ public class CBZip2InputStream extends I
this.blockSize100k = blockSize - '0';
- initBlock();
- setupBlock();
+ this.bsLive = 0;
+ this.computedCombinedCRC = 0;
+
+ return true;
}
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'
- ) {
+ char magic0;
+ char magic1;
+ char magic2;
+ char magic3;
+ char magic4;
+ char magic5;
+
+ while (true) {
+ // Get the block magic bytes.
+ magic0 = bsGetUByte();
+ magic1 = bsGetUByte();
+ magic2 = bsGetUByte();
+ magic3 = bsGetUByte();
+ magic4 = bsGetUByte();
+ magic5 = bsGetUByte();
+
+ // If isn't end of stream magic, break out of the loop.
+ if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45
+ || magic3 != 0x38 || magic4 != 0x50 || magic5 != 0x90) {
+ break;
+ }
+
+ // End of stream was reached. Check the combined CRC and
+ // advance to the next .bz2 stream if decoding concatenated
+ // streams.
+ if (complete()) {
+ return;
+ }
+ }
+
+ 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 {
@@ -313,7 +379,7 @@ public class CBZip2InputStream extends I
this.computedCombinedCRC ^= this.computedBlockCRC;
}
- private void complete() throws IOException {
+ private boolean complete() throws IOException {
this.storedCombinedCRC = bsGetInt();
this.currentState = EOF;
this.data = null;
@@ -321,8 +387,13 @@ public class CBZip2InputStream extends I
if (this.storedCombinedCRC != this.computedCombinedCRC) {
reportCRCError();
}
+
+ // Look for the next .bz2 stream if decompressing
+ // concatenated files.
+ return !decompressConcatenated || !init(false);
}
+ @Override
public void close() throws IOException {
InputStream inShadow = this.in;
if (inShadow != null) {
@@ -978,5 +1049,14 @@ public class CBZip2InputStream extends I
}
}
+
+ private static void reportCRCError() throws IOException {
+ // The clean way would be to throw an exception.
+ //throw new IOException("crc error");
+
+ // Just print a message, like the previous versions of this class did
+ System.err.println("BZip2 CRC error");
+ }
+
}