*/
public static ConversionResult makeDecimalValue(CharSequence in, boolean validate) {
try {
FastStringBuffer digits = new FastStringBuffer(in.length());
int scale = 0;
int state = 0;
// 0 - in initial whitespace; 1 - after sign
// 3 - after decimal point; 5 - in final whitespace
boolean foundDigit = false;
int len = in.length();
for (int i=0; i<len; i++) {
char c = in.charAt(i);
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
if (state != 0) {
state = 5;
}
break;
case '+':
if (state != 0) {
throw new NumberFormatException("unexpected sign");
}
state = 1;
break;
case '-':
if (state != 0) {
throw new NumberFormatException("unexpected sign");
}
state = 1;
digits.append(c);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (state == 0) {
state = 1;
} else if (state >= 3) {
scale++;
}
if (state == 5) {
throw new NumberFormatException("contains embedded whitespace");
}
digits.append(c);
foundDigit = true;
break;
case '.':
if (state == 5) {
throw new NumberFormatException("contains embedded whitespace");
}
if (state >= 3) {
throw new NumberFormatException("more than one decimal point");
}
state = 3;
break;
default:
throw new NumberFormatException("invalid character '" + c + "'");
}
}
if (!foundDigit) {
throw new NumberFormatException("no digits in value");
}
// remove insignificant trailing zeroes
while (scale > 0) {
if (digits.charAt(digits.length()-1) == '0') {
digits.setLength(digits.length() - 1);
scale--;
} else {
break;
}
}
BigInteger bigInt = new BigInteger(digits.toString());
BigDecimal bigDec = new BigDecimal(bigInt, scale);
return new DecimalValue(bigDec);
} catch (NumberFormatException err) {
ValidationFailure e = new ValidationFailure(
"Cannot convert string " + Err.wrap(Whitespace.trim(in), Err.VALUE) +