int radix = base == 0 ? 10 : base;
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
throw new IllegalArgumentException("illegal radix " + radix);
}
if (buflen == 0) {
throw new InvalidIntegerException();
}
int i = begin;
buflen += begin;
byte ival;
int flags = 0;
long limit = -Long.MAX_VALUE;
long result = 0;
long multmin = 0;
int digit;
int state = SBEGIN;
while (state != SCOMPLETE) {
states:
switch(state) {
case SBEGIN:
if (strict) {
for (; i < buflen && isWhitespace(bytes[i]); i++) ;
} else {
for (; i < buflen && (isWhitespace(ival = bytes[i]) || ival == '_'); i++) ;
}
state = i < buflen ? SSIGN : SEOF;
break;
case SSIGN:
switch(bytes[i]) {
case '-':
flags |= FLAG_NEGATIVE;
limit = Long.MIN_VALUE;
case '+':
if (++i >= buflen) {
state = SEOF;
} else if (bytes[i] == '0') {
state = SZERO;
} else {
state = SPOST_SIGN;
}
break states;
case '0':
state = SZERO;
break states;
default:
state = SDIGITS;
break states;
}
case SZERO:
if (++i >= buflen) {
state = SCOMPLETE;
break;
}
switch (bytes[i]) {
case 'x':
case 'X':
if (base == 0 || base == 16) {
radix = 16;
state = ++i >= buflen ? SEOF : SPOST_SIGN;
} else {
state = SDIGITS;
}
break states;
case 'b':
case 'B':
if (base == 0 || base == 2) {
radix = 2;
state = ++i >= buflen ? SEOF : SPOST_SIGN;
} else {
state = SDIGITS;
}
break states;
case 'd':
case 'D':
if (base == 0 || base == 10) {
radix = 10;
state = ++i >= buflen ? SEOF : SPOST_SIGN;
} else {
state = SDIGITS;
}
break states;
case 'o':
case 'O':
case '_':
if (base == 0 || base == 8) {
radix = 8;
state = ++i >= buflen ? SEOF : SPOST_SIGN;
} else {
state = SDIGITS;
}
break states;
default:
if (base == 0 || base == 8) {
radix = 8;
}
flags |= FLAG_DIGIT;
state = SDIGITS;
break states;
}
case SPOST_SIGN:
if (strict) {
int ibefore = i;
for (; i < buflen && isWhitespace(bytes[i]); i++) ;
if (ibefore != i) {
// set this to enforce no-underscore rule (though I think
// it's an MRI bug)
flags |= FLAG_WHITESPACE;
}
} else {
for ( ; i < buflen && (isWhitespace(ival = bytes[i]) || ival == '_'); i++) {
if (ival == '_') {
if ((flags & FLAG_WHITESPACE) != 0) {
throw new InvalidIntegerException();
}
flags |= FLAG_UNDERSCORE;
} else {
if ((flags & FLAG_UNDERSCORE) != 0) {
throw new InvalidIntegerException();
}
flags |= FLAG_WHITESPACE;
}
}
}
state = i < buflen ? SDIGITS : SEOF;
break;
case SDIGITS:
digit = Character.digit((char) bytes[i],radix);
if (digit < 0) {
state = strict ? SEOD_STRICT : SEOF;
break;
}
result = -digit;
if (++i >= buflen) {
state = SCOMPLETE;
break;
}
multmin = limit / radix;
flags = (flags | FLAG_DIGIT) & ~FLAG_UNDERSCORE;
state = strict ? SDIGIT_STRICT : SDIGIT;
break;
case SDIGIT:
while ((digit = Character.digit((char) bytes[i],radix)) >= 0) {
if (result < multmin || ((result *= radix) < limit + digit)) {
state = SERR_TOO_BIG;
break states;
}
result -= digit;
if (++i >= buflen) {
state = SCOMPLETE;
break states;
}
}
state = bytes[i++] == '_' ? SDIGIT_USC : SEOF;
break;
case SDIGIT_USC:
for ( ; i < buflen && bytes[i] == '_'; i++) ;
state = i < buflen ? SDIGIT : SEOF;
break;
case SDIGIT_STRICT:
while ((digit = Character.digit((char) bytes[i],radix)) >= 0) {
if (result < multmin || ((result *= radix) < limit + digit)) {
state = SERR_TOO_BIG;
break states;
}
result -= digit;
if (++i >= buflen) {
state = SCOMPLETE;
break states;
}
flags &= ~FLAG_UNDERSCORE;
}
if (bytes[i] == '_') {
if ((flags & (FLAG_UNDERSCORE | FLAG_WHITESPACE)) != 0) {
state = SERR_NOT_STRICT;
break;
}
flags |= FLAG_UNDERSCORE;
state = ++i >= buflen ? SEOD_STRICT : SDIGIT_STRICT;
} else {
state = SEOD_STRICT;
}
break;
case SEOD_STRICT:
if ((flags & FLAG_UNDERSCORE)!= 0) {
state = SERR_NOT_STRICT;
break;
}
for ( ; i < buflen && isWhitespace(bytes[i]); i++ );
state = i < buflen ? SERR_NOT_STRICT : SCOMPLETE;
break;
case SEOF:
if ((flags & FLAG_DIGIT) == 0) {
throw new InvalidIntegerException("no digits supplied");
}
state = SCOMPLETE;
break;
case SERR_TOO_BIG:
throw new NumberTooLargeException("can't convert to long");
case SERR_NOT_STRICT:
throw new InvalidIntegerException("does not meet strict criteria");
} // switch
} //while
if ((flags & FLAG_NEGATIVE) == 0) {
return -result;