This way we can reuse them beyond just the ObjectId family of classes. We also now accept upper case hex digits in object ids. Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx> --- .../tst/org/spearce/jgit/lib/T0001_ObjectId.java | 10 ++- .../org/spearce/jgit/lib/AbbreviatedObjectId.java | 8 +- .../src/org/spearce/jgit/lib/AnyObjectId.java | 36 --------- .../src/org/spearce/jgit/lib/MutableObjectId.java | 11 ++- .../src/org/spearce/jgit/lib/ObjectId.java | 19 +++-- .../src/org/spearce/jgit/util/RawParseUtils.java | 80 ++++++++++++++++++-- 6 files changed, 101 insertions(+), 63 deletions(-) diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0001_ObjectId.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0001_ObjectId.java index 4c03667..7a53925 100644 --- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0001_ObjectId.java +++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0001_ObjectId.java @@ -74,8 +74,8 @@ assertFalse("39 digits is not an id", ObjectId .isId("def4c620bc3713bb1bb26b808ec9312548e7394")); } - public void test007_notIsId() { - assertFalse("uppercase is not accepted", ObjectId + public void test007_isId() { + assertTrue("uppercase is accepted", ObjectId .isId("Def4c620bc3713bb1bb26b808ec9312548e73946")); } @@ -94,4 +94,10 @@ public void test010_toString() { final String x = "0000000000000000000000000000000000000000"; assertEquals(x, ObjectId.toString(null)); } + + public void test011_toString() { + final String x = "0123456789ABCDEFabcdef1234567890abcdefAB"; + final ObjectId oid = ObjectId.fromString(x); + assertEquals(x.toLowerCase(), oid.name()); + } } diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java index ed03fb5..1706e88 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java @@ -40,6 +40,7 @@ import java.io.UnsupportedEncodingException; import org.spearce.jgit.util.NB; +import org.spearce.jgit.util.RawParseUtils; /** * A prefix abbreviation of an {@link ObjectId}. @@ -107,15 +108,12 @@ private static final AbbreviatedObjectId fromHexString(final byte[] bs, private static final int hexUInt32(final byte[] bs, int p, final int end) { if (8 <= end - p) - return AnyObjectId.hexUInt32(bs, p); + return RawParseUtils.parseHexInt32(bs, p); int r = 0, n = 0; while (n < 8 && p < end) { - final int v = AnyObjectId.fromhex[bs[p++]]; - if (v < 0) - throw new ArrayIndexOutOfBoundsException(); r <<= 4; - r |= v; + r |= RawParseUtils.parseHexInt4(bs[p++]); n++; } return r << (8 - n) * 4; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java index acb3cb5..0df2768 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java @@ -41,7 +41,6 @@ import java.io.OutputStream; import java.io.Writer; import java.nio.ByteBuffer; -import java.util.Arrays; import org.spearce.jgit.util.NB; @@ -57,16 +56,7 @@ static final int STR_LEN = RAW_LEN * 2; - static final byte fromhex[]; - static { - fromhex = new byte['f' + 1]; - Arrays.fill(fromhex, (byte) -1); - for (char i = '0'; i <= '9'; i++) - fromhex[i] = (byte) (i - '0'); - for (char i = 'a'; i <= 'f'; i++) - fromhex[i] = (byte) ((i - 'a') + 10); - if (RAW_LEN != 20) throw new LinkageError("ObjectId expects" + " Constants.OBJECT_ID_LENGTH = 20; it is " + RAW_LEN @@ -100,32 +90,6 @@ public static boolean equals(final AnyObjectId firstObjectId, && firstObjectId.w1 == secondObjectId.w1; } - static final int hexUInt32(final byte[] bs, final int p) { - int r = fromhex[bs[p]] << 4; - - r |= fromhex[bs[p + 1]]; - r <<= 4; - - r |= fromhex[bs[p + 2]]; - r <<= 4; - - r |= fromhex[bs[p + 3]]; - r <<= 4; - - r |= fromhex[bs[p + 4]]; - r <<= 4; - - r |= fromhex[bs[p + 5]]; - r <<= 4; - - r |= fromhex[bs[p + 6]]; - - final int last = fromhex[bs[p + 7]]; - if (r < 0 || last < 0) - throw new ArrayIndexOutOfBoundsException(); - return (r << 4) | last; - } - int w1; int w2; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java index fadebab..805f328 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java @@ -40,6 +40,7 @@ import java.io.UnsupportedEncodingException; import org.spearce.jgit.util.NB; +import org.spearce.jgit.util.RawParseUtils; /** * A mutable SHA-1 abstraction. @@ -159,11 +160,11 @@ public void fromString(final String str) { private void fromHexString(final byte[] bs, int p) { try { - w1 = hexUInt32(bs, p); - w2 = hexUInt32(bs, p + 8); - w3 = hexUInt32(bs, p + 16); - w4 = hexUInt32(bs, p + 24); - w5 = hexUInt32(bs, p + 32); + w1 = RawParseUtils.parseHexInt32(bs, p); + w2 = RawParseUtils.parseHexInt32(bs, p + 8); + w3 = RawParseUtils.parseHexInt32(bs, p + 16); + w4 = RawParseUtils.parseHexInt32(bs, p + 24); + w5 = RawParseUtils.parseHexInt32(bs, p + 32); } catch (ArrayIndexOutOfBoundsException e1) { try { final String str = new String(bs, p, STR_LEN, "US-ASCII"); diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java index fde209b..cdd523f 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java @@ -41,6 +41,7 @@ import java.io.UnsupportedEncodingException; import org.spearce.jgit.util.NB; +import org.spearce.jgit.util.RawParseUtils; /** * A SHA-1 abstraction. @@ -74,12 +75,12 @@ public static final ObjectId zeroId() { * @return true if the string can converted into an ObjectId. */ public static final boolean isId(final String id) { - if (id.length() != 2 * Constants.OBJECT_ID_LENGTH) + if (id.length() != STR_LEN) return false; try { - for (int k = id.length() - 1; k >= 0; k--) - if (fromhex[id.charAt(k)] < 0) - return false; + for (int i = 0; i < STR_LEN; i++) { + RawParseUtils.parseHexInt4((byte) id.charAt(i)); + } return true; } catch (ArrayIndexOutOfBoundsException e) { return false; @@ -222,11 +223,11 @@ public static final ObjectId fromString(final String str) { private static final ObjectId fromHexString(final byte[] bs, int p) { try { - final int a = hexUInt32(bs, p); - final int b = hexUInt32(bs, p + 8); - final int c = hexUInt32(bs, p + 16); - final int d = hexUInt32(bs, p + 24); - final int e = hexUInt32(bs, p + 32); + final int a = RawParseUtils.parseHexInt32(bs, p); + final int b = RawParseUtils.parseHexInt32(bs, p + 8); + final int c = RawParseUtils.parseHexInt32(bs, p + 16); + final int d = RawParseUtils.parseHexInt32(bs, p + 24); + final int e = RawParseUtils.parseHexInt32(bs, p + 32); return new ObjectId(a, b, c, d, e); } catch (ArrayIndexOutOfBoundsException e1) { try { diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java index 79ebe41..0554acb 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java +++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java @@ -54,13 +54,24 @@ /** Handy utility functions to parse raw object contents. */ public final class RawParseUtils { - private static final byte[] digits; + private static final byte[] digits10; + + private static final byte[] digits16; static { - digits = new byte['9' + 1]; - Arrays.fill(digits, (byte) -1); + digits10 = new byte['9' + 1]; + Arrays.fill(digits10, (byte) -1); + for (char i = '0'; i <= '9'; i++) + digits10[i] = (byte) (i - '0'); + + digits16 = new byte['f' + 1]; + Arrays.fill(digits16, (byte) -1); for (char i = '0'; i <= '9'; i++) - digits[i] = (byte) (i - '0'); + digits16[i] = (byte) (i - '0'); + for (char i = 'a'; i <= 'f'; i++) + digits16[i] = (byte) ((i - 'a') + 10); + for (char i = 'A'; i <= 'F'; i++) + digits16[i] = (byte) ((i - 'A') + 10); } /** @@ -175,7 +186,7 @@ public static final int parseBase10(final byte[] b, int ptr, } while (ptr < sz) { - final byte v = digits[b[ptr]]; + final byte v = digits10[b[ptr]]; if (v < 0) break; r = (r * 10) + v; @@ -229,7 +240,7 @@ public static final long parseLongBase10(final byte[] b, int ptr, } while (ptr < sz) { - final byte v = digits[b[ptr]]; + final byte v = digits10[b[ptr]]; if (v < 0) break; r = (r * 10) + v; @@ -244,6 +255,63 @@ public static final long parseLongBase10(final byte[] b, int ptr, } /** + * Parse 8 character base 16 (hex) formatted string to unsigned integer. + * <p> + * The number is read in network byte order, that is, most significant + * nybble first. + * + * @param bs + * buffer to parse digits from; positions {@code [p, p+8)} will + * be parsed. + * @param p + * first position within the buffer to parse. + * @return the integer value. + * @throws ArrayIndexOutOfBoundsException + * if the string is not hex formatted. + */ + public static final int parseHexInt32(final byte[] bs, final int p) { + int r = digits16[bs[p]] << 4; + + r |= digits16[bs[p + 1]]; + r <<= 4; + + r |= digits16[bs[p + 2]]; + r <<= 4; + + r |= digits16[bs[p + 3]]; + r <<= 4; + + r |= digits16[bs[p + 4]]; + r <<= 4; + + r |= digits16[bs[p + 5]]; + r <<= 4; + + r |= digits16[bs[p + 6]]; + + final int last = digits16[bs[p + 7]]; + if (r < 0 || last < 0) + throw new ArrayIndexOutOfBoundsException(); + return (r << 4) | last; + } + + /** + * Parse a single hex digit to its numeric value (0-15). + * + * @param digit + * hex character to parse. + * @return numeric value, in the range 0-15. + * @throws ArrayIndexOutOfBoundsException + * if the input digit is not a valid hex digit. + */ + public static final int parseHexInt4(final byte digit) { + final byte r = digits16[digit]; + if (r < 0) + throw new ArrayIndexOutOfBoundsException(); + return r; + } + + /** * Parse a Git style timezone string. * <p> * The sequence "-0315" will be parsed as the numeric value -195, as the -- 1.6.3.1.333.g3ebba7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html