Browse Source

Merge bzip2 input from Compress, bringing support for files with multiple streams

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@1350882 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 13 years ago
parent
commit
a67cf020bd
2 changed files with 137 additions and 54 deletions
  1. +3
    -0
      WHATSNEW
  2. +134
    -54
      src/main/org/apache/tools/bzip2/CBZip2InputStream.java

+ 3
- 0
WHATSNEW View File

@@ -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
===================================



+ 134
- 54
src/main/org/apache/tools/bzip2/CBZip2InputStream.java View File

@@ -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 InputStream implements BZip2Constants {
private int nInUse;

private InputStream in;
private final boolean decompressConcatenated;

private int currentChar = -1;

@@ -129,7 +108,8 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {

/**
* 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 InputStream implements BZip2Constants {
* 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 InputStream implements BZip2Constants {
}
}

/*
* (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 InputStream implements BZip2Constants {
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 InputStream implements BZip2Constants {
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 InputStream implements BZip2Constants {

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 InputStream implements BZip2Constants {
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 InputStream implements BZip2Constants {
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 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");
}

}


Loading…
Cancel
Save