Add StringUtils.parseUInt31()

......@@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.Map;
import org.h2.engine.Constants;
import org.h2.util.StringUtils;
/**
* Utility methods
......@@ -931,9 +932,8 @@ public final class DataUtils {
if (m != null && m.endsWith("]")) {
int dash = m.lastIndexOf('/');
if (dash >= 0) {
String s = m.substring(dash + 1, m.length() - 1);
try {
return Integer.parseInt(s);
return StringUtils.parseUInt31(m, dash + 1, m.length() - 1);
} catch (NumberFormatException e) {
// no error code
}
......
......@@ -33,6 +33,7 @@ import org.h2.store.InDoubtTransaction;
import org.h2.store.fs.FileChannelInputStream;
import org.h2.store.fs.FileUtils;
import org.h2.table.TableBase;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
/**
......@@ -267,7 +268,7 @@ public class MVTableEngine implements TableEngine {
if (mapName.startsWith("temp.")) {
mvStore.removeMap(mapName);
} else if (mapName.startsWith("table.") || mapName.startsWith("index.")) {
int id = Integer.parseInt(mapName.substring(1 + mapName.indexOf('.')));
int id = StringUtils.parseUInt31(mapName, mapName.indexOf('.') + 1, mapName.length());
if (!objectIds.get(id)) {
mvStore.removeMap(mapName);
}
......
......@@ -19,6 +19,7 @@ import org.h2.mvstore.MVStore;
import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType;
import org.h2.mvstore.type.ObjectDataType;
import org.h2.util.StringUtils;
/**
* A store that supports concurrent MVCC read-committed transactions.
......@@ -153,7 +154,8 @@ public class TransactionStore {
if (mapName.length() > UNDO_LOG_NAME_PREFIX.length()) {
boolean committed = mapName.charAt(UNDO_LOG_NAME_PREFIX.length()) == UNDO_LOG_COMMITTED;
if (store.hasData(mapName) || committed) {
int transactionId = Integer.parseInt(mapName.substring(UNDO_LOG_NAME_PREFIX.length() + 1));
int transactionId = StringUtils.parseUInt31(mapName, UNDO_LOG_NAME_PREFIX.length() + 1,
mapName.length());
VersionedBitSet openTxBitSet = openTransactions.get();
if (!openTxBitSet.get(transactionId)) {
Object[] data = preparedTransactions.get(transactionId);
......
......@@ -370,8 +370,8 @@ public class DateTimeUtils {
}
}
int year = Integer.parseInt(s.substring(start, yEnd));
int month = Integer.parseInt(s.substring(mStart, mEnd));
int day = Integer.parseInt(s.substring(dStart, end));
int month = StringUtils.parseUInt31(s, mStart, mEnd);
int day = StringUtils.parseUInt31(s, dStart, end);
if (!isValidDate(year, month, day)) {
throw new IllegalArgumentException(year + "-" + month + "-" + day);
}
......@@ -439,23 +439,23 @@ public class DateTimeUtils {
sEnd = s.indexOf('.', sStart);
}
}
hour = Integer.parseInt(s.substring(start, hEnd));
if (hour < 0 || hour == 0 && s.charAt(start) == '-' || hour >= 24) {
hour = StringUtils.parseUInt31(s, start, hEnd);
if (hour >= 24) {
throw new IllegalArgumentException(s);
}
minute = Integer.parseInt(s.substring(mStart, mEnd));
minute = StringUtils.parseUInt31(s, mStart, mEnd);
if (sStart > 0) {
if (sEnd < 0) {
second = Integer.parseInt(s.substring(sStart, end));
second = StringUtils.parseUInt31(s, sStart, end);
nanos = 0;
} else {
second = Integer.parseInt(s.substring(sStart, sEnd));
second = StringUtils.parseUInt31(s, sStart, sEnd);
nanos = parseNanos(s, sEnd + 1, end);
}
} else {
second = nanos = 0;
}
if (minute < 0 || minute >= 60 || second < 0 || second >= 60) {
if (minute >= 60 || second >= 60) {
throw new IllegalArgumentException(s);
}
return ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND + nanos;
......@@ -1856,8 +1856,8 @@ public class DateTimeUtils {
}
private static long parseIntervalRemaining(String s, int start, int end, int max) {
long v = Integer.parseInt(s.substring(start, end));
if (v < 0 || v > max) {
int v = StringUtils.parseUInt31(s, start, end);
if (v > max) {
throw new IllegalArgumentException(s);
}
return v;
......@@ -1867,13 +1867,13 @@ public class DateTimeUtils {
int seconds, nanos;
int dot = s.indexOf('.', start + 1);
if (dot < 0) {
seconds = Integer.parseInt(s.substring(start));
seconds = StringUtils.parseUInt31(s, start, s.length());
nanos = 0;
} else {
seconds = Integer.parseInt(s.substring(start, dot));
seconds = StringUtils.parseUInt31(s, start, dot);
nanos = parseNanos(s, dot + 1, s.length());
}
if (seconds < 0 || seconds > 59) {
if (seconds > 59) {
throw new IllegalArgumentException(s);
}
return seconds * NANOS_PER_SECOND + nanos;
......
......@@ -921,6 +921,38 @@ public class StringUtils {
softCache = null;
}
/**
* Parses an unsigned 31-bit integer. Neither - nor + signs are allowed.
*
* @param s string to parse
* @param start the beginning index, inclusive
* @param end the ending index, exclusive
* @return the unsigned {@code int} not greater than {@link Integer#MAX_VALUE}.
*/
public static int parseUInt31(String s, int start, int end) {
if (end > s.length() || start < 0 || start > end) {
throw new IndexOutOfBoundsException();
}
if (start == end) {
throw new NumberFormatException("");
}
int result = 0;
for (int i = start; i < end; i++) {
char ch = s.charAt(i);
// Ensure that character is valid and that multiplication by 10 will
// be performed without overflow
if (ch < '0' || ch > '9' || result > 214_748_364) {
throw new NumberFormatException(s.substring(start, end));
}
result = result * 10 + ch - '0';
if (result < 0) {
// Overflow
throw new NumberFormatException(s.substring(start, end));
}
}
return result;
}
/**
* Convert a hex encoded string to a byte array.
*
......
......@@ -32,6 +32,7 @@ public class TestStringUtils extends TestBase {
@Override
public void test() throws Exception {
testParseUInt31();
testHex();
testXML();
testSplit();
......@@ -43,6 +44,32 @@ public class TestStringUtils extends TestBase {
testTrimSubstring();
}
private void testParseUInt31() {
assertEquals(0, StringUtils.parseUInt31("101", 1, 2));
assertEquals(11, StringUtils.parseUInt31("11", 0, 2));
assertEquals(0, StringUtils.parseUInt31("000", 0, 3));
assertEquals(1, StringUtils.parseUInt31("01", 0, 2));
assertEquals(999999999, StringUtils.parseUInt31("X999999999", 1, 10));
assertEquals(2147483647, StringUtils.parseUInt31("2147483647", 0, 10));
testParseUInt31Bad(null, 0, 1);
testParseUInt31Bad("1", -1, 1);
testParseUInt31Bad("1", 0, 0);
testParseUInt31Bad("12", 1, 0);
testParseUInt31Bad("-0", 0, 2);
testParseUInt31Bad("+0", 0, 2);
testParseUInt31Bad("2147483648", 0, 10);
testParseUInt31Bad("21474836470", 0, 11);
}
private void testParseUInt31Bad(String s, int start, int end) {
try {
StringUtils.parseUInt31(s, start, end);
} catch (NullPointerException | IndexOutOfBoundsException | NumberFormatException e) {
return;
}
fail();
}
private void testHex() {
assertEquals("face",
StringUtils.convertBytesToHex(new byte[]
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论