Fix bugs in DecimalFormatParser.parse

This commit is contained in:
Alexey Andreev 2015-06-14 16:36:50 +03:00
parent 2fd1ca9777
commit 857e336f03
3 changed files with 115 additions and 7 deletions

View File

@ -21,7 +21,6 @@ import java.text.DecimalFormatSymbols;
import org.teavm.classlib.impl.unicode.CLDRHelper; import org.teavm.classlib.impl.unicode.CLDRHelper;
import org.teavm.classlib.java.lang.TArithmeticException; import org.teavm.classlib.java.lang.TArithmeticException;
import org.teavm.classlib.java.lang.TDouble; import org.teavm.classlib.java.lang.TDouble;
import org.teavm.classlib.java.lang.TIndexOutOfBoundsException;
import org.teavm.classlib.java.lang.TString; import org.teavm.classlib.java.lang.TString;
import org.teavm.classlib.java.util.TLocale; import org.teavm.classlib.java.util.TLocale;
@ -221,7 +220,7 @@ public class TDecimalFormat extends TNumberFormat {
String posPrefix = getPositivePrefix(); String posPrefix = getPositivePrefix();
if (string.regionMatches(index, negPrefix, 0, negPrefix.length())) { if (string.regionMatches(index, negPrefix, 0, negPrefix.length())) {
positive = false; positive = false;
} else if (string.regionMatches(index, posPrefix, 0, posPrefix.length())) { } else if (!string.regionMatches(index, posPrefix, 0, posPrefix.length())) {
position.setErrorIndex(index); position.setErrorIndex(index);
return null; return null;
} }
@ -264,12 +263,38 @@ public class TDecimalFormat extends TNumberFormat {
} }
allowGroupSeparator = false; allowGroupSeparator = false;
++index; ++index;
} else if (index + exponentSeparator.length() < string.length() && } else if (string.regionMatches(index, exponentSeparator, 0, exponentSeparator.length())) {
string.substring(index, index + exponentSeparator.length()).equals(exponentSeparator)) {
if (exponentDigits == 0) { if (exponentDigits == 0) {
break; break;
} }
index += exponentSeparator.length(); index += exponentSeparator.length();
if (index == string.length()) {
position.setErrorIndex(index);
return null;
}
boolean positiveExponent = true;
if (string.charAt(index) == symbols.getMinusSign()) {
positiveExponent = false;
++index;
}
int exponentLength = 0;
while (index < string.length()) {
digit = string.charAt(index) - symbols.getZeroDigit();
if (digit < 0 || digit > 9) {
break;
}
exponent = exponent * 10 + digit;
++exponentLength;
++index;
}
if (exponentLength == 0) {
position.setErrorIndex(index);
return null;
}
if (!positiveExponent) {
exponent = -exponent;
}
break;
} else { } else {
break; break;
} }
@ -280,18 +305,26 @@ public class TDecimalFormat extends TNumberFormat {
return null; return null;
} }
if (exponent < POW10_ARRAY.length) { position.setIndex(index);
exponent += shift - fracSize;
if (exponent > 0 && exponent < POW10_ARRAY.length) {
if (mantissa < Long.MAX_VALUE / POW10_ARRAY[exponent]) { if (mantissa < Long.MAX_VALUE / POW10_ARRAY[exponent]) {
mantissa *= POW10_ARRAY[exponent]; mantissa *= POW10_ARRAY[exponent];
exponent = 0; exponent = 0;
} }
} else if (exponent < 0 && -exponent < POW10_ARRAY.length) {
if (mantissa % POW10_ARRAY[-exponent] == 0) {
mantissa /= POW10_ARRAY[-exponent];
exponent = 0;
}
} }
if (shift == 0 && exponent == 0) { if (exponent == 0) {
return positive ? mantissa : -mantissa; return positive ? mantissa : -mantissa;
} }
double result = TDouble.decimalExponent(exponent + shift); double result = TDouble.decimalExponent(exponent) * mantissa;
return positive ? result : -result; return positive ? result : -result;
} }

View File

@ -0,0 +1,60 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import static org.junit.Assert.*;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
public class DecimalFormatParseTest {
private static DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.ENGLISH);
@Test
public void parsesNumber() throws ParseException {
DecimalFormat format = createFormat("#,#00.#");
assertEquals(2L, format.parse("2"));
assertEquals(23L, format.parse("23"));
assertEquals(23L, format.parse("23.0"));
assertEquals(2300L, format.parse("2,3,0,0"));
assertEquals(23.1, format.parse("23.1"));
}
@Test
public void parsesLargeValue() throws ParseException {
DecimalFormat format = createFormat("#,#00.#");
assertEquals(9223372036854775807L, format.parse("9223372036854775807"));
assertEquals(99E18, format.parse("99000000000000000000"));
}
@Test
public void parsesExponential() throws ParseException {
DecimalFormat format = createFormat("0.#E0");
assertEquals(23L, format.parse("2.3E1"));
assertEquals(23L, format.parse("2300E-2"));
assertEquals(99E18, format.parse("99E18"));
}
private DecimalFormat createFormat(String format) {
return new DecimalFormat(format, symbols);
}
}

View File

@ -1,3 +1,18 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text; package org.teavm.classlib.java.text;
import static org.junit.Assert.*; import static org.junit.Assert.*;