PacketLineIn, PacketLineOut: Add support for delim-pkt

Most pkt-lines (data-pkts) have the form

	pkt-len pkt-payload

where pkt-len is a string of 4 hexadecimal digits representing the
size in bytes of the pkt-line.  Since this size includes the size of
the pkt-len, no data-pkt has a length less than 4.

A pkt-line with a length field less than 4 can thus be used for
other purposes.  In Git protocol v1, the only such pkt-line was

	flush-pkt = "0000"

which was used to mark the end of a stream.  Protocol v2 (see
Documentation/technical/protocol-v2.txt in git.git) introduces a
second special pkt-line type:

	delim-pkt = "0001"

used to mark the end of a section within a stream, for example to
separate capabilities from the content of a command.

[jn: split out from a larger patch that made use of this support]

Change-Id: I10e7824fa24ed74c4f45624bd490bba978cf5c34
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Jonathan Nieder <jrn@google.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
index 13fc68d..982bae8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
@@ -116,17 +116,6 @@
 	}
 
 	@Test
-	public void testReadString_Len0001() {
-		init("0001");
-		try {
-			in.readString();
-			fail("incorrectly accepted invalid packet header");
-		} catch (IOException e) {
-			assertEquals("Invalid packet line header: 0001", e.getMessage());
-		}
-	}
-
-	@Test
 	public void testReadString_Len0002() {
 		init("0002");
 		try {
@@ -164,6 +153,13 @@
 		assertEOF();
 	}
 
+	@Test
+	public void testReadString_Delim() throws IOException {
+		init("0001");
+		assertSame(PacketLineIn.DELIM, in.readString());
+		assertEOF();
+	}
+
 	// readStringNoLF
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
index eca5475..dd9a0d3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
@@ -113,6 +113,12 @@
 		assertEquals(1, flushCnt[0]);
 	}
 
+	@Test
+	public void testWriteDelim() throws IOException {
+		out.writeDelim();
+		assertBuffer("0001");
+	}
+
 	// writePacket
 
 	@Test
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
index 87064e1..f64c8ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -74,6 +74,13 @@
 	/** Magic return from {@link #readString()} when a flush packet is found. */
 	public static final String END = new StringBuilder(0).toString(); 	/* must not string pool */
 
+	/**
+	 * Magic return from {@link #readString()} when a delim packet is found.
+	 *
+	 * @since 5.0
+	 */
+	public static final String DELIM = new StringBuilder(0).toString(); 	/* must not string pool */
+
 	static enum AckNackResult {
 		/** NAK */
 		NAK,
@@ -147,6 +154,7 @@
 	 * use {@link #readStringRaw()} instead.
 	 *
 	 * @return the string. {@link #END} if the string was the magic flush
+	 *         packet, {@link #DELIM} if the string was the magic DELIM
 	 *         packet.
 	 * @throws java.io.IOException
 	 *             the stream cannot be read.
@@ -157,6 +165,10 @@
 			log.debug("git< 0000"); //$NON-NLS-1$
 			return END;
 		}
+		if (len == 1) {
+			log.debug("git< 0001"); //$NON-NLS-1$
+			return DELIM;
+		}
 
 		len -= 4; // length header (4 bytes)
 		if (len == 0) {
@@ -232,6 +244,8 @@
 
 		if (len == 0) {
 			return 0;
+		} else if (len == 1) {
+			return 1;
 		} else if (len < 4) {
 			throw invalidHeader();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
index 48bdd01..0cb3b0f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
@@ -147,6 +147,20 @@
 	}
 
 	/**
+	 * Write a packet delim marker (0001).
+	 *
+	 * @throws java.io.IOException
+	 *             the marker could not be written, the stream is corrupted
+	 *             as the marker may have been only partially written.
+	 * @since 5.0
+	 */
+	public void writeDelim() throws IOException {
+		formatLength(1);
+		out.write(lenbuffer, 0, 4);
+		log.debug("git> 0001"); //$NON-NLS-1$
+	}
+
+	/**
 	 * Write a packet end marker, sometimes referred to as a flush command.
 	 * <p>
 	 * Technically this is a magical packet type which can be detected