Fix Issue 7036: java.math.BigInteger ctor accepts invalid input.

OpenSSL's BN library accepts pretty much all input, so if we want to follow
Java's rules, we have to implement them ourselves.

(The FormatterTest change is unrelated and fixes outstanding build breakage
caused by me.)

Bug: http://code.google.com/p/android/issues/detail?id=7036
Change-Id: I0f5413b56fad9289644927672bebf7c3d57e8042
diff --git a/libcore/luni/src/test/java/java/math/AllTests.java b/libcore/luni/src/test/java/java/math/AllTests.java
new file mode 100644
index 0000000..f182e01
--- /dev/null
+++ b/libcore/luni/src/test/java/java/math/AllTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * 
+ * 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 java.math;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+    public static final Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(java.math.BigIntegerTest.class);
+        return suite;
+    }
+}
diff --git a/libcore/luni/src/test/java/java/math/BigIntegerTest.java b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
new file mode 100644
index 0000000..831ed62
--- /dev/null
+++ b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * 
+ * 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 java.math;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.math.BigInteger;
+import java.util.Locale;
+
+public class BigIntegerTest extends junit.framework.TestCase {
+    // http://code.google.com/p/android/issues/detail?id=7036
+    public void test_invalidBigIntegerStringConversions() {
+        // Check we don't disallow related reasonable strings...
+        new BigInteger("1", 10);
+        new BigInteger("1a", 16);
+        new BigInteger("-1", 10);
+        new BigInteger("-1a", 16);
+        // 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) {
+        }
+        try {
+            new BigInteger("-1a"); // no trailing digits from other bases.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-1 hello"); // no trailing junk at all.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("--1"); // only one sign.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger(""); // at least one digit.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-"); // at least one digit, even after a sign.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+    }
+}
diff --git a/libcore/luni/src/test/java/java/util/FormatterTest.java b/libcore/luni/src/test/java/java/util/FormatterTest.java
index c57c131..81c8a36 100644
--- a/libcore/luni/src/test/java/java/util/FormatterTest.java
+++ b/libcore/luni/src/test/java/java/util/FormatterTest.java
@@ -16,6 +16,7 @@
 
 package java.util;
 
+import java.math.BigDecimal;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
diff --git a/libcore/math/src/main/java/java/math/BigInt.java b/libcore/math/src/main/java/java/math/BigInt.java
index 6a1cb97..1f3ffdd 100644
--- a/libcore/math/src/main/java/java/math/BigInt.java
+++ b/libcore/math/src/main/java/java/math/BigInt.java
@@ -156,11 +156,7 @@
     }
 
     public void putDecString(String str) {
-        if (str == null) throw new NullPointerException();
-        if (str.length() == 0) {
-            // math.12=Zero length BigInteger
-            throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$
-        }
+        checkString(str, 10);
         this.makeValid();
         int usedLen = NativeBN.BN_dec2bn(this.bignum, str);
         Check((usedLen > 0));
@@ -170,11 +166,7 @@
     }
 
     public void putHexString(String str) {
-        if (str == null) throw new NullPointerException();
-        if (str.length() == 0) {
-            // math.12=Zero length BigInteger
-            throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$
-        }
+        checkString(str, 16);
         this.makeValid();
         int usedLen = NativeBN.BN_hex2bn(this.bignum, str);
         Check((usedLen > 0));
@@ -183,6 +175,31 @@
         }
     }
 
+    /**
+     * 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) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        // A valid big integer consists of an optional '-' 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;
+        if (charCount - i == 0) {
+            throw new NumberFormatException(s);
+        }
+        for (; i < charCount; ++i) {
+            if (Character.digit(s.charAt(i), radix) == -1) {
+                throw new NumberFormatException(s);
+            }
+        }
+    }
+
     public void putBigEndian(byte[] a, boolean neg) {
         this.makeValid();
         Check(NativeBN.BN_bin2bn(a, a.length, neg, this.bignum));