    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}