diff src/org/tmatesoft/hg/internal/DigestHelper.java @ 74:6f1b88693d48

Complete refactoring to org.tmatesoft
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 24 Jan 2011 03:14:45 +0100
parents src/com/tmate/hgkit/ll/DigestHelper.java@92c3d0920d58
children a5275143664c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/internal/DigestHelper.java	Mon Jan 24 03:14:45 2011 +0100
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2010-2011 TMate Software Ltd
+ *  
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For information on how to redistribute this software under
+ * the terms of a license other than GNU General Public License
+ * contact TMate Software at support@svnkit.com
+ */
+package org.tmatesoft.hg.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.tmatesoft.hg.core.Nodeid;
+
+
+/**
+ * <pre>
+ * DigestHelper dh;
+ * dh.sha1(...).asHexString();
+ *  or 
+ * dh = dh.sha1(...);
+ * nodeid.equalsTo(dh.asBinary());
+ * </pre>
+ *
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class DigestHelper {
+	private MessageDigest sha1;
+	private byte[] digest;
+
+	public DigestHelper() {
+	}
+	
+	private MessageDigest getSHA1() {
+		if (sha1 == null) {
+			try {
+				sha1 = MessageDigest.getInstance("SHA-1");
+			} catch (NoSuchAlgorithmException ex) {
+				// could hardly happen, JDK from Sun always has sha1.
+				ex.printStackTrace(); // FIXME log error
+			}
+		}
+		return sha1;
+	}
+
+
+	public DigestHelper sha1(Nodeid nodeid1, Nodeid nodeid2, byte[] data) {
+		return sha1(nodeid1.toByteArray(), nodeid2.toByteArray(), data);
+	}
+
+	//  sha1_digest(min(p1,p2) ++ max(p1,p2) ++ final_text)
+	public DigestHelper sha1(byte[] nodeidParent1, byte[] nodeidParent2, byte[] data) {
+		MessageDigest alg = getSHA1();
+		if ((nodeidParent1[0] & 0x00FF) < (nodeidParent2[0] & 0x00FF)) { 
+			alg.update(nodeidParent1);
+			alg.update(nodeidParent2);
+		} else {
+			alg.update(nodeidParent2);
+			alg.update(nodeidParent1);
+		}
+		digest = alg.digest(data);
+		assert digest.length == 20;
+		return this;
+	}
+	
+	public String asHexString() {
+		if (digest == null) {
+			throw new IllegalStateException("Shall init with sha1() call first");
+		}
+		return toHexString(digest, 0, digest.length);
+	}
+	
+	// by reference, be careful not to modify (or #clone() if needed)
+	public byte[] asBinary() {
+		if (digest == null) {
+			throw new IllegalStateException("Shall init with sha1() call first");
+		}
+		return digest; 
+	}
+
+	// XXX perhaps, digest functions should throw an exception, as it's caller responsibility to deal with eof, etc
+	public DigestHelper sha1(InputStream is /*ByteBuffer*/) throws IOException {
+		MessageDigest alg = getSHA1();
+		byte[] buf = new byte[1024];
+		int c;
+		while ((c = is.read(buf)) != -1) {
+			alg.update(buf, 0, c);
+		}
+		digest = alg.digest();
+		return this;
+	}
+
+	public static String toHexString(byte[] data, final int offset, final int count) {
+		char[] result = new char[count << 1];
+		final String hexDigits = "0123456789abcdef";
+		final int end = offset+count;
+		for (int i = offset, j = 0; i < end; i++) {
+			result[j++] = hexDigits.charAt((data[i] >>> 4) & 0x0F);
+			result[j++] = hexDigits.charAt(data[i] & 0x0F);
+		}
+		return new String(result);
+	}
+}