bundles/org.tukani.xz/src/org/tukaani/xz/SeekableXZInputStream.java
public int read(byte[] buf, int off, int len) throws IOException {
        if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
            throw new IndexOutOfBoundsException();

        if (len == 0)
            return 0;

        if (in == null)
            throw new XZIOException("Stream closed");

        if (exception != null)
            throw exception;

        int size = 0;

        try {
            if (seekNeeded)
                seek();

            if (endReached)
                return -1;

            while (len > 0) {
                if (blockDecoder == null) {
                    seek();
                    if (endReached)
                        break;
                }

                int ret = blockDecoder.read(buf, off, len);

                if (ret > 0) {
                    curPos += ret;
                    size += ret;
                    off += ret;
                    len -= ret;
                } else if (ret == -1) {
                    blockDecoder = null;
                }
            }
        } catch (IOException e) {
            // We know that the file isn't simply truncated because we could
            // parse the Indexes in the constructor. So convert EOFException
            // to CorruptedInputException.
            if (e instanceof EOFException)
                e = new CorruptedInputException();

            exception = e;
            if (size == 0)
                throw e;
        }

        return size;
    }
public int read(byte[] buf, int off, int len) throws IOException {
        if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
            throw new IndexOutOfBoundsException();

        if (len == 0)
            return 0;

        if (in == null)
            throw new XZIOException("Stream closed");

        if (exception != null)
            throw exception;

        int size = 0;

        try {
            if (seekNeeded)
                seek();

            if (endReached)
                return -1;

            while (len > 0) {
                if (blockDecoder == null) {
                    seek();
                    if (endReached)
                        break;
                }

                int ret = blockDecoder.read(buf, off, len);

                if (ret > 0) {
                    curPos += ret;
                    size += ret;
                    off += ret;
                    len -= ret;
                } else if (ret == -1) {
                    blockDecoder = null;
                }
            }
        } catch (IOException e) {
            // We know that the file isn't simply truncated because we could
            // parse the Indexes in the constructor. So convert EOFException
            // to CorruptedInputException.
            if (e instanceof EOFException)
                e = new CorruptedInputException();

            exception = e;
            if (size == 0)
                throw e;
        }

        return size;
    }
Decompresses into an array of bytes.
<p>
If <code>len</code> is zero, no bytes are read and <code>0</code>
is returned. Otherwise this will try to decompress <code>len</code>
bytes of uncompressed data. Less than <code>len</code> bytes may
be read only in the following situations:
<ul>
<li>The end of the compressed data was reached successfully.</li>
<li>An error is detected after at least one but less than
<code>len</code> bytes have already been successfully
decompressed. The next call with non-zero <code>len</code>
will immediately throw the pending exception.</li>
<li>An exception is thrown.</li>
</ul>

@param       buf         target buffer for uncompressed data
@param       off         start offset in <code>buf</code>
@param       len         maximum number of uncompressed bytes to read

@return      number of bytes read, or <code>-1</code> to indicate
the end of the compressed stream

@throws      CorruptedInputException
@throws      UnsupportedOptionsException
@throws      MemoryLimitException

@throws      XZIOException if the stream has been closed

@throws      IOException may be thrown by <code>in</code>