package co.codewizards.cloudstore.core.util;
import co.codewizards.cloudstore.core.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
import co.codewizards.cloudstore.core.progress.NullProgressMonitor;
import co.codewizards.cloudstore.core.progress.ProgressMonitor;
public final class HashUtil {
/**
* Specifies usage of the MD5 algorithm in {@link #hash(String, InputStream)}.
*/
public static final String HASH_ALGORITHM_MD5 = "MD5";
/**
* Specifies usage of the SHA algorithm in {@link #hash(String, InputStream)}.
*/
public static final String HASH_ALGORITHM_SHA = "SHA";
private HashUtil() { }
public static String encodeHexStr(final byte[] buf)
{
return encodeHexStr(buf, 0, buf.length);
}
/**
* Encode a byte array into a human readable hex string. For each byte,
* two hex digits are produced. They are concatenated without any separators.
*
* @param buf The byte array to translate into human readable text.
* @param pos The start position (0-based).
* @param len The number of bytes that shall be processed beginning at the position specified by <code>pos</code>.
* @return a human readable string like "fa3d70" for a byte array with 3 bytes and these values.
* @see #encodeHexStr(byte[])
* @see #decodeHexStr(String)
*/
public static String encodeHexStr(final byte[] buf, int pos, int len)
{
final StringBuilder hex = new StringBuilder();
while (len-- > 0) {
final byte ch = buf[pos++];
int d = (ch >> 4) & 0xf;
hex.append((char)(d >= 10 ? 'a' - 10 + d : '0' + d));
d = ch & 0xf;
hex.append((char)(d >= 10 ? 'a' - 10 + d : '0' + d));
}
return hex.toString();
}
/**
* Decode a string containing two hex digits for each byte.
* @param hex The hex encoded string
* @return The byte array represented by the given hex string
* @see #encodeHexStr(byte[])
* @see #encodeHexStr(byte[], int, int)
*/
public static byte[] decodeHexStr(final String hex)
{
if (hex.length() % 2 != 0)
throw new IllegalArgumentException("The hex string must have an even number of characters!");
final byte[] res = new byte[hex.length() / 2];
int m = 0;
for (int i = 0; i < hex.length(); i += 2) {
res[m++] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
}
return res;
}
public static byte[] hash(final String algorithm, final InputStream in) throws NoSuchAlgorithmException, IOException {
return hash(algorithm, in, new NullProgressMonitor());
}
public static byte[] hash(final String algorithm, final InputStream in, final ProgressMonitor monitor) throws NoSuchAlgorithmException, IOException {
monitor.beginTask(algorithm, Math.max(1, in.available()));
try {
final MessageDigest md = MessageDigest.getInstance(algorithm);
final byte[] data = new byte[10240];
while (true) {
final int bytesRead = in.read(data, 0, data.length);
if (bytesRead < 0) {
break;
}
if (bytesRead > 0) {
md.update(data, 0, bytesRead);
monitor.worked(bytesRead);
}
}
return md.digest();
} finally {
monitor.done();
}
}
public static String formatEncodedHexStrForHuman(String hex) {
if (hex.length() % 2 != 0)
throw new IllegalArgumentException("The hex string must have an even number of characters!");
hex = hex.toUpperCase(Locale.UK);
final StringBuilder sb = new StringBuilder(hex.length() * 3 / 2);
for (int i = 0; i < hex.length(); i += 2) {
if (sb.length() > 0)
sb.append(':');
sb.append(hex.substring(i, i + 2));
}
return sb.toString();
}
public static String sha1ForHuman(final byte[] in) {
try {
return sha1ForHuman(new ByteArrayInputStream(in));
} catch (final IOException x) {
throw new RuntimeException(x);
}
}
public static String sha1ForHuman(final InputStream in) throws IOException {
return formatEncodedHexStrForHuman(sha1(in));
}
public static String sha1(final String in) {
try {
return sha1(in.getBytes(IOUtil.CHARSET_NAME_UTF_8));
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static String sha1(final byte[] in) {
try {
return sha1(new ByteArrayInputStream(in));
} catch (final IOException x) {
throw new RuntimeException(x);
}
}
public static String sha1(final InputStream in) throws IOException {
byte[] hash;
try {
hash = hash(HASH_ALGORITHM_SHA, in);
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return encodeHexStr(hash);
}
}