Home | History | Annotate | Download | only in hash
      1 /*
      2  * Copyright (C) 2011 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.FilterOutputStream;
     22 import java.io.IOException;
     23 import java.io.OutputStream;
     24 
     25 /**
     26  * An {@link OutputStream} that maintains a hash of the data written to it.
     27  *
     28  * @author Nick Piepmeier
     29  * @since 16.0
     30  */
     31 @Beta
     32 public final class HashingOutputStream extends FilterOutputStream {
     33   private final Hasher hasher;
     34 
     35   /**
     36    * Creates an output stream that hashes using the given {@link HashFunction}, and forwards all
     37    * data written to it to the underlying {@link OutputStream}.
     38    *
     39    * <p>The {@link OutputStream} should not be written to before or after the hand-off.
     40    */
     41   // TODO(user): Evaluate whether it makes sense to always piggyback the computation of a
     42   // HashCode on an existing OutputStream, compared to creating a separate OutputStream that could
     43   // be (optionally) be combined with another if needed (with something like
     44   // MultiplexingOutputStream).
     45   public HashingOutputStream(HashFunction hashFunction, OutputStream out) {
     46     super(checkNotNull(out));
     47     this.hasher = checkNotNull(hashFunction.newHasher());
     48   }
     49 
     50   @Override public void write(int b) throws IOException {
     51     hasher.putByte((byte) b);
     52     out.write(b);
     53   }
     54 
     55   @Override public void write(byte[] bytes, int off, int len) throws IOException {
     56     hasher.putBytes(bytes, off, len);
     57     out.write(bytes, off, len);
     58   }
     59 
     60   /**
     61    * Returns the {@link HashCode} based on the data written to this stream. The result is
     62    * unspecified if this method is called more than once on the same instance.
     63    */
     64   public HashCode hash() {
     65     return hasher.hash();
     66   }
     67 
     68   // Overriding close() because FilterOutputStream's close() method pre-JDK8 has bad behavior:
     69   // it silently ignores any exception thrown by flush(). Instead, just close the delegate stream.
     70   // It should flush itself if necessary.
     71   @Override public void close() throws IOException {
     72     out.close();
     73   }
     74 }
     75