1 /* 2 * Copyright (C) 2013 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.hash; 16 17 import static com.google.common.base.Preconditions.checkNotNull; 18 19 import com.google.common.annotations.Beta; 20 21 import java.io.FilterInputStream; 22 import java.io.IOException; 23 import java.io.InputStream; 24 25 /** 26 * An {@link InputStream} that maintains a hash of the data read from it. 27 * 28 * @author Qian Huang 29 * @since 16.0 30 */ 31 @Beta 32 public final class HashingInputStream extends FilterInputStream { 33 private final Hasher hasher; 34 35 /** 36 * Creates an input stream that hashes using the given {@link HashFunction} and delegates all data 37 * read from it to the underlying {@link InputStream}. 38 * 39 * <p>The {@link InputStream} should not be read from before or after the hand-off. 40 */ HashingInputStream(HashFunction hashFunction, InputStream in)41 public HashingInputStream(HashFunction hashFunction, InputStream in) { 42 super(checkNotNull(in)); 43 this.hasher = checkNotNull(hashFunction.newHasher()); 44 } 45 46 /** 47 * Reads the next byte of data from the underlying input stream and updates the hasher with 48 * the byte read. 49 */ 50 @Override read()51 public int read() throws IOException { 52 int b = in.read(); 53 if (b != -1) { 54 hasher.putByte((byte) b); 55 } 56 return b; 57 } 58 59 /** 60 * Reads the specified bytes of data from the underlying input stream and updates the hasher with 61 * the bytes read. 62 */ 63 @Override read(byte[] bytes, int off, int len)64 public int read(byte[] bytes, int off, int len) throws IOException { 65 int numOfBytesRead = in.read(bytes, off, len); 66 if (numOfBytesRead != -1) { 67 hasher.putBytes(bytes, off, numOfBytesRead); 68 } 69 return numOfBytesRead; 70 } 71 72 /** 73 * mark() is not supported for HashingInputStream 74 * @return {@code false} always 75 */ 76 @Override markSupported()77 public boolean markSupported() { 78 return false; 79 } 80 81 /** 82 * mark() is not supported for HashingInputStream 83 */ 84 @Override mark(int readlimit)85 public void mark(int readlimit) {} 86 87 /** 88 * reset() is not supported for HashingInputStream. 89 * @throws IOException this operation is not supported 90 */ 91 @Override reset()92 public void reset() throws IOException { 93 throw new IOException("reset not supported"); 94 } 95 96 /** 97 * Returns the {@link HashCode} based on the data read from this stream. The result is 98 * unspecified if this method is called more than once on the same instance. 99 */ hash()100 public HashCode hash() { 101 return hasher.hash(); 102 } 103 } 104