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 * merged the TAR package from Commons Compress, it can now read
archives using POSIX extension headers and STAR extensions. 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 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 { 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. * 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 int nInUse;


private InputStream in; private InputStream in;
private final boolean decompressConcatenated;


private int currentChar = -1; private int currentChar = -1;


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


/** /**
* Constructs a new CBZip2InputStream which decompresses bytes read from * 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 * <p>Although BZip2 headers are marked with the magic
* <tt>"Bz"</tt> this constructor expects the next byte in the * <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> * if <tt>in == null</tt>
*/ */
public CBZip2InputStream(final InputStream in) throws IOException { 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(); super();


this.in = in; this.in = in;
init();
this.decompressConcatenated = decompressConcatenated;

init(true);
initBlock();
setupBlock();
} }


/** {@inheritDoc} */
@Override
public int read() throws IOException { public int read() throws IOException {
if (this.in != null) { if (this.in != null) {
return read0(); 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) public int read(final byte[] dest, final int offs, final int len)
throws IOException { throws IOException {
if (offs < 0) { if (offs < 0) {
@@ -183,6 +203,21 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {
return (destOffs == offs) ? -1 : (destOffs - offs); 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 { private int read0() throws IOException {
final int retChar = this.currentChar; final int retChar = this.currentChar;


@@ -222,18 +257,31 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {
return retChar; return retChar;
} }


private void init() throws IOException {
private boolean init(boolean isFirstStream) throws IOException {
if (null == in) { if (null == in) {
throw new IOException("No InputStream"); 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(); int magic2 = this.in.read();
if (magic2 != 'h') { 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(); int blockSize = this.in.read();
@@ -244,32 +292,50 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {


this.blockSize100k = blockSize - '0'; this.blockSize100k = blockSize - '0';


initBlock();
setupBlock();
this.bsLive = 0;
this.computedCombinedCRC = 0;

return true;
} }


private void initBlock() throws IOException { 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; this.currentState = EOF;
throw new IOException("bad block header"); throw new IOException("bad block header");
} else { } else {
@@ -313,7 +379,7 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {
this.computedCombinedCRC ^= this.computedBlockCRC; this.computedCombinedCRC ^= this.computedBlockCRC;
} }


private void complete() throws IOException {
private boolean complete() throws IOException {
this.storedCombinedCRC = bsGetInt(); this.storedCombinedCRC = bsGetInt();
this.currentState = EOF; this.currentState = EOF;
this.data = null; this.data = null;
@@ -321,8 +387,13 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants {
if (this.storedCombinedCRC != this.computedCombinedCRC) { if (this.storedCombinedCRC != this.computedCombinedCRC) {
reportCRCError(); reportCRCError();
} }

// Look for the next .bz2 stream if decompressing
// concatenated files.
return !decompressConcatenated || !init(false);
} }


@Override
public void close() throws IOException { public void close() throws IOException {
InputStream inShadow = this.in; InputStream inShadow = this.in;
if (inShadow != null) { 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