diff --git a/agrona/src/main/java/org/agrona/AsciiEncoding.java b/agrona/src/main/java/org/agrona/AsciiEncoding.java index dee3fa09c..418ecb2ef 100644 --- a/agrona/src/main/java/org/agrona/AsciiEncoding.java +++ b/agrona/src/main/java/org/agrona/AsciiEncoding.java @@ -127,21 +127,20 @@ public static int getDigit(final int index, final char value) * @param index at which the number begins. * @param length of the encoded number in characters. * @throws AsciiNumberFormatException if cs is not an int value - * @throws IndexOutOfBoundsException if cs is empty + * @throws IndexOutOfBoundsException if parsing results in access outside string boundaries, or length is negative * @return the parsed value. */ public static int parseIntAscii(final CharSequence cs, final int index, final int length) { - final int endExclusive = index + length; - final int first = cs.charAt(index); - int i = index; - final boolean hasSign = first == MINUS_SIGN; - - if (hasSign && length > 1) + if (length <= 1) { - i++; + return parseSingleDigit(cs, index, length); } + final boolean hasSign = cs.charAt(index) == MINUS_SIGN; + final int endExclusive = index + length; + int i = hasSign ? index + 1 : index; + if (length >= 10) { checkIntLimits(cs, index, length, i, hasSign); @@ -168,21 +167,20 @@ public static int parseIntAscii(final CharSequence cs, final int index, final in * @param index at which the number begins. * @param length of the encoded number in characters. * @throws AsciiNumberFormatException if cs is not a long value - * @throws IndexOutOfBoundsException if cs is empty + * @throws IndexOutOfBoundsException if parsing results in access outside string boundaries, or length is negative * @return the parsed value. */ public static long parseLongAscii(final CharSequence cs, final int index, final int length) { - final int endExclusive = index + length; - final int first = cs.charAt(index); - int i = index; - final boolean hasSign = first == MINUS_SIGN; - - if (hasSign && length > 1) + if (length <= 1) { - i++; + return parseSingleDigit(cs, index, length); } + final boolean hasSign = cs.charAt(index) == MINUS_SIGN; + final int endExclusive = index + length; + int i = hasSign ? index + 1 : index; + if (length >= 19) { checkLongLimits(cs, index, length, i, hasSign); @@ -202,6 +200,22 @@ public static long parseLongAscii(final CharSequence cs, final int index, final return tally; } + private static int parseSingleDigit(final CharSequence cs, final int index, final int length) + { + if (length == 1) + { + return AsciiEncoding.getDigit(index, cs.charAt(index)); + } + else if (length == 0) + { + throw new AsciiNumberFormatException("'' is not a valid int @ " + index); + } + else + { + throw new IndexOutOfBoundsException("length=" + length); + } + } + private static void checkIntLimits( final CharSequence cs, final int index, final int length, final int i, final boolean hasSign) { diff --git a/agrona/src/test/java/org/agrona/AsciiEncodingTest.java b/agrona/src/test/java/org/agrona/AsciiEncodingTest.java index 4a44d62af..ddb91ee5d 100644 --- a/agrona/src/test/java/org/agrona/AsciiEncodingTest.java +++ b/agrona/src/test/java/org/agrona/AsciiEncodingTest.java @@ -151,12 +151,12 @@ public void shouldThrowExceptionWhenParsingLongContainingLonePlusSign() @Test public void shouldThrowExceptionWhenParsingEmptyInteger() { - assertThrows(IndexOutOfBoundsException.class, () -> parseIntAscii("", 0, 0)); + assertThrows(AsciiNumberFormatException.class, () -> parseIntAscii("", 0, 0)); } @Test public void shouldThrowExceptionWhenParsingEmptyLong() { - assertThrows(IndexOutOfBoundsException.class, () -> parseLongAscii("", 0, 0)); + assertThrows(AsciiNumberFormatException.class, () -> parseLongAscii("", 0, 0)); } }