11e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan/*
21e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * SingleXZInputStream
31e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan *
41e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * Author: Lasse Collin <lasse.collin@tukaani.org>
51e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan *
61e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * This file has been put into the public domain.
71e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * You can do whatever you want with this file.
81e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan */
91e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
101e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanpackage org.tukaani.xz;
111e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
121e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport java.io.InputStream;
131e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport java.io.DataInputStream;
141e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport java.io.IOException;
151e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport java.io.EOFException;
161e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport org.tukaani.xz.common.DecoderUtil;
171e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport org.tukaani.xz.common.StreamFlags;
181e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport org.tukaani.xz.index.IndexHash;
191e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanimport org.tukaani.xz.check.Check;
201e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
211e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan/**
221e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * Decompresses exactly one XZ Stream in streamed mode (no seeking).
231e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * The decompression stops after the first XZ Stream has been decompressed,
241e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * and the read position in the input stream is left at the first byte
251e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * after the end of the XZ Stream. This can be useful when XZ data has
261e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * been stored inside some other file format or protocol.
271e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * <p>
281e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * Unless you know what you are doing, don't use this class to decompress
291e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * standalone .xz files. For that purpose, use <code>XZInputStream</code>.
301e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan *
311e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * <h4>When uncompressed size is known beforehand</h4>
321e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * <p>
331e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * If you are decompressing complete XZ streams and your application knows
341e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * exactly how much uncompressed data there should be, it is good to try
351e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * reading one more byte by calling <code>read()</code> and checking
361e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * that it returns <code>-1</code>. This way the decompressor will parse the
371e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * file footers and verify the integrity checks, giving the caller more
381e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * confidence that the uncompressed data is valid.
391e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan *
401e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan * @see XZInputStream
411e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan */
421e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnanpublic class SingleXZInputStream extends InputStream {
431e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private InputStream in;
441e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final int memoryLimit;
451e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final StreamFlags streamHeaderFlags;
461e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final Check check;
471e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final boolean verifyCheck;
481e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private BlockInputStream blockDecoder = null;
491e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final IndexHash indexHash = new IndexHash();
501e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private boolean endReached = false;
511e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private IOException exception = null;
521e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
531e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private final byte[] tempBuf = new byte[1];
541e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
551e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
561e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Reads the Stream Header into a buffer.
571e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * This is a helper function for the constructors.
581e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
591e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private static byte[] readStreamHeader(InputStream in) throws IOException {
601e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        byte[] streamHeader = new byte[DecoderUtil.STREAM_HEADER_SIZE];
611e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        new DataInputStream(in).readFully(streamHeader);
621e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return streamHeader;
631e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
641e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
651e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
661e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Creates a new XZ decompressor that decompresses exactly one
671e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * XZ Stream from <code>in</code> without a memory usage limit.
681e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
691e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * This constructor reads and parses the XZ Stream Header (12 bytes)
701e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * from <code>in</code>. The header of the first Block is not read
711e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * until <code>read</code> is called.
721e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
731e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       in          input stream from which XZ-compressed
741e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          data is read
751e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
761e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      XZFormatException
771e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          input is not in the XZ format
781e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
791e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      CorruptedInputException
801e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header CRC32 doesn't match
811e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
821e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      UnsupportedOptionsException
831e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header is valid but specifies options
841e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          not supported by this implementation
851e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
861e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      EOFException
871e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          less than 12 bytes of input was available
881e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          from <code>in</code>
891e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
901e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      IOException may be thrown by <code>in</code>
911e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
921e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public SingleXZInputStream(InputStream in) throws IOException {
931e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this(in, -1);
941e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
951e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
961e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
971e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Creates a new XZ decompressor that decompresses exactly one
981e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * XZ Stream from <code>in</code> with an optional memory usage limit.
991e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
1001e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * This is identical to <code>SingleXZInputStream(InputStream)</code>
1011e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * except that this takes also the <code>memoryLimit</code> argument.
1021e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1031e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       in          input stream from which XZ-compressed
1041e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          data is read
1051e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1061e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       memoryLimit memory usage limit in kibibytes (KiB)
1071e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          or <code>-1</code> to impose no
1081e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          memory usage limit
1091e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1101e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      XZFormatException
1111e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          input is not in the XZ format
1121e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1131e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      CorruptedInputException
1141e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header CRC32 doesn't match
1151e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1161e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      UnsupportedOptionsException
1171e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header is valid but specifies options
1181e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          not supported by this implementation
1191e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1201e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      EOFException
1211e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          less than 12 bytes of input was available
1221e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          from <code>in</code>
1231e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1241e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      IOException may be thrown by <code>in</code>
1251e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
1261e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public SingleXZInputStream(InputStream in, int memoryLimit)
1271e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throws IOException {
1281e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this(in, memoryLimit, true, readStreamHeader(in));
1291e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
1301e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
1311e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
1321e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Creates a new XZ decompressor that decompresses exactly one
1331e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * XZ Stream from <code>in</code> with an optional memory usage limit
1341e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * and ability to disable verification of integrity checks.
1351e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
1361e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * This is identical to <code>SingleXZInputStream(InputStream,int)</code>
1371e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * except that this takes also the <code>verifyCheck</code> argument.
1381e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
1391e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Note that integrity check verification should almost never be disabled.
1401e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Possible reasons to disable integrity check verification:
1411e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <ul>
1421e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   <li>Trying to recover data from a corrupt .xz file.</li>
1431e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   <li>Speeding up decompression. This matters mostly with SHA-256
1441e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   or with files that have compressed extremely well. It's recommended
1451e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   that integrity checking isn't disabled for performance reasons
1461e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   unless the file integrity is verified externally in some other
1471e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   way.</li>
1481e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * </ul>
1491e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
1501e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <code>verifyCheck</code> only affects the integrity check of
1511e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * the actual compressed data. The CRC32 fields in the headers
1521e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * are always verified.
1531e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1541e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       in          input stream from which XZ-compressed
1551e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          data is read
1561e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1571e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       memoryLimit memory usage limit in kibibytes (KiB)
1581e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          or <code>-1</code> to impose no
1591e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          memory usage limit
1601e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1611e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       verifyCheck if <code>true</code>, the integrity checks
1621e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          will be verified; this should almost never
1631e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          be set to <code>false</code>
1641e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1651e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      XZFormatException
1661e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          input is not in the XZ format
1671e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1681e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      CorruptedInputException
1691e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header CRC32 doesn't match
1701e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1711e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      UnsupportedOptionsException
1721e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          XZ header is valid but specifies options
1731e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          not supported by this implementation
1741e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1751e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      EOFException
1761e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          less than 12 bytes of input was available
1771e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          from <code>in</code>
1781e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1791e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      IOException may be thrown by <code>in</code>
1801e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
1811e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @since 1.6
1821e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
1831e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public SingleXZInputStream(InputStream in, int memoryLimit,
1841e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                               boolean verifyCheck) throws IOException {
1851e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this(in, memoryLimit, verifyCheck, readStreamHeader(in));
1861e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
1871e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
1881e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    SingleXZInputStream(InputStream in, int memoryLimit, boolean verifyCheck,
1891e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        byte[] streamHeader) throws IOException {
1901e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this.in = in;
1911e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this.memoryLimit = memoryLimit;
1921e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        this.verifyCheck = verifyCheck;
1931e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        streamHeaderFlags = DecoderUtil.decodeStreamHeader(streamHeader);
1941e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        check = Check.getInstance(streamHeaderFlags.checkType);
1951e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
1961e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
1971e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
1981e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Gets the ID of the integrity check used in this XZ Stream.
1991e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2001e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @return      the Check ID specified in the XZ Stream Header
2011e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
2021e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public int getCheckType() {
2031e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return streamHeaderFlags.checkType;
2041e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
2051e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2061e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
2071e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Gets the name of the integrity check used in this XZ Stream.
2081e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2091e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @return      the name of the check specified in the XZ Stream Header
2101e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
2111e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public String getCheckName() {
2121e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return check.getName();
2131e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
2141e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2151e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
2161e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Decompresses the next byte from this input stream.
2171e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
2181e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Reading lots of data with <code>read()</code> from this input stream
2191e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
2201e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * if you need to read lots of data one byte at a time.
2211e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2221e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @return      the next decompressed byte, or <code>-1</code>
2231e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *              to indicate the end of the compressed stream
2241e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2251e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      CorruptedInputException
2261e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      UnsupportedOptionsException
2271e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      MemoryLimitException
2281e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2291e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      XZIOException if the stream has been closed
2301e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2311e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      EOFException
2321e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          compressed input is truncated or corrupt
2331e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2341e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      IOException may be thrown by <code>in</code>
2351e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
2361e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public int read() throws IOException {
2371e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
2381e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
2391e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2401e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
2411e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Decompresses into an array of bytes.
2421e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <p>
2431e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * If <code>len</code> is zero, no bytes are read and <code>0</code>
2441e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * is returned. Otherwise this will try to decompress <code>len</code>
2451e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * bytes of uncompressed data. Less than <code>len</code> bytes may
2461e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * be read only in the following situations:
2471e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * <ul>
2481e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   <li>The end of the compressed data was reached successfully.</li>
2491e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   <li>An error is detected after at least one but less <code>len</code>
2501e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *       bytes have already been successfully decompressed.
2511e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *       The next call with non-zero <code>len</code> will immediately
2521e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *       throw the pending exception.</li>
2531e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *   <li>An exception is thrown.</li>
2541e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * </ul>
2551e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2561e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       buf         target buffer for uncompressed data
2571e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       off         start offset in <code>buf</code>
2581e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @param       len         maximum number of uncompressed bytes to read
2591e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2601e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @return      number of bytes read, or <code>-1</code> to indicate
2611e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *              the end of the compressed stream
2621e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2631e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      CorruptedInputException
2641e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      UnsupportedOptionsException
2651e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      MemoryLimitException
2661e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2671e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      XZIOException if the stream has been closed
2681e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2691e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      EOFException
2701e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *                          compressed input is truncated or corrupt
2711e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
2721e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws      IOException may be thrown by <code>in</code>
2731e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
2741e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public int read(byte[] buf, int off, int len) throws IOException {
2751e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
2761e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw new IndexOutOfBoundsException();
2771e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2781e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (len == 0)
2791e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            return 0;
2801e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2811e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (in == null)
2821e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw new XZIOException("Stream closed");
2831e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2841e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (exception != null)
2851e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw exception;
2861e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2871e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (endReached)
2881e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            return -1;
2891e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2901e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        int size = 0;
2911e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
2921e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        try {
2931e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            while (len > 0) {
2941e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                if (blockDecoder == null) {
2951e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    try {
2961e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        blockDecoder = new BlockInputStream(
2971e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                                in, check, verifyCheck, memoryLimit, -1, -1);
2981e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    } catch (IndexIndicatorException e) {
2991e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        indexHash.validate(in);
3001e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        validateStreamFooter();
3011e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        endReached = true;
3021e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                        return size > 0 ? size : -1;
3031e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    }
3041e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                }
3051e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3061e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                int ret = blockDecoder.read(buf, off, len);
3071e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3081e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                if (ret > 0) {
3091e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    size += ret;
3101e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    off += ret;
3111e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    len -= ret;
3121e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                } else if (ret == -1) {
3131e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    indexHash.add(blockDecoder.getUnpaddedSize(),
3141e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                                  blockDecoder.getUncompressedSize());
3151e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    blockDecoder = null;
3161e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                }
3171e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            }
3181e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        } catch (IOException e) {
3191e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            exception = e;
3201e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            if (size == 0)
3211e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                throw e;
3221e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        }
3231e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3241e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return size;
3251e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
3261e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3271e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    private void validateStreamFooter() throws IOException {
3281e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
3291e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        new DataInputStream(in).readFully(buf);
3301e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        StreamFlags streamFooterFlags = DecoderUtil.decodeStreamFooter(buf);
3311e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3321e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (!DecoderUtil.areStreamFlagsEqual(streamHeaderFlags,
3331e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                                             streamFooterFlags)
3341e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                || indexHash.getIndexSize() != streamFooterFlags.backwardSize)
3351e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw new CorruptedInputException(
3361e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                    "XZ Stream Footer does not match Stream Header");
3371e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
3381e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3391e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
3401e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Returns the number of uncompressed bytes that can be read
3411e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * without blocking. The value is returned with an assumption
3421e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * that the compressed input data will be valid. If the compressed
3431e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * data is corrupt, <code>CorruptedInputException</code> may get
3441e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * thrown before the number of bytes claimed to be available have
3451e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * been read from this input stream.
3461e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
3471e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @return      the number of uncompressed bytes that can be read
3481e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *              without blocking
3491e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
3501e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public int available() throws IOException {
3511e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (in == null)
3521e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw new XZIOException("Stream closed");
3531e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3541e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (exception != null)
3551e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            throw exception;
3561e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3571e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        return blockDecoder == null ? 0 : blockDecoder.available();
3581e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
3591e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan
3601e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    /**
3611e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * Closes the stream and calls <code>in.close()</code>.
3621e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * If the stream was already closed, this does nothing.
3631e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     *
3641e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     * @throws  IOException if thrown by <code>in.close()</code>
3651e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan     */
3661e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    public void close() throws IOException {
3671e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        if (in != null) {
3681e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            try {
3691e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                in.close();
3701e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            } finally {
3711e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan                in = null;
3721e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan            }
3731e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan        }
3741e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan    }
3751e977d75f657dacb4cb5c36ab6054bcf66b08076Vinod Krishnan}
376