Merge "SHA1: support reset() and reuse instances"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
index c530804..8642db7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
@@ -72,8 +72,13 @@ public void test0() throws NoSuchAlgorithmException {
 		s.update(new byte[] {});
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
+		s.reset();
+		s.update(new byte[] {});
+		ObjectId s2 = s.toObjectId();
+
 		assertEquals(m1, s1);
 		assertEquals(exp, s1);
+		assertEquals(exp, s2);
 	}
 
 	@Test
@@ -89,8 +94,13 @@ public void test1() throws NoSuchAlgorithmException {
 		s.update(TEST1.getBytes(StandardCharsets.UTF_8));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
+		s.reset();
+		s.update(TEST1.getBytes(StandardCharsets.UTF_8));
+		ObjectId s2 = s.toObjectId();
+
 		assertEquals(m1, s1);
 		assertEquals(exp, s1);
+		assertEquals(exp, s2);
 	}
 
 	@Test
@@ -106,7 +116,12 @@ public void test2() throws NoSuchAlgorithmException {
 		s.update(TEST2.getBytes(StandardCharsets.UTF_8));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
+		s.reset();
+		s.update(TEST2.getBytes(StandardCharsets.UTF_8));
+		ObjectId s2 = s.toObjectId();
+
 		assertEquals(m1, s1);
 		assertEquals(exp, s1);
+		assertEquals(exp, s2);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index d3ac626..fd72756 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -169,7 +169,7 @@ public ObjectId insert(int type, long len, InputStream in)
 		}
 
 		long offset = beginObject(type, len);
-		SHA1 md = SHA1.newInstance();
+		SHA1 md = digest();
 		md.update(Constants.encodedTypeString(type));
 		md.update((byte) ' ');
 		md.update(Constants.encodeASCII(len));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
index c37c4da..aa435bf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
@@ -140,7 +140,7 @@ ObjectId insert(int type, long len, InputStream is, boolean createDuplicate)
 			return insert(type, buf, 0, actLen, createDuplicate);
 
 		} else {
-			SHA1 md = SHA1.newInstance();
+			SHA1 md = digest();
 			File tmp = toTemp(md, type, len, is);
 			ObjectId id = md.toObjectId();
 			return insertOneObject(tmp, id, createDuplicate);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
index b39603a..ad0b333 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
@@ -177,6 +177,8 @@ public void close() {
 		}
 	}
 
+	private final SHA1 hasher = SHA1.newInstance();
+
 	/** Temporary working buffer for streaming data through. */
 	private byte[] tempBuffer;
 
@@ -217,7 +219,7 @@ protected ObjectInserter() {
 
 	/** @return digest to help compute an ObjectId */
 	protected SHA1 digest() {
-		return SHA1.newInstance();
+		return hasher.reset();
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 7d48f2a..c82b389 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -117,6 +117,7 @@ public static enum Source {
 
 	private byte[] hdrBuf;
 
+	private final SHA1 objectHasher = SHA1.newInstance();
 	private final MutableObjectId tempObjectId;
 
 	private InputStream in;
@@ -665,7 +666,7 @@ private void resolveDeltas(DeltaVisit visit, final int type,
 						JGitText.get().corruptionDetectedReReadingAt,
 						Long.valueOf(visit.delta.position)));
 
-			SHA1 objectDigest = SHA1.newInstance();
+			SHA1 objectDigest = objectHasher.reset();
 			objectDigest.update(Constants.encodedTypeString(type));
 			objectDigest.update((byte) ' ');
 			objectDigest.update(Constants.encodeASCII(visit.data.length));
@@ -1023,7 +1024,7 @@ private void indexOneObject() throws IOException {
 
 	private void whole(final long pos, final int type, final long sz)
 			throws IOException {
-		SHA1 objectDigest = SHA1.newInstance();
+		SHA1 objectDigest = objectHasher.reset();
 		objectDigest.update(Constants.encodedTypeString(type));
 		objectDigest.update((byte) ' ');
 		objectDigest.update(Constants.encodeASCII(sz));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
index 0a1dc10..293b4ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
@@ -63,12 +63,11 @@ public static SHA1 newInstance() {
 		return new SHA1();
 	}
 
-	// Magic initialization constants defined by FIPS180.
-	private int h0 = 0x67452301;
-	private int h1 = 0xEFCDAB89;
-	private int h2 = 0x98BADCFE;
-	private int h3 = 0x10325476;
-	private int h4 = 0xC3D2E1F0;
+	private int h0;
+	private int h1;
+	private int h2;
+	private int h3;
+	private int h4;
 	private final int[] w = new int[80];
 
 	/** Buffer to accumulate partial blocks to 64 byte alignment. */
@@ -78,6 +77,27 @@ public static SHA1 newInstance() {
 	private long length;
 
 	private SHA1() {
+		init();
+	}
+
+	/**
+	 * Reset this instance to compute another hash.
+	 *
+	 * @return {@code this}.
+	 */
+	public SHA1 reset() {
+		init();
+		length = 0;
+		return this;
+	}
+
+	private void init() {
+		// Magic initialization constants defined by FIPS180.
+		h0 = 0x67452301;
+		h1 = 0xEFCDAB89;
+		h2 = 0x98BADCFE;
+		h3 = 0x10325476;
+		h4 = 0xC3D2E1F0;
 	}
 
 	/**