001/** 002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC 003 * and GZip files. (http://jwat.org/) 004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.jwat.common; 019 020import java.security.MessageDigest; 021import java.security.NoSuchAlgorithmException; 022import java.util.Arrays; 023import java.util.Map; 024import java.util.TreeMap; 025import java.util.zip.CRC32; 026import java.util.zip.Checksum; 027 028/** 029 * This class represents a message digest including information about algorithm 030 * and encoding used. 031 * 032 * @author nicl 033 */ 034public class Digest { 035 036 /** Digest algorithm used. */ 037 public String algorithm; 038 039 /** Digest in bytes as returned by e.g. <code>MessageDigest</code>. */ 040 public byte[] digestBytes; 041 042 /** Digest string, encoded. */ 043 public String digestString; 044 045 /** Digest encoding used. (E.g. Base16, 32 or 64) */ 046 public String encoding; 047 048 /** Cache length of algorithm digest output. */ 049 protected static Map<String, Integer> digestAlgoLengthache = new TreeMap<String, Integer>(); 050 051 /** 052 * Returns the length of an algorithms digest output or -1 if it is an 053 * invalid digest algorithm. 054 * @param digestAlgorithm digest algorithm 055 * @return digest algorithm output length or -1 if invalid digest algorithm 056 */ 057 public static synchronized int digestAlgorithmLength(String digestAlgorithm) { 058 if (digestAlgorithm == null || digestAlgorithm.length() == 0) { 059 throw new IllegalArgumentException("'digestAlgorithm' is empty or null"); 060 } 061 Integer cachedLen = digestAlgoLengthache.get(digestAlgorithm); 062 if (cachedLen == null) { 063 try { 064 MessageDigest md = MessageDigest.getInstance(digestAlgorithm); 065 byte[] digest = md.digest(new byte[16]); 066 cachedLen = digest.length; 067 md.reset(); 068 } catch (NoSuchAlgorithmException e) { 069 } 070 if (cachedLen == null) { 071 cachedLen = -1; 072 } 073 digestAlgoLengthache.put(digestAlgorithm, cachedLen); 074 } 075 return cachedLen; 076 } 077 078 @Override 079 public boolean equals(Object obj) { 080 if (obj == null || !(obj instanceof Digest)) { 081 return false; 082 } 083 Digest digestObj = (Digest)obj; 084 if (!Arrays.equals(digestBytes, digestObj.digestBytes)) { 085 return false; 086 } 087 if (algorithm != null) { 088 if (!algorithm.equals(digestObj.algorithm)) { 089 return false; 090 } 091 } else if (digestObj.algorithm != null) { 092 return false; 093 } 094 if (digestString != null) { 095 if (!digestString.equals(digestObj.digestString)) { 096 return false; 097 } 098 } else if (digestObj.digestString != null) { 099 return false; 100 } 101 if (encoding != null) { 102 if (!encoding.equals(digestObj.encoding)) { 103 return false; 104 } 105 } else if (digestObj.encoding != null) { 106 return false; 107 } 108 return true; 109 } 110 111 @Override 112 public int hashCode() { 113 int hashCode = 0; 114 if (digestBytes != null) { 115 Checksum checksum = new CRC32(); 116 checksum.update(digestBytes, 0, digestBytes.length); 117 hashCode ^= checksum.getValue(); 118 } 119 if (algorithm != null) { 120 hashCode ^= algorithm.hashCode(); 121 } 122 if (digestString != null) { 123 hashCode ^= digestString.hashCode(); 124 } 125 if (encoding != null) { 126 hashCode ^= encoding.hashCode(); 127 } 128 return hashCode; 129 } 130 131}