View Javadoc
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  import com.google.errorprone.annotations.CanIgnoreReturnValue;
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 the
48     * byte read.
49     */
50    @Override
51    @CanIgnoreReturnValue
52    public int read() throws IOException {
53      int b = in.read();
54      if (b != -1) {
55        hasher.putByte((byte) b);
56      }
57      return b;
58    }
59  
60    /**
61     * Reads the specified bytes of data from the underlying input stream and updates the hasher with
62     * the bytes read.
63     */
64    @Override
65    @CanIgnoreReturnValue
66    public int read(byte[] bytes, int off, int len) throws IOException {
67      int numOfBytesRead = in.read(bytes, off, len);
68      if (numOfBytesRead != -1) {
69        hasher.putBytes(bytes, off, numOfBytesRead);
70      }
71      return numOfBytesRead;
72    }
73  
74    /**
75     * mark() is not supported for HashingInputStream
76     *
77     * @return {@code false} always
78     */
79    @Override
80    public boolean markSupported() {
81      return false;
82    }
83  
84    /**
85     * mark() is not supported for HashingInputStream
86     */
87    @Override
88    public void mark(int readlimit) {}
89  
90    /**
91     * reset() is not supported for HashingInputStream.
92     *
93     * @throws IOException this operation is not supported
94     */
95    @Override
96    public void reset() throws IOException {
97      throw new IOException("reset not supported");
98    }
99  
100   /**
101    * Returns the {@link HashCode} based on the data read from this stream. The result is unspecified
102    * if this method is called more than once on the same instance.
103    */
104   public HashCode hash() {
105     return hasher.hash();
106   }
107 }