001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.utils;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.util.zip.CheckedInputStream;
024import java.util.zip.Checksum;
025
026/**
027 * Verifies the checksum of the data read once the stream is exhausted.
028 *
029 * @NotThreadSafe
030 * @since 1.7
031 * @deprecated Use {@link org.apache.commons.io.input.ChecksumInputStream}.
032 */
033@Deprecated
034public class ChecksumVerifyingInputStream extends CheckedInputStream {
035    private long remaining;
036    private final long expected;
037
038    /**
039     * Constructs a new instance.
040     *
041     * @param checksum         Checksum implementation.
042     * @param in               the stream to wrap
043     * @param size             the of the stream's content
044     * @param expectedChecksum the expected checksum
045     */
046    public ChecksumVerifyingInputStream(final Checksum checksum, final InputStream in, final long size, final long expectedChecksum) {
047        super(in, checksum);
048        this.expected = expectedChecksum;
049        this.remaining = size;
050    }
051
052    /**
053     * Gets the byte count remaining to read.
054     *
055     * @return bytes remaining to read.
056     * @since 1.21
057     */
058    public long getBytesRemaining() {
059        return remaining;
060    }
061
062    /**
063     * Reads a single byte from the stream
064     *
065     * @throws IOException if the underlying stream throws or the stream is exhausted and the Checksum doesn't match the expected value
066     */
067    @Override
068    public int read() throws IOException {
069        if (remaining <= 0) {
070            return -1;
071        }
072        final int data = super.read();
073        if (data >= 0) {
074            --remaining;
075        }
076        verify();
077        return data;
078    }
079
080    /**
081     * Reads from the stream into a byte array.
082     *
083     * @throws IOException if the underlying stream throws or the stream is exhausted and the Checksum doesn't match the expected value
084     */
085    @Override
086    public int read(final byte[] b, final int off, final int len) throws IOException {
087        if (len == 0) {
088            return 0;
089        }
090        final int readCount = super.read(b, off, len);
091        if (readCount >= 0) {
092            remaining -= readCount;
093        }
094        verify();
095        return readCount;
096    }
097
098    private void verify() throws IOException {
099        if (remaining <= 0 && expected != getChecksum().getValue()) {
100            throw new IOException("Checksum verification failed");
101        }
102    }
103}