diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java index 574f85c91..beda2a7b9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java @@ -383,6 +383,19 @@ public void testParse_PublicParseMethod() assertEquals(src.getMessage(), p.getFullMessage()); } + @Test + public void testParse_GitStyleMessageWithCRLF() throws Exception { + final String shortMsgIn = "This fixes a\r\nbug.\r\n\r\n"; + final String shortMsg = "This fixes a bug."; + final String body = "We do it with magic and pixie dust\r\nand stuff.\r\n" + + "\r\n\r\n" + + "Signed-off-by: A U. Thor \r\n"; + final String fullMsg = shortMsgIn + "\r\n" + "\r\n" + body; + final RevCommit c = create(fullMsg); + assertEquals(fullMsg, c.getFullMessage()); + assertEquals(shortMsg, c.getShortMessage()); + } + private static ObjectId id(final String str) { return ObjectId.fromString(str); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java index d7b92ade9..86fed22af 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java @@ -91,4 +91,16 @@ public void testEqualsIgnoreCase4() { assertTrue(StringUtils.equalsIgnoreCase("A", "a")); assertTrue(StringUtils.equalsIgnoreCase("a", "A")); } + + @Test + public void testReplaceLineBreaks() { + assertEquals("a b c ", + StringUtils.replaceLineBreaksWithSpace("a b\nc\r")); + assertEquals("a b c ", + StringUtils.replaceLineBreaksWithSpace("a b\nc\n")); + assertEquals("a b c ", + StringUtils.replaceLineBreaksWithSpace("a b\nc\r\n")); + assertEquals("a b c d", + StringUtils.replaceLineBreaksWithSpace("a\r\nb\nc d")); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java index 9f2ccfd97..93d28aaf5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java @@ -59,6 +59,7 @@ import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.StringUtils; /** A commit reference to a commit in the DAG. */ public class RevCommit extends RevObject { @@ -421,7 +422,7 @@ public final String getShortMessage() { final int msgE = RawParseUtils.endOfParagraph(raw, msgB); String str = RawParseUtils.decode(enc, raw, msgB, msgE); if (hasLF(raw, msgB, msgE)) - str = str.replace('\n', ' '); + str = StringUtils.replaceLineBreaksWithSpace(str); return str; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java index 12693a03e..1a59b440c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java @@ -58,6 +58,7 @@ import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.util.MutableInteger; import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.StringUtils; /** An annotated tag. */ public class RevTag extends RevObject { @@ -234,7 +235,7 @@ public final String getShortMessage() { final int msgE = RawParseUtils.endOfParagraph(raw, msgB); String str = RawParseUtils.decode(enc, raw, msgB, msgE); if (RevCommit.hasLF(raw, msgB, msgE)) - str = str.replace('\n', ' '); + str = StringUtils.replaceLineBreaksWithSpace(str); return str; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java index 9114d500e..2f9a6d12c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java @@ -1058,7 +1058,7 @@ public static final int tagMessage(final byte[] b, int ptr) { /** * Locate the end of a paragraph. *

- * A paragraph is ended by two consecutive LF bytes. + * A paragraph is ended by two consecutive LF bytes or CRLF pairs * * @param b * buffer to scan. @@ -1072,9 +1072,11 @@ public static final int tagMessage(final byte[] b, int ptr) { public static final int endOfParagraph(final byte[] b, final int start) { int ptr = start; final int sz = b.length; - while (ptr < sz && b[ptr] != '\n') + while (ptr < sz && (b[ptr] != '\n' && b[ptr] != '\r')) ptr = nextLF(b, ptr); - while (0 < ptr && start < ptr && b[ptr - 1] == '\n') + if (ptr > start && b[ptr - 1] == '\n') + ptr--; + if (ptr > start && b[ptr - 1] == '\r') ptr--; return ptr; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java index cb4895025..bfefc50c3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java @@ -279,4 +279,30 @@ private StringUtils() { public static boolean isEmptyOrNull(String stringValue) { return stringValue == null || stringValue.length() == 0; } + + /** + * Replace CRLF, CR or LF with a single space. + * + * @param in + * A string with line breaks + * @return in without line breaks + */ + public static String replaceLineBreaksWithSpace(String in) { + char[] buf = new char[in.length()]; + int o = 0; + for (int i = 0; i < buf.length; ++i) { + char ch = in.charAt(i); + if (ch == '\r') { + if (i + 1 < buf.length && in.charAt(i + 1) == '\n') { + buf[o++] = ' '; + ++i; + } else + buf[o++] = ' '; + } else if (ch == '\n') + buf[o++] = ' '; + else + buf[o++] = ch; + } + return new String(buf, 0, o); + } }