Coverage Summary for Class: MessageDigestHashFunction (com.google.common.hash)

Class Method, % Line, %
MessageDigestHashFunction 0% (0/8) 0% (0/26)
MessageDigestHashFunction$MessageDigestHasher 0% (0/7) 0% (0/16)
MessageDigestHashFunction$SerializedForm 0% (0/3) 0% (0/6)
Total 0% (0/18) 0% (0/48)


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.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkState; 20  21 import com.google.errorprone.annotations.Immutable; 22 import java.io.Serializable; 23 import java.nio.ByteBuffer; 24 import java.security.MessageDigest; 25 import java.security.NoSuchAlgorithmException; 26 import java.util.Arrays; 27  28 /** 29  * {@link HashFunction} adapter for {@link MessageDigest} instances. 30  * 31  * @author Kevin Bourrillion 32  * @author Dimitris Andreou 33  */ 34 @Immutable 35 @ElementTypesAreNonnullByDefault 36 final class MessageDigestHashFunction extends AbstractHashFunction implements Serializable { 37  38  @SuppressWarnings("Immutable") // cloned before each use 39  private final MessageDigest prototype; 40  41  private final int bytes; 42  private final boolean supportsClone; 43  private final String toString; 44  45  MessageDigestHashFunction(String algorithmName, String toString) { 46  this.prototype = getMessageDigest(algorithmName); 47  this.bytes = prototype.getDigestLength(); 48  this.toString = checkNotNull(toString); 49  this.supportsClone = supportsClone(prototype); 50  } 51  52  MessageDigestHashFunction(String algorithmName, int bytes, String toString) { 53  this.toString = checkNotNull(toString); 54  this.prototype = getMessageDigest(algorithmName); 55  int maxLength = prototype.getDigestLength(); 56  checkArgument( 57  bytes >= 4 && bytes <= maxLength, "bytes (%s) must be >= 4 and < %s", bytes, maxLength); 58  this.bytes = bytes; 59  this.supportsClone = supportsClone(prototype); 60  } 61  62  private static boolean supportsClone(MessageDigest digest) { 63  try { 64  digest.clone(); 65  return true; 66  } catch (CloneNotSupportedException e) { 67  return false; 68  } 69  } 70  71  @Override 72  public int bits() { 73  return bytes * Byte.SIZE; 74  } 75  76  @Override 77  public String toString() { 78  return toString; 79  } 80  81  private static MessageDigest getMessageDigest(String algorithmName) { 82  try { 83  return MessageDigest.getInstance(algorithmName); 84  } catch (NoSuchAlgorithmException e) { 85  throw new AssertionError(e); 86  } 87  } 88  89  @Override 90  public Hasher newHasher() { 91  if (supportsClone) { 92  try { 93  return new MessageDigestHasher((MessageDigest) prototype.clone(), bytes); 94  } catch (CloneNotSupportedException e) { 95  // falls through 96  } 97  } 98  return new MessageDigestHasher(getMessageDigest(prototype.getAlgorithm()), bytes); 99  } 100  101  private static final class SerializedForm implements Serializable { 102  private final String algorithmName; 103  private final int bytes; 104  private final String toString; 105  106  private SerializedForm(String algorithmName, int bytes, String toString) { 107  this.algorithmName = algorithmName; 108  this.bytes = bytes; 109  this.toString = toString; 110  } 111  112  private Object readResolve() { 113  return new MessageDigestHashFunction(algorithmName, bytes, toString); 114  } 115  116  private static final long serialVersionUID = 0; 117  } 118  119  Object writeReplace() { 120  return new SerializedForm(prototype.getAlgorithm(), bytes, toString); 121  } 122  123  /** Hasher that updates a message digest. */ 124  private static final class MessageDigestHasher extends AbstractByteHasher { 125  private final MessageDigest digest; 126  private final int bytes; 127  private boolean done; 128  129  private MessageDigestHasher(MessageDigest digest, int bytes) { 130  this.digest = digest; 131  this.bytes = bytes; 132  } 133  134  @Override 135  protected void update(byte b) { 136  checkNotDone(); 137  digest.update(b); 138  } 139  140  @Override 141  protected void update(byte[] b, int off, int len) { 142  checkNotDone(); 143  digest.update(b, off, len); 144  } 145  146  @Override 147  protected void update(ByteBuffer bytes) { 148  checkNotDone(); 149  digest.update(bytes); 150  } 151  152  private void checkNotDone() { 153  checkState(!done, "Cannot re-use a Hasher after calling hash() on it"); 154  } 155  156  @Override 157  public HashCode hash() { 158  checkNotDone(); 159  done = true; 160  return (bytes == digest.getDigestLength()) 161  ? HashCode.fromBytesNoCopy(digest.digest()) 162  : HashCode.fromBytesNoCopy(Arrays.copyOf(digest.digest(), bytes)); 163  } 164  } 165 }