diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/org/tukaani/xz/BCJDecoder.java | 2 | ||||
-rw-r--r-- | src/org/tukaani/xz/BlockInputStream.java | 25 | ||||
-rw-r--r-- | src/org/tukaani/xz/CountingInputStream.java | 4 | ||||
-rw-r--r-- | src/org/tukaani/xz/DeltaDecoder.java | 2 | ||||
-rw-r--r-- | src/org/tukaani/xz/FilterDecoder.java | 2 | ||||
-rw-r--r-- | src/org/tukaani/xz/LZMA2Decoder.java | 2 | ||||
-rw-r--r-- | src/org/tukaani/xz/SeekableXZInputStream.java | 195 | ||||
-rw-r--r-- | src/org/tukaani/xz/SingleXZInputStream.java | 174 | ||||
-rw-r--r-- | src/org/tukaani/xz/XZInputStream.java | 162 |
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; } |