Fix several BigInteger failures.
From Java 7 on, BigInteger also accepts a leading "+" in its string
constructors.
BigInteger has always claimed to accept non-ASCII digits, but our
implementation never has.
BigInteger.isProbablePrime is defined to return true for certainty <= 0,
but OpenSSL (on which we're based) takes the opposite stance.
Change-Id: I00bfc591a4d583460f71b7eec3de91bf6b03cd87
diff --git a/libcore/luni/src/test/java/java/math/BigIntegerTest.java b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
index 831ed62..ec63e20 100644
--- a/libcore/luni/src/test/java/java/math/BigIntegerTest.java
+++ b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
@@ -30,13 +30,10 @@
new BigInteger("1a", 16);
new BigInteger("-1", 10);
new BigInteger("-1a", 16);
+ // This is allowed from Java 7 on.
+ new BigInteger("+1");
// Now check the invalid cases...
try {
- new BigInteger("+1"); // no positive sign allowed.
- fail();
- } catch (NumberFormatException expected) {
- }
- try {
new BigInteger("-a"); // no digits from other bases.
fail();
} catch (NumberFormatException expected) {
diff --git a/libcore/math/src/main/java/java/math/BigInt.java b/libcore/math/src/main/java/java/math/BigInt.java
index d1bd29b..76ed1ff 100644
--- a/libcore/math/src/main/java/java/math/BigInt.java
+++ b/libcore/math/src/main/java/java/math/BigInt.java
@@ -151,49 +151,80 @@
Check(NativeBN.putULongInt(this.bignum, val, neg));
}
- public void putDecString(String str) {
- checkString(str, 10);
+ public void putDecString(String original) {
+ String s = checkString(original, 10);
this.makeValid();
- int usedLen = NativeBN.BN_dec2bn(this.bignum, str);
+ int usedLen = NativeBN.BN_dec2bn(this.bignum, s);
Check((usedLen > 0));
- if (usedLen < str.length()) {
- throw new NumberFormatException(str);
+ if (usedLen < s.length()) {
+ throw new NumberFormatException(original);
}
}
- public void putHexString(String str) {
- checkString(str, 16);
+ public void putHexString(String original) {
+ String s = checkString(original, 16);
this.makeValid();
- int usedLen = NativeBN.BN_hex2bn(this.bignum, str);
+ int usedLen = NativeBN.BN_hex2bn(this.bignum, s);
Check((usedLen > 0));
- if (usedLen < str.length()) {
- throw new NumberFormatException(str);
+ if (usedLen < s.length()) {
+ throw new NumberFormatException(original);
}
}
/**
+ * Returns a string suitable for passing to OpenSSL.
* Throws if 's' doesn't match Java's rules for valid BigInteger strings.
* BN_dec2bn and BN_hex2bn do very little checking, so we need to manually
* ensure we comply with Java's rules.
* http://code.google.com/p/android/issues/detail?id=7036
*/
- public void checkString(String s, int radix) {
+ public String checkString(String s, int radix) {
if (s == null) {
throw new NullPointerException();
}
- // A valid big integer consists of an optional '-' followed by
+ // A valid big integer consists of an optional '-' or '+' followed by
// one or more digit characters appropriate to the given radix,
// and no other characters.
- final int charCount = s.length();
- int i = (charCount > 0 && s.charAt(0) == '-') ? 1 : 0;
+ int charCount = s.length();
+ int i = 0;
+ if (charCount > 0) {
+ char ch = s.charAt(0);
+ if (ch == '+') {
+ // Java supports leading +, but OpenSSL doesn't, so we need to strip it.
+ s = s.substring(1);
+ --charCount;
+ } else if (ch == '-') {
+ ++i;
+ }
+ }
if (charCount - i == 0) {
throw new NumberFormatException(s);
}
+ boolean nonAscii = false;
for (; i < charCount; ++i) {
- if (Character.digit(s.charAt(i), radix) == -1) {
+ char ch = s.charAt(i);
+ if (Character.digit(ch, radix) == -1) {
throw new NumberFormatException(s);
}
+ if (ch < '0' || ch > '9') {
+ nonAscii = true;
+ }
}
+ return nonAscii ? toAscii(s) : s;
+ }
+
+ // Java supports non-ASCII digits, but OpenSSL doesn't.
+ private static String toAscii(String s) {
+ int length = s.length();
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ char ch = s.charAt(i);
+ if (ch != '-') {
+ ch = (char) ('0' + Character.digit(ch, 10));
+ }
+ result.append(ch);
+ }
+ return result.toString();
}
public void putBigEndian(byte[] a, boolean neg) {
diff --git a/libcore/math/src/main/java/java/math/BigInteger.java b/libcore/math/src/main/java/java/math/BigInteger.java
index 1fbeb48..adef534 100644
--- a/libcore/math/src/main/java/java/math/BigInteger.java
+++ b/libcore/math/src/main/java/java/math/BigInteger.java
@@ -271,8 +271,9 @@
/**
* Constructs a new {@code BigInteger} instance from the string
- * representation. The string representation consists of an optional minus
+ * representation. The string representation consists of an optional plus or minus
* sign followed by a non-empty sequence of decimal digits.
+ * Digits are interpreted as if by {@code Character.digit(char, 10)}.
*
* @param val
* string representation of the new {@code BigInteger}.
@@ -291,10 +292,9 @@
/**
* Constructs a new {@code BigInteger} instance from the string
- * representation. The string representation consists of an optional minus
+ * representation. The string representation consists of an optional plus or minus
* sign followed by a non-empty sequence of digits in the specified radix.
- * For the conversion the method {@code Character.digit(char, radix)} is
- * used.
+ * Digits are interpreted as if by {@code Character.digit(char, radix)}.
*
* @param val
* string representation of the new {@code BigInteger}.
@@ -1215,6 +1215,9 @@
* otherwise.
*/
public boolean isProbablePrime(int certainty) {
+ if (certainty <= 0) {
+ return true;
+ }
validate1("isProbablePrime", this);
return bigInt.isPrime(certainty, null, null);
}