10888a09821a98ac0680fad765217302858e70fa4Paul Duffin/*
20888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Copyright (C) 2013 The Guava Authors
30888a09821a98ac0680fad765217302858e70fa4Paul Duffin *
40888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
50888a09821a98ac0680fad765217302858e70fa4Paul Duffin * in compliance with the License. You may obtain a copy of the License at
60888a09821a98ac0680fad765217302858e70fa4Paul Duffin *
70888a09821a98ac0680fad765217302858e70fa4Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
80888a09821a98ac0680fad765217302858e70fa4Paul Duffin *
90888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Unless required by applicable law or agreed to in writing, software distributed under the License
100888a09821a98ac0680fad765217302858e70fa4Paul Duffin * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
110888a09821a98ac0680fad765217302858e70fa4Paul Duffin * or implied. See the License for the specific language governing permissions and limitations under
120888a09821a98ac0680fad765217302858e70fa4Paul Duffin * the License.
130888a09821a98ac0680fad765217302858e70fa4Paul Duffin */
140888a09821a98ac0680fad765217302858e70fa4Paul Duffin
150888a09821a98ac0680fad765217302858e70fa4Paul Duffinpackage com.google.common.hash;
160888a09821a98ac0680fad765217302858e70fa4Paul Duffin
170888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull;
180888a09821a98ac0680fad765217302858e70fa4Paul Duffin
190888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.annotations.Beta;
200888a09821a98ac0680fad765217302858e70fa4Paul Duffin
210888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.io.FilterInputStream;
220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.io.IOException;
230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.io.InputStream;
240888a09821a98ac0680fad765217302858e70fa4Paul Duffin
250888a09821a98ac0680fad765217302858e70fa4Paul Duffin/**
260888a09821a98ac0680fad765217302858e70fa4Paul Duffin * An {@link InputStream} that maintains a hash of the data read from it.
270888a09821a98ac0680fad765217302858e70fa4Paul Duffin *
280888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @author Qian Huang
290888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 16.0
300888a09821a98ac0680fad765217302858e70fa4Paul Duffin */
310888a09821a98ac0680fad765217302858e70fa4Paul Duffin@Beta
320888a09821a98ac0680fad765217302858e70fa4Paul Duffinpublic final class HashingInputStream extends FilterInputStream {
330888a09821a98ac0680fad765217302858e70fa4Paul Duffin  private final Hasher hasher;
340888a09821a98ac0680fad765217302858e70fa4Paul Duffin
350888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
360888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Creates an input stream that hashes using the given {@link HashFunction} and delegates all data
370888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * read from it to the underlying {@link InputStream}.
380888a09821a98ac0680fad765217302858e70fa4Paul Duffin   *
390888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * <p>The {@link InputStream} should not be read from before or after the hand-off.
400888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
410888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public HashingInputStream(HashFunction hashFunction, InputStream in) {
420888a09821a98ac0680fad765217302858e70fa4Paul Duffin    super(checkNotNull(in));
430888a09821a98ac0680fad765217302858e70fa4Paul Duffin    this.hasher = checkNotNull(hashFunction.newHasher());
440888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
450888a09821a98ac0680fad765217302858e70fa4Paul Duffin
460888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
470888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Reads the next byte of data from the underlying input stream and updates the hasher with
480888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * the byte read.
490888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
500888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override
510888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public int read() throws IOException {
520888a09821a98ac0680fad765217302858e70fa4Paul Duffin    int b = in.read();
530888a09821a98ac0680fad765217302858e70fa4Paul Duffin    if (b != -1) {
540888a09821a98ac0680fad765217302858e70fa4Paul Duffin      hasher.putByte((byte) b);
550888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
560888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return b;
570888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
580888a09821a98ac0680fad765217302858e70fa4Paul Duffin
590888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
600888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Reads the specified bytes of data from the underlying input stream and updates the hasher with
610888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * the bytes read.
620888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
630888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override
640888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public int read(byte[] bytes, int off, int len) throws IOException {
650888a09821a98ac0680fad765217302858e70fa4Paul Duffin    int numOfBytesRead = in.read(bytes, off, len);
660888a09821a98ac0680fad765217302858e70fa4Paul Duffin    if (numOfBytesRead != -1) {
670888a09821a98ac0680fad765217302858e70fa4Paul Duffin      hasher.putBytes(bytes, off, numOfBytesRead);
680888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
690888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return numOfBytesRead;
700888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
710888a09821a98ac0680fad765217302858e70fa4Paul Duffin
720888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
730888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * mark() is not supported for HashingInputStream
740888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * @return {@code false} always
750888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
760888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override
770888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public boolean markSupported() {
780888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return false;
790888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
800888a09821a98ac0680fad765217302858e70fa4Paul Duffin
810888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
820888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * mark() is not supported for HashingInputStream
830888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
840888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override
850888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void mark(int readlimit) {}
860888a09821a98ac0680fad765217302858e70fa4Paul Duffin
870888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
880888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * reset() is not supported for HashingInputStream.
890888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * @throws IOException this operation is not supported
900888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
910888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override
920888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void reset() throws IOException {
930888a09821a98ac0680fad765217302858e70fa4Paul Duffin    throw new IOException("reset not supported");
940888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
950888a09821a98ac0680fad765217302858e70fa4Paul Duffin
960888a09821a98ac0680fad765217302858e70fa4Paul Duffin  /**
970888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Returns the {@link HashCode} based on the data read from this stream. The result is
980888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * unspecified if this method is called more than once on the same instance.
990888a09821a98ac0680fad765217302858e70fa4Paul Duffin   */
1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public HashCode hash() {
1010888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return hasher.hash();
1020888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin}
104