Home | History | Annotate | Download | only in hash
      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    */
     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
     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
     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
     77   public boolean markSupported() {
     78     return false;
     79   }
     80 
     81   /**
     82    * mark() is not supported for HashingInputStream
     83    */
     84   @Override
     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
     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    */
    100   public HashCode hash() {
    101     return hasher.hash();
    102   }
    103 }
    104