aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2017-10-13 18:47:28 +0300
committerLasse Collin <lasse.collin@tukaani.org>2017-12-16 17:34:30 +0200
commite989ce27f071100642babb5cd0dc03c56dfe4511 (patch)
tree3c514863f04d7495e741d1594931273f9e62a43b
parenta0d189d655b7cb34792bbda4b1a8b0230c541b34 (diff)
downloadxz-java-e989ce27f071100642babb5cd0dc03c56dfe4511.tar.gz
Add ArrayCache support to {,Single,Seekable}XZInputStream.
In addition to the new constructors, this adds close(boolean) to these three classes.
-rw-r--r--src/org/tukaani/xz/BCJDecoder.java2
-rw-r--r--src/org/tukaani/xz/BlockInputStream.java25
-rw-r--r--src/org/tukaani/xz/CountingInputStream.java4
-rw-r--r--src/org/tukaani/xz/DeltaDecoder.java2
-rw-r--r--src/org/tukaani/xz/FilterDecoder.java2
-rw-r--r--src/org/tukaani/xz/LZMA2Decoder.java2
-rw-r--r--src/org/tukaani/xz/SeekableXZInputStream.java195
-rw-r--r--src/org/tukaani/xz/SingleXZInputStream.java174
-rw-r--r--src/org/tukaani/xz/XZInputStream.java162
9 files changed, 547 insertions, 21 deletions
diff --git a/src/org/tukaani/xz/BCJDecoder.java b/src/org/tukaani/xz/BCJDecoder.java
index f8a6ae2..31251f2 100644
--- a/src/org/tukaani/xz/BCJDecoder.java
+++ b/src/org/tukaani/xz/BCJDecoder.java
@@ -39,7 +39,7 @@ class BCJDecoder extends BCJCoder implements FilterDecoder {
return SimpleInputStream.getMemoryUsage();
}
- public InputStream getInputStream(InputStream in) {
+ public InputStream getInputStream(InputStream in, ArrayCache arrayCache) {
SimpleFilter simpleFilter = null;
if (filterID == X86_FILTER_ID)
diff --git a/src/org/tukaani/xz/BlockInputStream.java b/src/org/tukaani/xz/BlockInputStream.java
index d1e72af..1931bd6 100644
--- a/src/org/tukaani/xz/BlockInputStream.java
+++ b/src/org/tukaani/xz/BlockInputStream.java
@@ -37,7 +37,8 @@ class BlockInputStream extends InputStream {
Check check, boolean verifyCheck,
int memoryLimit,
long unpaddedSizeInIndex,
- long uncompressedSizeInIndex)
+ long uncompressedSizeInIndex,
+ ArrayCache arrayCache)
throws IOException, IndexIndicatorException {
this.check = check;
this.verifyCheck = verifyCheck;
@@ -196,7 +197,7 @@ class BlockInputStream extends InputStream {
// Initialize the filter chain.
filterChain = inCounted;
for (int i = filters.length - 1; i >= 0; --i)
- filterChain = filters[i].getInputStream(filterChain);
+ filterChain = filters[i].getInputStream(filterChain, arrayCache);
}
public int read() throws IOException {
@@ -274,6 +275,26 @@ class BlockInputStream extends InputStream {
return filterChain.available();
}
+ public void close() {
+ // This puts all arrays, that were allocated from ArrayCache,
+ // back to the ArrayCache. The last filter in the chain will
+ // call inCounted.close() which, being an instance of
+ // CloseIgnoringInputStream, won't close() the InputStream that
+ // was provided by the application.
+ try {
+ filterChain.close();
+ } catch (IOException e) {
+ // It's a bug if we get here. The InputStreams that we are closing
+ // are all from this package and they are known to not throw
+ // IOException. (They could throw an IOException if we were
+ // closing the application-supplied InputStream, but
+ // inCounted.close() doesn't do that.)
+ assert false;
+ }
+
+ filterChain = null;
+ }
+
public long getUnpaddedSize() {
return headerSize + inCounted.getSize() + check.getSize();
}
diff --git a/src/org/tukaani/xz/CountingInputStream.java b/src/org/tukaani/xz/CountingInputStream.java
index ce0935a..8599f97 100644
--- a/src/org/tukaani/xz/CountingInputStream.java
+++ b/src/org/tukaani/xz/CountingInputStream.java
@@ -15,8 +15,10 @@ import java.io.IOException;
/**
* Counts the number of bytes read from an input stream.
+ * The <code>close()</code> method does nothing, that is, the underlying
+ * <code>InputStream</code> isn't closed.
*/
-class CountingInputStream extends FilterInputStream {
+class CountingInputStream extends CloseIgnoringInputStream {
private long size = 0;
public CountingInputStream(InputStream in) {
diff --git a/src/org/tukaani/xz/DeltaDecoder.java b/src/org/tukaani/xz/DeltaDecoder.java
index 445d178..4d21ca2 100644
--- a/src/org/tukaani/xz/DeltaDecoder.java
+++ b/src/org/tukaani/xz/DeltaDecoder.java
@@ -26,7 +26,7 @@ class DeltaDecoder extends DeltaCoder implements FilterDecoder {
return 1;
}
- public InputStream getInputStream(InputStream in) {
+ public InputStream getInputStream(InputStream in, ArrayCache arrayCache) {
return new DeltaInputStream(in, distance);
}
}
diff --git a/src/org/tukaani/xz/FilterDecoder.java b/src/org/tukaani/xz/FilterDecoder.java
index 8e2d006..6ec2f83 100644
--- a/src/org/tukaani/xz/FilterDecoder.java
+++ b/src/org/tukaani/xz/FilterDecoder.java
@@ -13,5 +13,5 @@ import java.io.InputStream;
interface FilterDecoder extends FilterCoder {
int getMemoryUsage();
- InputStream getInputStream(InputStream in);
+ InputStream getInputStream(InputStream in, ArrayCache arrayCache);
}
diff --git a/src/org/tukaani/xz/LZMA2Decoder.java b/src/org/tukaani/xz/LZMA2Decoder.java
index 82075c2..8e777fe 100644
--- a/src/org/tukaani/xz/LZMA2Decoder.java
+++ b/src/org/tukaani/xz/LZMA2Decoder.java
@@ -29,7 +29,7 @@ class LZMA2Decoder extends LZMA2Coder implements FilterDecoder {
return LZMA2InputStream.getMemoryUsage(dictSize);
}
- public InputStream getInputStream(InputStream in) {
+ public InputStream getInputStream(InputStream in, ArrayCache arrayCache) {
return new LZMA2InputStream(in, dictSize);
}
}
diff --git a/src/org/tukaani/xz/SeekableXZInputStream.java b/src/org/tukaani/xz/SeekableXZInputStream.java
index 612ee99..74f130e 100644
--- a/src/org/tukaani/xz/SeekableXZInputStream.java
+++ b/src/org/tukaani/xz/SeekableXZInputStream.java
@@ -75,6 +75,11 @@ import org.tukaani.xz.index.BlockInfo;
*/
public class SeekableXZInputStream extends SeekableInputStream {
/**
+ * Cache for big arrays.
+ */
+ private final ArrayCache arrayCache;
+
+ /**
* The input stream containing XZ compressed data.
*/
private SeekableInputStream in;
@@ -211,6 +216,43 @@ public class SeekableXZInputStream extends SeekableInputStream {
}
/**
+ * Creates a new seekable XZ decompressor without a memory usage limit.
+ * <p>
+ * This is identical to
+ * <code>SeekableXZInputStream(SeekableInputStream)</code> except that
+ * this also takes the <code>arrayCache</code> argument.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SeekableXZInputStream(SeekableInputStream in, ArrayCache arrayCache)
+ throws IOException {
+ this(in, -1, arrayCache);
+ }
+
+ /**
* Creates a new seekable XZ decomporessor with an optional
* memory usage limit.
*
@@ -250,6 +292,53 @@ public class SeekableXZInputStream extends SeekableInputStream {
/**
* Creates a new seekable XZ decomporessor with an optional
+ * memory usage limit.
+ * <p>
+ * This is identical to
+ * <code>SeekableXZInputStream(SeekableInputStream,int)</code>
+ * except that this also takes the <code>arrayCache</code> argument.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws MemoryLimitException
+ * decoded XZ Indexes would need more memory
+ * than allowed by the memory usage limit
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SeekableXZInputStream(SeekableInputStream in, int memoryLimit,
+ ArrayCache arrayCache)
+ throws IOException {
+ this(in, memoryLimit, true, arrayCache);
+ }
+
+ /**
+ * Creates a new seekable XZ decomporessor with an optional
* memory usage limit and ability to disable verification
* of integrity checks.
* <p>
@@ -306,6 +395,59 @@ public class SeekableXZInputStream extends SeekableInputStream {
public SeekableXZInputStream(SeekableInputStream in, int memoryLimit,
boolean verifyCheck)
throws IOException {
+ this(in, memoryLimit, verifyCheck, ArrayCache.getDefaultCache());
+ }
+
+ /**
+ * Creates a new seekable XZ decomporessor with an optional
+ * memory usage limit and ability to disable verification
+ * of integrity checks.
+ * <p>
+ * This is identical to
+ * <code>SeekableXZInputStream(SeekableInputStream,int,boolean)</code>
+ * except that this also takes the <code>arrayCache</code> argument.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws MemoryLimitException
+ * decoded XZ Indexes would need more memory
+ * than allowed by the memory usage limit
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SeekableXZInputStream(SeekableInputStream in, int memoryLimit,
+ boolean verifyCheck, ArrayCache arrayCache)
+ throws IOException {
+ this.arrayCache = arrayCache;
this.verifyCheck = verifyCheck;
this.in = in;
DataInputStream inData = new DataInputStream(in);
@@ -734,13 +876,48 @@ public class SeekableXZInputStream extends SeekableInputStream {
/**
* Closes the stream and calls <code>in.close()</code>.
* If the stream was already closed, this does nothing.
+ * <p>
+ * This is equivalent to <code>close(true)</code>.
*
* @throws IOException if thrown by <code>in.close()</code>
*/
public void close() throws IOException {
+ close(true);
+ }
+
+ /**
+ * Closes the stream and optionally calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ * If <code>close(false)</code> has been called, a further
+ * call of <code>close(true)</code> does nothing (it doesn't call
+ * <code>in.close()</code>).
+ * <p>
+ * If you don't want to close the underlying <code>InputStream</code>,
+ * there is usually no need to worry about closing this stream either;
+ * it's fine to do nothing and let the garbage collector handle it.
+ * However, if you are using {@link ArrayCache}, <code>close(false)</code>
+ * can be useful to put the allocated arrays back to the cache without
+ * closing the underlying <code>InputStream</code>.
+ * <p>
+ * Note that if you successfully reach the end of the stream
+ * (<code>read</code> returns <code>-1</code>), the arrays are
+ * automatically put back to the cache by that <code>read</code> call. In
+ * this situation <code>close(false)</code> is redundant (but harmless).
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ *
+ * @since 1.7
+ */
+ public void close(boolean closeInput) throws IOException {
if (in != null) {
+ if (blockDecoder != null) {
+ blockDecoder.close();
+ blockDecoder = null;
+ }
+
try {
- in.close();
+ if (closeInput)
+ in.close();
} finally {
in = null;
}
@@ -841,7 +1018,12 @@ public class SeekableXZInputStream extends SeekableInputStream {
// Check if we are seeking to or past the end of the file.
if (seekPos >= uncompressedSize) {
curPos = seekPos;
- blockDecoder = null;
+
+ if (blockDecoder != null) {
+ blockDecoder.close();
+ blockDecoder = null;
+ }
+
endReached = true;
return;
}
@@ -946,10 +1128,15 @@ public class SeekableXZInputStream extends SeekableInputStream {
try {
// Set it to null first so that GC can collect it if memory
// runs tight when initializing a new BlockInputStream.
- blockDecoder = null;
+ if (blockDecoder != null) {
+ blockDecoder.close();
+ blockDecoder = null;
+ }
+
blockDecoder = new BlockInputStream(
in, check, verifyCheck, memoryLimit,
- curBlockInfo.unpaddedSize, curBlockInfo.uncompressedSize);
+ curBlockInfo.unpaddedSize, curBlockInfo.uncompressedSize,
+ arrayCache);
} catch (MemoryLimitException e) {
// BlockInputStream doesn't know how much memory we had
// already needed so we need to recreate the exception.
diff --git a/src/org/tukaani/xz/SingleXZInputStream.java b/src/org/tukaani/xz/SingleXZInputStream.java
index f0c5a16..8da2be0 100644
--- a/src/org/tukaani/xz/SingleXZInputStream.java
+++ b/src/org/tukaani/xz/SingleXZInputStream.java
@@ -41,6 +41,7 @@ import org.tukaani.xz.check.Check;
*/
public class SingleXZInputStream extends InputStream {
private InputStream in;
+ private final ArrayCache arrayCache;
private final int memoryLimit;
private final StreamFlags streamHeaderFlags;
private final Check check;
@@ -95,10 +96,45 @@ public class SingleXZInputStream extends InputStream {
/**
* Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> without a memory usage limit.
+ * <p>
+ * This is identical to <code>SingleXZInputStream(InputStream)</code>
+ * except that this also takes the <code>arrayCache</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SingleXZInputStream(InputStream in, ArrayCache arrayCache)
+ throws IOException {
+ this(in, -1, arrayCache);
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
* XZ Stream from <code>in</code> with an optional memory usage limit.
* <p>
* This is identical to <code>SingleXZInputStream(InputStream)</code>
- * except that this takes also the <code>memoryLimit</code> argument.
+ * except that this also takes the <code>memoryLimit</code> argument.
*
* @param in input stream from which XZ-compressed
* data is read
@@ -125,7 +161,47 @@ public class SingleXZInputStream extends InputStream {
*/
public SingleXZInputStream(InputStream in, int memoryLimit)
throws IOException {
- this(in, memoryLimit, true, readStreamHeader(in));
+ this(in, memoryLimit, true);
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> with an optional memory usage limit.
+ * <p>
+ * This is identical to <code>SingleXZInputStream(InputStream)</code>
+ * except that this also takes the <code>memoryLimit</code> and
+ * <code>arrayCache</code> arguments.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SingleXZInputStream(InputStream in, int memoryLimit,
+ ArrayCache arrayCache) throws IOException {
+ this(in, memoryLimit, true, arrayCache);
}
/**
@@ -134,7 +210,7 @@ public class SingleXZInputStream extends InputStream {
* and ability to disable verification of integrity checks.
* <p>
* This is identical to <code>SingleXZInputStream(InputStream,int)</code>
- * except that this takes also the <code>verifyCheck</code> argument.
+ * except that this also takes the <code>verifyCheck</code> argument.
* <p>
* Note that integrity check verification should almost never be disabled.
* Possible reasons to disable integrity check verification:
@@ -182,11 +258,59 @@ public class SingleXZInputStream extends InputStream {
*/
public SingleXZInputStream(InputStream in, int memoryLimit,
boolean verifyCheck) throws IOException {
- this(in, memoryLimit, verifyCheck, readStreamHeader(in));
+ this(in, memoryLimit, verifyCheck, ArrayCache.getDefaultCache());
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> with an optional memory usage limit
+ * and ability to disable verification of integrity checks.
+ * <p>
+ * This is identical to
+ * <code>SingleXZInputStream(InputStream,int,boolean)</code>
+ * except that this also takes the <code>arrayCache</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public SingleXZInputStream(InputStream in, int memoryLimit,
+ boolean verifyCheck, ArrayCache arrayCache)
+ throws IOException {
+ this(in, memoryLimit, verifyCheck, readStreamHeader(in), arrayCache);
}
SingleXZInputStream(InputStream in, int memoryLimit, boolean verifyCheck,
- byte[] streamHeader) throws IOException {
+ byte[] streamHeader, ArrayCache arrayCache)
+ throws IOException {
+ this.arrayCache = arrayCache;
this.in = in;
this.memoryLimit = memoryLimit;
this.verifyCheck = verifyCheck;
@@ -294,7 +418,8 @@ public class SingleXZInputStream extends InputStream {
if (blockDecoder == null) {
try {
blockDecoder = new BlockInputStream(
- in, check, verifyCheck, memoryLimit, -1, -1);
+ in, check, verifyCheck, memoryLimit, -1, -1,
+ arrayCache);
} catch (IndexIndicatorException e) {
indexHash.validate(in);
validateStreamFooter();
@@ -360,13 +485,48 @@ public class SingleXZInputStream extends InputStream {
/**
* Closes the stream and calls <code>in.close()</code>.
* If the stream was already closed, this does nothing.
+ * <p>
+ * This is equivalent to <code>close(true)</code>.
*
* @throws IOException if thrown by <code>in.close()</code>
*/
public void close() throws IOException {
+ close(true);
+ }
+
+ /**
+ * Closes the stream and optionally calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ * If <code>close(false)</code> has been called, a further
+ * call of <code>close(true)</code> does nothing (it doesn't call
+ * <code>in.close()</code>).
+ * <p>
+ * If you don't want to close the underlying <code>InputStream</code>,
+ * there is usually no need to worry about closing this stream either;
+ * it's fine to do nothing and let the garbage collector handle it.
+ * However, if you are using {@link ArrayCache}, <code>close(false)</code>
+ * can be useful to put the allocated arrays back to the cache without
+ * closing the underlying <code>InputStream</code>.
+ * <p>
+ * Note that if you successfully reach the end of the stream
+ * (<code>read</code> returns <code>-1</code>), the arrays are
+ * automatically put back to the cache by that <code>read</code> call. In
+ * this situation <code>close(false)</code> is redundant (but harmless).
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ *
+ * @since 1.7
+ */
+ public void close(boolean closeInput) throws IOException {
if (in != null) {
+ if (blockDecoder != null) {
+ blockDecoder.close();
+ blockDecoder = null;
+ }
+
try {
- in.close();
+ if (closeInput)
+ in.close();
} finally {
in = null;
}
diff --git a/src/org/tukaani/xz/XZInputStream.java b/src/org/tukaani/xz/XZInputStream.java
index 0d460ea..680f647 100644
--- a/src/org/tukaani/xz/XZInputStream.java
+++ b/src/org/tukaani/xz/XZInputStream.java
@@ -61,6 +61,8 @@ import org.tukaani.xz.common.DecoderUtil;
* @see SingleXZInputStream
*/
public class XZInputStream extends InputStream {
+ private final ArrayCache arrayCache;
+
private final int memoryLimit;
private InputStream in;
private SingleXZInputStream xzIn;
@@ -101,6 +103,40 @@ public class XZInputStream extends InputStream {
}
/**
+ * Creates a new XZ decompressor without a memory usage limit.
+ * <p>
+ * This is identical to <code>XZInputStream(InputStream)</code>
+ * except that this takes also the <code>arrayCache</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public XZInputStream(InputStream in, ArrayCache arrayCache)
+ throws IOException {
+ this(in, -1, arrayCache);
+ }
+
+ /**
* Creates a new XZ decompressor with an optional memory usage limit.
* <p>
* This is identical to <code>XZInputStream(InputStream)</code> except
@@ -134,6 +170,45 @@ public class XZInputStream extends InputStream {
}
/**
+ * Creates a new XZ decompressor with an optional memory usage limit.
+ * <p>
+ * This is identical to <code>XZInputStream(InputStream)</code> except
+ * that this takes also the <code>memoryLimit</code> and
+ * <code>arrayCache</code> arguments.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public XZInputStream(InputStream in, int memoryLimit,
+ ArrayCache arrayCache) throws IOException {
+ this(in, memoryLimit, true, arrayCache);
+ }
+
+ /**
* Creates a new XZ decompressor with an optional memory usage limit
* and ability to disable verification of integrity checks.
* <p>
@@ -186,10 +261,55 @@ public class XZInputStream extends InputStream {
*/
public XZInputStream(InputStream in, int memoryLimit, boolean verifyCheck)
throws IOException {
+ this(in, memoryLimit, verifyCheck, ArrayCache.getDefaultCache());
+ }
+
+ /**
+ * Creates a new XZ decompressor with an optional memory usage limit
+ * and ability to disable verification of integrity checks.
+ * <p>
+ * This is identical to <code>XZInputStream(InputStream,int,boolean)</code>
+ * except that this takes also the <code>arrayCache</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @param arrayCache cache to be used for allocating large arrays
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.7
+ */
+ public XZInputStream(InputStream in, int memoryLimit, boolean verifyCheck,
+ ArrayCache arrayCache) throws IOException {
+ this.arrayCache = arrayCache;
this.in = in;
this.memoryLimit = memoryLimit;
this.verifyCheck = verifyCheck;
- this.xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck);
+ this.xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck,
+ arrayCache);
}
/**
@@ -323,7 +443,8 @@ public class XZInputStream extends InputStream {
inData.readFully(buf, 4, DecoderUtil.STREAM_HEADER_SIZE - 4);
try {
- xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck, buf);
+ xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck, buf,
+ arrayCache);
} catch (XZFormatException e) {
// Since this isn't the first .xz Stream, it is more
// logical to tell that the data is corrupt.
@@ -356,13 +477,48 @@ public class XZInputStream extends InputStream {
/**
* Closes the stream and calls <code>in.close()</code>.
* If the stream was already closed, this does nothing.
+ * <p>
+ * This is equivalent to <code>close(true)</code>.
*
* @throws IOException if thrown by <code>in.close()</code>
*/
public void close() throws IOException {
+ close(true);
+ }
+
+ /**
+ * Closes the stream and optionally calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ * If <code>close(false)</code> has been called, a further
+ * call of <code>close(true)</code> does nothing (it doesn't call
+ * <code>in.close()</code>).
+ * <p>
+ * If you don't want to close the underlying <code>InputStream</code>,
+ * there is usually no need to worry about closing this stream either;
+ * it's fine to do nothing and let the garbage collector handle it.
+ * However, if you are using {@link ArrayCache}, <code>close(false)</code>
+ * can be useful to put the allocated arrays back to the cache without
+ * closing the underlying <code>InputStream</code>.
+ * <p>
+ * Note that if you successfully reach the end of the stream
+ * (<code>read</code> returns <code>-1</code>), the arrays are
+ * automatically put back to the cache by that <code>read</code> call. In
+ * this situation <code>close(false)</code> is redundant (but harmless).
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ *
+ * @since 1.7
+ */
+ public void close(boolean closeInput) throws IOException {
if (in != null) {
+ if (xzIn != null) {
+ xzIn.close(false);
+ xzIn = null;
+ }
+
try {
- in.close();
+ if (closeInput)
+ in.close();
} finally {
in = null;
}