1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughespackage java.lang;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Used to parse a string and return either a single or double precision
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * floating point number.
23dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughes * @hide
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
25dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughesfinal class StringToReal {
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
271f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private static final class StringExponentPair {
281f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        String s;
29750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        long e;
301f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        boolean negative;
311f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
32750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // Flags for two special non-error failure cases.
33750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        boolean infinity;
34750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        boolean zero;
35750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes
36750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        public float specialValue() {
37750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            if (infinity) {
38750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
39750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            }
40750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            return negative ? -0.0f : 0.0f;
411f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
421f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
431f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
441f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    /**
451f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * Takes a String and an integer exponent. The String should hold a positive
461f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * integer value (or zero). The exponent will be used to calculate the
471f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * floating point number by taking the positive integer the String
481f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * represents and multiplying by 10 raised to the power of the of the
49750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes     * exponent. Returns the closest double value to the real number, or Double.longBitsToDouble(-1).
501f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     */
511f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private static native double parseDblImpl(String s, int e);
521f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
531f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    /**
541f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * Takes a String and an integer exponent. The String should hold a positive
551f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * integer value (or zero). The exponent will be used to calculate the
561f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * floating point number by taking the positive integer the String
571f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * represents and multiplying by 10 raised to the power of the of the
58750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes     * exponent. Returns the closest float value to the real number, or Float.intBitsToFloat(-1).
591f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     */
601f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private static native float parseFltImpl(String s, int e);
611f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
621f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private static NumberFormatException invalidReal(String s, boolean isDouble) {
631f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        throw new NumberFormatException("Invalid " + (isDouble ? "double" : "float") + ": \"" + s + "\"");
641f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
651f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
661f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    /**
67750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes     * Returns a StringExponentPair containing a String with no leading or trailing white
681f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * space and trailing zeroes eliminated. The exponent of the
691f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * StringExponentPair will be used to calculate the floating point number by
701f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * taking the positive integer the String represents and multiplying by 10
711f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * raised to the power of the of the exponent.
721f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     */
731f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private static StringExponentPair initialParse(String s, int length, boolean isDouble) {
74750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        StringExponentPair result = new StringExponentPair();
751f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (length == 0) {
761f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, isDouble);
771f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
78750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        result.negative = (s.charAt(0) == '-');
79750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes
80750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // We ignore trailing double or float indicators; the method you called determines
81750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // what you'll get.
82750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        char c = s.charAt(length - 1);
831f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (c == 'D' || c == 'd' || c == 'F' || c == 'f') {
841f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            length--;
851f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            if (length == 0) {
861f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                throw invalidReal(s, isDouble);
871f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            }
881f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
891f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
90750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        int end = Math.max(s.indexOf('E'), s.indexOf('e'));
91750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        if (end != -1) {
92750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            // Is there anything after the 'e'?
931f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            if (end + 1 == length) {
941f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                throw invalidReal(s, isDouble);
951f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            }
961f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
97750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            // Do we have an optional explicit sign?
98750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            int exponentOffset = end + 1;
99750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            boolean negativeExponent = false;
100750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            char firstExponentChar = s.charAt(exponentOffset);
101750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            if (firstExponentChar == '+' || firstExponentChar == '-') {
102750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                negativeExponent = (firstExponentChar == '-');
103750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                ++exponentOffset;
104750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            }
105750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes
106750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            // Do we have a valid positive integer?
107750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            String exponentString = s.substring(exponentOffset, length);
108750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            if (exponentString.isEmpty()) {
109750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                throw invalidReal(s, isDouble);
110750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            }
111750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            for (int i = 0; i < exponentString.length(); ++i) {
112750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                char ch = exponentString.charAt(i);
113750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                if (ch < '0' || ch > '9') {
1141f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                    throw invalidReal(s, isDouble);
1151f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                }
1161f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            }
117750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes
118750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            // Parse the integer exponent.
1191f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            try {
120750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                result.e = Integer.parseInt(exponentString);
121750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                if (negativeExponent) {
122750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                    result.e = -result.e;
123750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                }
1241f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            } catch (NumberFormatException ex) {
125750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                // We already checked the string, so the exponent must have been out of range for an int.
126750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                if (negativeExponent) {
127750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                    result.zero = true;
128750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                } else {
129750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                    result.infinity = true;
130750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                }
131750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes                return result;
1321f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            }
1331f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        } else {
1341f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            end = length;
1351f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1361f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (length == 0) {
1371f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, isDouble);
1381f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1391f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
140750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        int start = 0;
1411f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        c = s.charAt(start);
1421f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (c == '-') {
1431f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            ++start;
1441f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            --length;
145750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.negative = true;
1461f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        } else if (c == '+') {
1471f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            ++start;
1481f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            --length;
1491f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1501f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (length == 0) {
1511f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, isDouble);
1521f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1531f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
154750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        int decimal = s.indexOf('.');
1551f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (decimal > -1) {
156750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.e -= end - decimal - 1;
1571f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            s = s.substring(start, decimal) + s.substring(decimal + 1, end);
1581f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        } else {
1591f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            s = s.substring(start, end);
1601f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1611f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
1621f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if ((length = s.length()) == 0) {
1631f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, isDouble);
1641f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1651f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
1661f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        end = length;
1671f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        while (end > 1 && s.charAt(end - 1) == '0') {
1681f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            --end;
1691f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1701f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
1711f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        start = 0;
1721f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        while (start < end - 1 && s.charAt(start) == '0') {
1731f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            start++;
1741f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1751f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
1761f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (end != length || start != 0) {
177750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.e += length - end;
1781f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            s = s.substring(start, end);
1791f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
180a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson
181750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // This is a hack for https://issues.apache.org/jira/browse/HARMONY-329
182a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        // Trim the length of very small numbers, natives can only handle down
183a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        // to E-309
184a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        final int APPROX_MIN_MAGNITUDE = -359;
185a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        final int MAX_DIGITS = 52;
186a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        length = s.length();
187750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        if (length > MAX_DIGITS && result.e < APPROX_MIN_MAGNITUDE) {
188750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            int d = Math.min(APPROX_MIN_MAGNITUDE - (int) result.e, length - 1);
189a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson            s = s.substring(0, length - d);
190750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.e += d;
191750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        }
192750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes
193750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // This is a hack for https://issues.apache.org/jira/browse/HARMONY-6641
194750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // The magic 1024 was determined experimentally; the more plausible -324 and +309 were
195750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        // not sufficient to pass both our tests and harmony's tests.
196750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        if (result.e < -1024) {
197750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.zero = true;
198750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            return result;
199750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        } else if (result.e > 1024) {
200750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            result.infinity = true;
201750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            return result;
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
204750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        result.s = s;
205750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        return result;
2061f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
2071f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2088899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes    // Parses "+Nan", "NaN", "-Nan", "+Infinity", "Infinity", and "-Infinity", case-insensitively.
2098899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes    private static float parseName(String name, boolean isDouble) {
2108899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        // Explicit sign?
2111f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        boolean negative = false;
212866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        int i = 0;
2138899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        int length = name.length();
2148899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        char firstChar = name.charAt(i);
215866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        if (firstChar == '-') {
216866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes            negative = true;
217866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes            ++i;
2188899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes            --length;
219866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        } else if (firstChar == '+') {
220866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes            ++i;
2218899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes            --length;
2221f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
2231f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2248899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        if (length == 8 && name.regionMatches(false, i, "Infinity", 0, 8)) {
2251f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
2261f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
2278899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        if (length == 3 && name.regionMatches(false, i, "NaN", 0, 3)) {
2281f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            return Float.NaN;
2291f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
2308899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        throw invalidReal(name, isDouble);
2311f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
2321f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2331f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    /**
2341f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * Returns the closest double value to the real number in the string.
2351f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *
2361f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @param s
2371f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *            the String that will be parsed to a floating point
2381f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @return the double closest to the real number
2391f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *
2401f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @exception NumberFormatException
2411f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *                if the String doesn't represent a double
2421f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     */
2431f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    public static double parseDouble(String s) {
2441f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        s = s.trim();
2451f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        int length = s.length();
2461f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2471f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (length == 0) {
2481f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, true);
2491f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
2501f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2511f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        // See if this could be a named double
2521f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        char last = s.charAt(length - 1);
2538899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        if (last == 'y' || last == 'N') {
2548899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes            return parseName(s, true);
2551f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
256f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
25778e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes        // See if it could be a hexadecimal representation.
25878e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes        // We don't use startsWith because there might be a leading sign.
25978e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes        if (s.indexOf("0x") != -1 || s.indexOf("0X") != -1) {
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return HexStringParser.parseDouble(s);
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
262f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
2631f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        StringExponentPair info = initialParse(s, length, true);
264750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        if (info.infinity || info.zero) {
265750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            return info.specialValue();
266750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        }
267750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        double result = parseDblImpl(info.s, (int) info.e);
2681f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (Double.doubleToRawLongBits(result) == 0xffffffffffffffffL) {
2691f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, true);
2701f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
271750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        return info.negative ? -result : result;
2721f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
2731f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2741f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    /**
2751f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * Returns the closest float value to the real number in the string.
2761f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *
2771f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @param s
2781f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *            the String that will be parsed to a floating point
2791f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @return the float closest to the real number
2801f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *
2811f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     * @exception NumberFormatException
2821f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     *                if the String doesn't represent a float
2831f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes     */
2841f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    public static float parseFloat(String s) {
2851f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        s = s.trim();
2861f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        int length = s.length();
2871f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2881f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (length == 0) {
2891f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, false);
2901f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
2911f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
2921f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        // See if this could be a named float
2931f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        char last = s.charAt(length - 1);
2948899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes        if (last == 'y' || last == 'N') {
2958899157a607a6bfd4ca4f361c77db8726885e47bElliott Hughes            return parseName(s, false);
2961f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
297f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // See if it could be a hexadecimal representation
29978e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes        // We don't use startsWith because there might be a leading sign.
30078e3320540c8bdcbefba5ae1222ee18f6679ab33Elliott Hughes        if (s.indexOf("0x") != -1 || s.indexOf("0X") != -1) {
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return HexStringParser.parseFloat(s);
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
303f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
3041f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        StringExponentPair info = initialParse(s, length, false);
305750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        if (info.infinity || info.zero) {
306750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes            return info.specialValue();
307750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        }
308750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        float result = parseFltImpl(info.s, (int) info.e);
3091f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (Float.floatToRawIntBits(result) == 0xffffffff) {
3101f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw invalidReal(s, false);
3111f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
312750d24b13461035a89c9af8ec7555588da1cc3d0Elliott Hughes        return info.negative ? -result : result;
3131f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    }
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
315