ApplyCommand: support binary patches

Implement applying binary patches. Handles both literal and delta
patches. Note that C git also runs binary files through the clean
and smudge filters. Implement the same safeguards against corrupted
patches as in C git: require the full OIDs to be present in the patch
file, and apply a binary patch only if both pre- and post-image hashes
match.

Add tests for applying literal and delta patches.

Bug: 371725
Change-Id: I71dc214fe4145d7cc8e4769384fb78c7d0d6c220
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes
index c5831d9..28caa2f 100644
--- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes
@@ -1,3 +1,5 @@
 *.patch -crlf
 *Image -crlf
 *.out -crlf
+delta* -text
+literal* -text
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch
new file mode 100644
index 0000000..8485530
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch
@@ -0,0 +1,8 @@
+diff --git a/delta b/delta
+index b4527005bf9e4da2dd1d7185b51bdac623a4218f..8b370bb5f2bc3261b6b62e80d6edd784a61ec225 100644
+GIT binary patch
+delta 14
+ScmZp0Xmwa1z*+$U3j_csN(Dmz
+
+delta 12
+TcmZp5XmD5{u!xa=5hEi28?FP4
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage
new file mode 100644
index 0000000..8b370bb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage
new file mode 100644
index 0000000..b452700
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch
new file mode 100644
index 0000000..c8811d5
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch
@@ -0,0 +1,126 @@
+diff --git a/literal b/literal
+index 799df8578e3cae8a5e979182391b8e9a6a3deded..74e4201af6378ac87bf9e118fbab6553c7fd355c 100644
+GIT binary patch
+literal 5389
+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
+
+literal 1629
+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
+bU%LDkMDBWX&Ru`<00000NkvXXu0mjfJA@b~
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage
new file mode 100644
index 0000000..74e4201
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage
new file mode 100644
index 0000000..799df85
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch
new file mode 100644
index 0000000..bb6a9e4
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch
@@ -0,0 +1,40 @@
+diff --git a/literal_add b/literal_add
+new file mode 100644
+index 0000000000000000000000000000000000000000..799df8578e3cae8a5e979182391b8e9a6a3deded
+GIT binary patch
+literal 1629
+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
+bU%LDkMDBWX&Ru`<00000NkvXXu0mjfJA@b~
+
+literal 0
+HcmV?d00001
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage
new file mode 100644
index 0000000..799df85
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage
Binary files differ
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
index 335a64d..e9b8924 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -19,6 +20,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.Files;
 
 import org.eclipse.jgit.api.errors.PatchApplyException;
 import org.eclipse.jgit.api.errors.PatchFormatException;
@@ -29,6 +31,7 @@
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.util.IO;
 import org.junit.Test;
 
 public class ApplyCommandTest extends RepositoryTestCase {
@@ -246,6 +249,44 @@
 		}
 	}
 
+	private void checkBinary(String name, boolean hasPreImage)
+			throws Exception {
+		try (Git git = new Git(db)) {
+			byte[] post = IO
+					.readWholeStream(getTestResource(name + "_PostImage"), 0)
+					.array();
+			File f = new File(db.getWorkTree(), name);
+			if (hasPreImage) {
+				byte[] pre = IO
+						.readWholeStream(getTestResource(name + "_PreImage"), 0)
+						.array();
+				Files.write(f.toPath(), pre);
+				git.add().addFilepattern(name).call();
+				git.commit().setMessage("PreImage").call();
+			}
+			ApplyResult result = git.apply()
+					.setPatch(getTestResource(name + ".patch")).call();
+			assertEquals(1, result.getUpdatedFiles().size());
+			assertEquals(f, result.getUpdatedFiles().get(0));
+			assertArrayEquals(post, Files.readAllBytes(f.toPath()));
+		}
+	}
+
+	@Test
+	public void testBinaryDelta() throws Exception {
+		checkBinary("delta", true);
+	}
+
+	@Test
+	public void testBinaryLiteral() throws Exception {
+		checkBinary("literal", true);
+	}
+
+	@Test
+	public void testBinaryLiteralAdd() throws Exception {
+		checkBinary("literal_add", false);
+	}
+
 	@Test
 	public void testAddA1() throws Exception {
 		ApplyResult result = init("A1", false, true);
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 8b6872d..962324e 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -13,6 +13,9 @@
 aNewObjectIdIsRequired=A NewObjectId is required.
 anExceptionOccurredWhileTryingToAddTheIdOfHEAD=An exception occurred while trying to add the Id of HEAD
 anSSHSessionHasBeenAlreadyCreated=An SSH session has been already created
+applyBinaryBaseOidWrong=Cannot apply binary patch; OID for file {0} does not match
+applyBinaryOidTooShort=Binary patch for file {0} does not have full IDs
+applyBinaryResultOidWrong=Result of binary patch for file {0} has wrong OID.
 applyingCommit=Applying {0}
 archiveFormatAlreadyAbsent=Archive format already absent: {0}
 archiveFormatAlreadyRegistered=Archive format already registered with different implementation: {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
index 5d975ea..f7eba88 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
@@ -9,7 +9,9 @@
  */
 package org.eclipse.jgit.api;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -25,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.zip.InflaterInputStream;
 
 import org.eclipse.jgit.api.errors.FilterFailedException;
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -44,10 +47,13 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectStream;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.patch.BinaryHunk;
 import org.eclipse.jgit.patch.FileHeader;
+import org.eclipse.jgit.patch.FileHeader.PatchType;
 import org.eclipse.jgit.patch.HunkHeader;
 import org.eclipse.jgit.patch.Patch;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
@@ -57,14 +63,17 @@
 import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
 import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
 import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.TemporaryBuffer;
-import org.eclipse.jgit.util.FS.ExecutionResult;
 import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
+import org.eclipse.jgit.util.io.BinaryDeltaInputStream;
+import org.eclipse.jgit.util.io.BinaryHunkInputStream;
 import org.eclipse.jgit.util.io.EolStreamTypeUtil;
+import org.eclipse.jgit.util.sha1.SHA1;
 
 /**
  * Apply a patch to files and/or to the index.
@@ -191,6 +200,9 @@
 
 	private void apply(Repository repository, String path, DirCache cache,
 			File f, FileHeader fh) throws IOException, PatchApplyException {
+		if (PatchType.BINARY.equals(fh.getPatchType())) {
+			return;
+		}
 		boolean convertCrLf = needsCrLfConversion(f, fh);
 		// Use a TreeWalk with a DirCacheIterator to pick up the correct
 		// clean/smudge filters. CR-LF handling is completely determined by
@@ -217,16 +229,23 @@
 				FileTreeIterator file = walk.getTree(fileIdx,
 						FileTreeIterator.class);
 				if (file != null) {
-					command = walk
-							.getFilterCommand(Constants.ATTR_FILTER_TYPE_CLEAN);
-					RawText raw;
-					// Can't use file.openEntryStream() as it would do CR-LF
-					// conversion as usual, not as wanted by us.
-					try (InputStream input = filterClean(repository, path,
-							new FileInputStream(f), convertCrLf, command)) {
-						raw = new RawText(IO.readWholeStream(input, 0).array());
+					if (PatchType.GIT_BINARY.equals(fh.getPatchType())) {
+						applyBinary(repository, path, f, fh,
+								file::openEntryStream, file.getEntryObjectId(),
+								checkOut);
+					} else {
+						command = walk.getFilterCommand(
+								Constants.ATTR_FILTER_TYPE_CLEAN);
+						RawText raw;
+						// Can't use file.openEntryStream() as it would do CR-LF
+						// conversion as usual, not as wanted by us.
+						try (InputStream input = filterClean(repository, path,
+								new FileInputStream(f), convertCrLf, command)) {
+							raw = new RawText(
+									IO.readWholeStream(input, 0).array());
+						}
+						applyText(repository, path, raw, f, fh, checkOut);
 					}
-					apply(repository, path, raw, f, fh, checkOut);
 					return;
 				}
 			}
@@ -234,21 +253,30 @@
 		// File ignored?
 		RawText raw;
 		CheckoutMetadata checkOut;
-		if (convertCrLf) {
-			try (InputStream input = EolStreamTypeUtil.wrapInputStream(
-					new FileInputStream(f), EolStreamType.TEXT_LF)) {
-				raw = new RawText(IO.readWholeStream(input, 0).array());
-			}
-			checkOut = new CheckoutMetadata(EolStreamType.TEXT_CRLF, null);
-		} else {
-			raw = new RawText(f);
+		if (PatchType.GIT_BINARY.equals(fh.getPatchType())) {
 			checkOut = new CheckoutMetadata(EolStreamType.DIRECT, null);
+			applyBinary(repository, path, f, fh, () -> new FileInputStream(f),
+					null, checkOut);
+		} else {
+			if (convertCrLf) {
+				try (InputStream input = EolStreamTypeUtil.wrapInputStream(
+						new FileInputStream(f), EolStreamType.TEXT_LF)) {
+					raw = new RawText(IO.readWholeStream(input, 0).array());
+				}
+				checkOut = new CheckoutMetadata(EolStreamType.TEXT_CRLF, null);
+			} else {
+				raw = new RawText(f);
+				checkOut = new CheckoutMetadata(EolStreamType.DIRECT, null);
+			}
+			applyText(repository, path, raw, f, fh, checkOut);
 		}
-		apply(repository, path, raw, f, fh, checkOut);
 	}
 
 	private boolean needsCrLfConversion(File f, FileHeader fileHeader)
 			throws IOException {
+		if (PatchType.GIT_BINARY.equals(fileHeader.getPatchType())) {
+			return false;
+		}
 		if (!hasCrLf(fileHeader)) {
 			try (InputStream input = new FileInputStream(f)) {
 				return RawText.isCrLfText(input);
@@ -258,7 +286,7 @@
 	}
 
 	private static boolean hasCrLf(FileHeader fileHeader) {
-		if (fileHeader == null) {
+		if (PatchType.GIT_BINARY.equals(fileHeader.getPatchType())) {
 			return false;
 		}
 		for (HunkHeader header : fileHeader.getHunks()) {
@@ -331,18 +359,29 @@
 	}
 
 	/**
+	 * Something that can supply an {@link InputStream}.
+	 */
+	private interface StreamSupplier {
+		InputStream load() throws IOException;
+	}
+
+	/**
 	 * We write the patch result to a {@link TemporaryBuffer} and then use
 	 * {@link DirCacheCheckout}.getContent() to run the result through the CR-LF
 	 * and smudge filters. DirCacheCheckout needs an ObjectLoader, not a
-	 * TemporaryBuffer, so this class bridges between the two, making the
-	 * TemporaryBuffer look like an ordinary git blob to DirCacheCheckout.
+	 * TemporaryBuffer, so this class bridges between the two, making any Stream
+	 * provided by a {@link StreamSupplier} look like an ordinary git blob to
+	 * DirCacheCheckout.
 	 */
-	private static class BufferLoader extends ObjectLoader {
+	private static class StreamLoader extends ObjectLoader {
 
-		private TemporaryBuffer data;
+		private StreamSupplier data;
 
-		BufferLoader(TemporaryBuffer data) {
+		private long size;
+
+		StreamLoader(StreamSupplier data, long length) {
 			this.data = data;
+			this.size = length;
 		}
 
 		@Override
@@ -352,7 +391,7 @@
 
 		@Override
 		public long getSize() {
-			return data.length();
+			return size;
 		}
 
 		@Override
@@ -369,12 +408,146 @@
 		public ObjectStream openStream()
 				throws MissingObjectException, IOException {
 			return new ObjectStream.Filter(getType(), getSize(),
-					data.openInputStream());
+					new BufferedInputStream(data.load()));
 		}
 	}
 
-	private void apply(Repository repository, String path, RawText rt, File f,
-			FileHeader fh, CheckoutMetadata checkOut)
+	private void initHash(SHA1 hash, long size) {
+		hash.update(Constants.encodedTypeString(Constants.OBJ_BLOB));
+		hash.update((byte) ' ');
+		hash.update(Constants.encodeASCII(size));
+		hash.update((byte) 0);
+	}
+
+	private ObjectId hash(File f) throws IOException {
+		SHA1 hash = SHA1.newInstance();
+		initHash(hash, f.length());
+		try (InputStream input = new FileInputStream(f)) {
+			byte[] buf = new byte[8192];
+			int n;
+			while ((n = input.read(buf)) >= 0) {
+				hash.update(buf, 0, n);
+			}
+		}
+		return hash.toObjectId();
+	}
+
+	private void checkOid(ObjectId baseId, ObjectId id, ChangeType type, File f,
+			String path)
+			throws PatchApplyException, IOException {
+		boolean hashOk = false;
+		if (id != null) {
+			hashOk = baseId.equals(id);
+			if (!hashOk && ChangeType.ADD.equals(type)
+					&& ObjectId.zeroId().equals(baseId)) {
+				// We create the file first. The OID of an empty file is not the
+				// zero id!
+				hashOk = Constants.EMPTY_BLOB_ID.equals(id);
+			}
+		} else {
+			if (ObjectId.zeroId().equals(baseId)) {
+				// File empty is OK.
+				hashOk = !f.exists() || f.length() == 0;
+			} else {
+				hashOk = baseId.equals(hash(f));
+			}
+		}
+		if (!hashOk) {
+			throw new PatchApplyException(MessageFormat
+					.format(JGitText.get().applyBinaryBaseOidWrong, path));
+		}
+	}
+
+	private void applyBinary(Repository repository, String path, File f,
+			FileHeader fh, StreamSupplier loader, ObjectId id,
+			CheckoutMetadata checkOut)
+			throws PatchApplyException, IOException {
+		if (!fh.getOldId().isComplete() || !fh.getNewId().isComplete()) {
+			throw new PatchApplyException(MessageFormat
+					.format(JGitText.get().applyBinaryOidTooShort, path));
+		}
+		BinaryHunk hunk = fh.getForwardBinaryHunk();
+		// A BinaryHunk has the start at the "literal" or "delta" token. Data
+		// starts on the next line.
+		int start = RawParseUtils.nextLF(hunk.getBuffer(),
+				hunk.getStartOffset());
+		int length = hunk.getEndOffset() - start;
+		SHA1 hash = SHA1.newInstance();
+		// Write to a buffer and copy to the file only if everything was fine
+		TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(null);
+		try {
+			switch (hunk.getType()) {
+			case LITERAL_DEFLATED:
+				// This just overwrites the file. We need to check the hash of
+				// the base.
+				checkOid(fh.getOldId().toObjectId(), id, fh.getChangeType(), f,
+						path);
+				initHash(hash, hunk.getSize());
+				try (OutputStream out = buffer;
+						InputStream inflated = new SHA1InputStream(hash,
+								new InflaterInputStream(
+										new BinaryHunkInputStream(
+												new ByteArrayInputStream(
+														hunk.getBuffer(), start,
+														length))))) {
+					DirCacheCheckout.getContent(repository, path, checkOut,
+							new StreamLoader(() -> inflated, hunk.getSize()),
+							null, out);
+					if (!fh.getNewId().toObjectId().equals(hash.toObjectId())) {
+						throw new PatchApplyException(MessageFormat.format(
+								JGitText.get().applyBinaryResultOidWrong,
+								path));
+					}
+				}
+				try (InputStream bufIn = buffer.openInputStream()) {
+					Files.copy(bufIn, f.toPath(),
+							StandardCopyOption.REPLACE_EXISTING);
+				}
+				break;
+			case DELTA_DEFLATED:
+				// Unfortunately delta application needs random access to the
+				// base to construct the result.
+				byte[] base;
+				try (InputStream input = loader.load()) {
+					base = IO.readWholeStream(input, 0).array();
+				}
+				// At least stream the result!
+				try (BinaryDeltaInputStream input = new BinaryDeltaInputStream(
+						base,
+						new InflaterInputStream(new BinaryHunkInputStream(
+								new ByteArrayInputStream(hunk.getBuffer(),
+										start, length))))) {
+					long finalSize = input.getExpectedResultSize();
+					initHash(hash, finalSize);
+					try (OutputStream out = buffer;
+							SHA1InputStream hashed = new SHA1InputStream(hash,
+									input)) {
+						DirCacheCheckout.getContent(repository, path, checkOut,
+								new StreamLoader(() -> hashed, finalSize), null,
+								out);
+						if (!fh.getNewId().toObjectId()
+								.equals(hash.toObjectId())) {
+							throw new PatchApplyException(MessageFormat.format(
+									JGitText.get().applyBinaryResultOidWrong,
+									path));
+						}
+					}
+				}
+				try (InputStream bufIn = buffer.openInputStream()) {
+					Files.copy(bufIn, f.toPath(),
+							StandardCopyOption.REPLACE_EXISTING);
+				}
+				break;
+			default:
+				break;
+			}
+		} finally {
+			buffer.destroy();
+		}
+	}
+
+	private void applyText(Repository repository, String path, RawText rt,
+			File f, FileHeader fh, CheckoutMetadata checkOut)
 			throws IOException, PatchApplyException {
 		List<String> oldLines = new ArrayList<>(rt.size());
 		for (int i = 0; i < rt.size(); i++) {
@@ -514,7 +687,9 @@
 			}
 			try (OutputStream output = new FileOutputStream(f)) {
 				DirCacheCheckout.getContent(repository, path, checkOut,
-						new BufferLoader(buffer), null, output);
+						new StreamLoader(buffer::openInputStream,
+								buffer.length()),
+						null, output);
 			}
 		} finally {
 			buffer.destroy();
@@ -565,4 +740,43 @@
 		return lhrt.getString(lhrt.size() - 1)
 				.equals("\\ No newline at end of file"); //$NON-NLS-1$
 	}
+
+	/**
+	 * An {@link InputStream} that updates a {@link SHA1} on every byte read.
+	 * The hash is supposed to have been initialized before reading starts.
+	 */
+	private static class SHA1InputStream extends InputStream {
+
+		private final SHA1 hash;
+
+		private final InputStream in;
+
+		SHA1InputStream(SHA1 hash, InputStream in) {
+			this.hash = hash;
+			this.in = in;
+		}
+
+		@Override
+		public int read() throws IOException {
+			int b = in.read();
+			if (b >= 0) {
+				hash.update((byte) b);
+			}
+			return b;
+		}
+
+		@Override
+		public int read(byte[] b, int off, int len) throws IOException {
+			int n = in.read(b, off, len);
+			if (n > 0) {
+				hash.update(b, off, n);
+			}
+			return n;
+		}
+
+		@Override
+		public void close() throws IOException {
+			in.close();
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 3b67b0f..fd54986 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -41,6 +41,9 @@
 	/***/ public String aNewObjectIdIsRequired;
 	/***/ public String anExceptionOccurredWhileTryingToAddTheIdOfHEAD;
 	/***/ public String anSSHSessionHasBeenAlreadyCreated;
+	/***/ public String applyBinaryBaseOidWrong;
+	/***/ public String applyBinaryOidTooShort;
+	/***/ public String applyBinaryResultOidWrong;
 	/***/ public String applyingCommit;
 	/***/ public String archiveFormatAlreadyAbsent;
 	/***/ public String archiveFormatAlreadyRegistered;