All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.signalfx.shaded.apache.commons.io.input.ChecksumInputStream Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.signalfx.shaded.apache.commons.io.input;

import static com.signalfx.shaded.apache.commons.io.IOUtils.EOF;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.CheckedInputStream;
import java.util.zip.Checksum;

import com.signalfx.shaded.apache.commons.io.build.AbstractStreamBuilder;

/**
 * Automatically verifies a {@link Checksum} value once the stream is exhausted or the count threshold is reached.
 * 

* If the {@link Checksum} does not meet the expected value when exhausted, then the input stream throws an * {@link IOException}. *

*

* If you do not need the verification or threshold feature, then use a plain {@link CheckedInputStream}. *

*

* To build an instance, use {@link Builder}. *

* * @see Builder * @since 2.16.0 */ public final class ChecksumInputStream extends CountingInputStream { // @formatter:off /** * Builds a new {@link ChecksumInputStream}. * *

* There is no default {@link Checksum}; you MUST provide one. *

*

Using NIO

*
{@code
     * ChecksumInputStream s = ChecksumInputStream.builder()
     *   .setPath(Paths.get("MyFile.xml"))
     *   .setChecksum(new CRC32())
     *   .setExpectedChecksumValue(12345)
     *   .get();
     * }
*

Using IO

*
{@code
     * ChecksumInputStream s = ChecksumInputStream.builder()
     *   .setFile(new File("MyFile.xml"))
     *   .setChecksum(new CRC32())
     *   .setExpectedChecksumValue(12345)
     *   .get();
     * }
*

Validating only part of an InputStream

*

* The following validates the first 100 bytes of the given input. *

*
{@code
     * ChecksumInputStream s = ChecksumInputStream.builder()
     *   .setPath(Paths.get("MyFile.xml"))
     *   .setChecksum(new CRC32())
     *   .setExpectedChecksumValue(12345)
     *   .setCountThreshold(100)
     *   .get();
     * }
*

* To validate input after the beginning of a stream, build an instance with an InputStream starting where you want to validate. *

*
{@code
     * InputStream inputStream = ...;
     * inputStream.read(...);
     * inputStream.skip(...);
     * ChecksumInputStream s = ChecksumInputStream.builder()
     *   .setInputStream(inputStream)
     *   .setChecksum(new CRC32())
     *   .setExpectedChecksumValue(12345)
     *   .setCountThreshold(100)
     *   .get();
     * }
* * @see #get() */ // @formatter:on public static class Builder extends AbstractStreamBuilder { /** * There is no default checksum, you MUST provide one. This avoids any issue with a default {@link Checksum} * being proven deficient or insecure in the future. */ private Checksum checksum; /** * The count threshold to limit how much input is consumed to update the {@link Checksum} before the input * stream validates its value. *

* By default, all input updates the {@link Checksum}. *

*/ private long countThreshold = -1; /** * The expected {@link Checksum} value once the stream is exhausted or the count threshold is reached. */ private long expectedChecksumValue; /** * Builds a new {@link ChecksumInputStream}. *

* You must set input that supports {@link #getInputStream()}, otherwise, this method throws an exception. *

*

* This builder use the following aspects: *

*
    *
  • {@link #getInputStream()}
  • *
  • {@link Checksum}
  • *
  • expectedChecksumValue
  • *
  • countThreshold
  • *
* * @return a new instance. * @throws IllegalStateException if the {@code origin} is {@code null}. * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}. * @throws IOException if an I/O error occurs. * @see #getInputStream() */ @SuppressWarnings("resource") @Override public ChecksumInputStream get() throws IOException { return new ChecksumInputStream(getInputStream(), checksum, expectedChecksumValue, countThreshold); } /** * Sets the Checksum. * * @param checksum the Checksum. * @return this. */ public Builder setChecksum(final Checksum checksum) { this.checksum = checksum; return this; } /** * Sets the count threshold to limit how much input is consumed to update the {@link Checksum} before the input * stream validates its value. *

* By default, all input updates the {@link Checksum}. *

* * @param countThreshold the count threshold. A negative number means the threshold is unbound. * @return this. */ public Builder setCountThreshold(final long countThreshold) { this.countThreshold = countThreshold; return this; } /** * The expected {@link Checksum} value once the stream is exhausted or the count threshold is reached. * * @param expectedChecksumValue The expected Checksum value. * @return this. */ public Builder setExpectedChecksumValue(final long expectedChecksumValue) { this.expectedChecksumValue = expectedChecksumValue; return this; } } /** * Constructs a new {@link Builder}. * * @return a new {@link Builder}. */ public static Builder builder() { return new Builder(); } /** The expected checksum. */ private final long expectedChecksumValue; /** * The count threshold to limit how much input is consumed to update the {@link Checksum} before the input stream * validates its value. *

* By default, all input updates the {@link Checksum}. *

*/ private final long countThreshold; /** * Constructs a new instance. * * @param in the stream to wrap. * @param checksum a Checksum implementation. * @param expectedChecksumValue the expected checksum. * @param countThreshold the count threshold to limit how much input is consumed, a negative number means the * threshold is unbound. */ private ChecksumInputStream(final InputStream in, final Checksum checksum, final long expectedChecksumValue, final long countThreshold) { super(new CheckedInputStream(in, checksum)); this.countThreshold = countThreshold; this.expectedChecksumValue = expectedChecksumValue; } @Override protected synchronized void afterRead(final int n) throws IOException { super.afterRead(n); if ((countThreshold > 0 && getByteCount() >= countThreshold || n == EOF) && expectedChecksumValue != getChecksum().getValue()) { // Validate when past the threshold or at EOF throw new IOException("Checksum verification failed."); } } /** * Gets the current checksum value. * * @return the current checksum value. */ private Checksum getChecksum() { return ((CheckedInputStream) in).getChecksum(); } /** * Gets the byte count remaining to read. * * @return bytes remaining to read, a negative number means the threshold is unbound. */ public long getRemaining() { return countThreshold - getByteCount(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy