1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java Thu Oct 03 15:40:35 2013 +0200
1.3 @@ -0,0 +1,3278 @@
1.4 +/*
1.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +/*
1.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
1.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
1.32 + *
1.33 + * The original version of this source code and documentation is copyrighted
1.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
1.35 + * materials are provided under terms of a License Agreement between Taligent
1.36 + * and Sun. This technology is protected by multiple US and International
1.37 + * patents. This notice and attribution to Taligent may not be removed.
1.38 + * Taligent is a registered trademark of Taligent, Inc.
1.39 + *
1.40 + */
1.41 +
1.42 +package java.text;
1.43 +
1.44 +import java.io.InvalidObjectException;
1.45 +import java.io.IOException;
1.46 +import java.io.ObjectInputStream;
1.47 +import java.math.BigDecimal;
1.48 +import java.math.BigInteger;
1.49 +import java.math.RoundingMode;
1.50 +import java.util.ArrayList;
1.51 +import java.util.Currency;
1.52 +import java.util.Locale;
1.53 +import java.util.ResourceBundle;
1.54 +import java.util.concurrent.ConcurrentHashMap;
1.55 +import java.util.concurrent.ConcurrentMap;
1.56 +import java.util.concurrent.atomic.AtomicInteger;
1.57 +import java.util.concurrent.atomic.AtomicLong;
1.58 +import sun.util.resources.LocaleData;
1.59 +
1.60 +/**
1.61 + * <code>DecimalFormat</code> is a concrete subclass of
1.62 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
1.63 + * features designed to make it possible to parse and format numbers in any
1.64 + * locale, including support for Western, Arabic, and Indic digits. It also
1.65 + * supports different kinds of numbers, including integers (123), fixed-point
1.66 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
1.67 + * currency amounts ($123). All of these can be localized.
1.68 + *
1.69 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
1.70 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
1.71 + * as <code>getInstance()</code>. In general, do not call the
1.72 + * <code>DecimalFormat</code> constructors directly, since the
1.73 + * <code>NumberFormat</code> factory methods may return subclasses other than
1.74 + * <code>DecimalFormat</code>. If you need to customize the format object, do
1.75 + * something like this:
1.76 + *
1.77 + * <blockquote><pre>
1.78 + * NumberFormat f = NumberFormat.getInstance(loc);
1.79 + * if (f instanceof DecimalFormat) {
1.80 + * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
1.81 + * }
1.82 + * </pre></blockquote>
1.83 + *
1.84 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
1.85 + * <em>symbols</em>. The pattern may be set directly using
1.86 + * <code>applyPattern()</code>, or indirectly using the API methods. The
1.87 + * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
1.88 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
1.89 + * read from localized <code>ResourceBundle</code>s.
1.90 + *
1.91 + * <h4>Patterns</h4>
1.92 + *
1.93 + * <code>DecimalFormat</code> patterns have the following syntax:
1.94 + * <blockquote><pre>
1.95 + * <i>Pattern:</i>
1.96 + * <i>PositivePattern</i>
1.97 + * <i>PositivePattern</i> ; <i>NegativePattern</i>
1.98 + * <i>PositivePattern:</i>
1.99 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
1.100 + * <i>NegativePattern:</i>
1.101 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
1.102 + * <i>Prefix:</i>
1.103 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
1.104 + * <i>Suffix:</i>
1.105 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
1.106 + * <i>Number:</i>
1.107 + * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
1.108 + * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
1.109 + * <i>Integer:</i>
1.110 + * <i>MinimumInteger</i>
1.111 + * #
1.112 + * # <i>Integer</i>
1.113 + * # , <i>Integer</i>
1.114 + * <i>MinimumInteger:</i>
1.115 + * 0
1.116 + * 0 <i>MinimumInteger</i>
1.117 + * 0 , <i>MinimumInteger</i>
1.118 + * <i>Fraction:</i>
1.119 + * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
1.120 + * <i>MinimumFraction:</i>
1.121 + * 0 <i>MinimumFraction<sub>opt</sub></i>
1.122 + * <i>OptionalFraction:</i>
1.123 + * # <i>OptionalFraction<sub>opt</sub></i>
1.124 + * <i>Exponent:</i>
1.125 + * E <i>MinimumExponent</i>
1.126 + * <i>MinimumExponent:</i>
1.127 + * 0 <i>MinimumExponent<sub>opt</sub></i>
1.128 + * </pre></blockquote>
1.129 + *
1.130 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
1.131 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
1.132 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
1.133 + * is optional; if absent, then the positive subpattern prefixed with the
1.134 + * localized minus sign (<code>'-'</code> in most locales) is used as the
1.135 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
1.136 + * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
1.137 + * serves only to specify the negative prefix and suffix; the number of digits,
1.138 + * minimal digits, and other characteristics are all the same as the positive
1.139 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
1.140 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
1.141 + *
1.142 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
1.143 + * thousands separators, decimal separators, etc. may be set to arbitrary
1.144 + * values, and they will appear properly during formatting. However, care must
1.145 + * be taken that the symbols and strings do not conflict, or parsing will be
1.146 + * unreliable. For example, either the positive and negative prefixes or the
1.147 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
1.148 + * to distinguish positive from negative values. (If they are identical, then
1.149 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
1.150 + * specified.) Another example is that the decimal separator and thousands
1.151 + * separator should be distinct characters, or parsing will be impossible.
1.152 + *
1.153 + * <p>The grouping separator is commonly used for thousands, but in some
1.154 + * countries it separates ten-thousands. The grouping size is a constant number
1.155 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
1.156 + * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
1.157 + * interval between the last one and the end of the integer is the one that is
1.158 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
1.159 + * <code>"##,####,####"</code>.
1.160 + *
1.161 + * <h4>Special Pattern Characters</h4>
1.162 + *
1.163 + * <p>Many characters in a pattern are taken literally; they are matched during
1.164 + * parsing and output unchanged during formatting. Special characters, on the
1.165 + * other hand, stand for other characters, strings, or classes of characters.
1.166 + * They must be quoted, unless noted otherwise, if they are to appear in the
1.167 + * prefix or suffix as literals.
1.168 + *
1.169 + * <p>The characters listed here are used in non-localized patterns. Localized
1.170 + * patterns use the corresponding characters taken from this formatter's
1.171 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
1.172 + * their special status. Two exceptions are the currency sign and quote, which
1.173 + * are not localized.
1.174 + *
1.175 + * <blockquote>
1.176 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
1.177 + * location, localized, and meaning.">
1.178 + * <tr bgcolor="#ccccff">
1.179 + * <th align=left>Symbol
1.180 + * <th align=left>Location
1.181 + * <th align=left>Localized?
1.182 + * <th align=left>Meaning
1.183 + * <tr valign=top>
1.184 + * <td><code>0</code>
1.185 + * <td>Number
1.186 + * <td>Yes
1.187 + * <td>Digit
1.188 + * <tr valign=top bgcolor="#eeeeff">
1.189 + * <td><code>#</code>
1.190 + * <td>Number
1.191 + * <td>Yes
1.192 + * <td>Digit, zero shows as absent
1.193 + * <tr valign=top>
1.194 + * <td><code>.</code>
1.195 + * <td>Number
1.196 + * <td>Yes
1.197 + * <td>Decimal separator or monetary decimal separator
1.198 + * <tr valign=top bgcolor="#eeeeff">
1.199 + * <td><code>-</code>
1.200 + * <td>Number
1.201 + * <td>Yes
1.202 + * <td>Minus sign
1.203 + * <tr valign=top>
1.204 + * <td><code>,</code>
1.205 + * <td>Number
1.206 + * <td>Yes
1.207 + * <td>Grouping separator
1.208 + * <tr valign=top bgcolor="#eeeeff">
1.209 + * <td><code>E</code>
1.210 + * <td>Number
1.211 + * <td>Yes
1.212 + * <td>Separates mantissa and exponent in scientific notation.
1.213 + * <em>Need not be quoted in prefix or suffix.</em>
1.214 + * <tr valign=top>
1.215 + * <td><code>;</code>
1.216 + * <td>Subpattern boundary
1.217 + * <td>Yes
1.218 + * <td>Separates positive and negative subpatterns
1.219 + * <tr valign=top bgcolor="#eeeeff">
1.220 + * <td><code>%</code>
1.221 + * <td>Prefix or suffix
1.222 + * <td>Yes
1.223 + * <td>Multiply by 100 and show as percentage
1.224 + * <tr valign=top>
1.225 + * <td><code>\u2030</code>
1.226 + * <td>Prefix or suffix
1.227 + * <td>Yes
1.228 + * <td>Multiply by 1000 and show as per mille value
1.229 + * <tr valign=top bgcolor="#eeeeff">
1.230 + * <td><code>¤</code> (<code>\u00A4</code>)
1.231 + * <td>Prefix or suffix
1.232 + * <td>No
1.233 + * <td>Currency sign, replaced by currency symbol. If
1.234 + * doubled, replaced by international currency symbol.
1.235 + * If present in a pattern, the monetary decimal separator
1.236 + * is used instead of the decimal separator.
1.237 + * <tr valign=top>
1.238 + * <td><code>'</code>
1.239 + * <td>Prefix or suffix
1.240 + * <td>No
1.241 + * <td>Used to quote special characters in a prefix or suffix,
1.242 + * for example, <code>"'#'#"</code> formats 123 to
1.243 + * <code>"#123"</code>. To create a single quote
1.244 + * itself, use two in a row: <code>"# o''clock"</code>.
1.245 + * </table>
1.246 + * </blockquote>
1.247 + *
1.248 + * <h4>Scientific Notation</h4>
1.249 + *
1.250 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
1.251 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
1.252 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
1.253 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
1.254 + * notation <em>only via a pattern</em>; there is currently no factory method
1.255 + * that creates a scientific notation format. In a pattern, the exponent
1.256 + * character immediately followed by one or more digit characters indicates
1.257 + * scientific notation. Example: <code>"0.###E0"</code> formats the number
1.258 + * 1234 as <code>"1.234E3"</code>.
1.259 + *
1.260 + * <ul>
1.261 + * <li>The number of digit characters after the exponent character gives the
1.262 + * minimum exponent digit count. There is no maximum. Negative exponents are
1.263 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
1.264 + * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
1.265 + *
1.266 + * <li>The minimum and maximum number of integer digits are interpreted
1.267 + * together:
1.268 + *
1.269 + * <ul>
1.270 + * <li>If the maximum number of integer digits is greater than their minimum number
1.271 + * and greater than 1, it forces the exponent to be a multiple of the maximum
1.272 + * number of integer digits, and the minimum number of integer digits to be
1.273 + * interpreted as 1. The most common use of this is to generate
1.274 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
1.275 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
1.276 + * formats to <code>"12.345E3"</code>, and 123456 formats to
1.277 + * <code>"123.456E3"</code>.
1.278 + *
1.279 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
1.280 + * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
1.281 + * <code>"12.3E-4"</code>.
1.282 + * </ul>
1.283 + *
1.284 + * <li>The number of significant digits in the mantissa is the sum of the
1.285 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
1.286 + * unaffected by the maximum integer digits. For example, 12345 formatted with
1.287 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
1.288 + * the significant digits count to zero. The number of significant digits
1.289 + * does not affect parsing.
1.290 + *
1.291 + * <li>Exponential patterns may not contain grouping separators.
1.292 + * </ul>
1.293 + *
1.294 + * <h4>Rounding</h4>
1.295 + *
1.296 + * <code>DecimalFormat</code> provides rounding modes defined in
1.297 + * {@link java.math.RoundingMode} for formatting. By default, it uses
1.298 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
1.299 + *
1.300 + * <h4>Digits</h4>
1.301 + *
1.302 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
1.303 + * characters starting with the localized zero digit defined in the
1.304 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
1.305 + * digits as well as all Unicode decimal digits, as defined by
1.306 + * {@link Character#digit Character.digit}, are recognized.
1.307 + *
1.308 + * <h4>Special Values</h4>
1.309 + *
1.310 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
1.311 + * <code>\uFFFD</code>. This string is determined by the
1.312 + * <code>DecimalFormatSymbols</code> object. This is the only value for which
1.313 + * the prefixes and suffixes are not used.
1.314 + *
1.315 + * <p>Infinity is formatted as a string, which typically has a single character
1.316 + * <code>\u221E</code>, with the positive or negative prefixes and suffixes
1.317 + * applied. The infinity string is determined by the
1.318 + * <code>DecimalFormatSymbols</code> object.
1.319 + *
1.320 + * <p>Negative zero (<code>"-0"</code>) parses to
1.321 + * <ul>
1.322 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
1.323 + * true,
1.324 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
1.325 + * and <code>isParseIntegerOnly()</code> is true,
1.326 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
1.327 + * and <code>isParseIntegerOnly()</code> are false.
1.328 + * </ul>
1.329 + *
1.330 + * <h4><a name="synchronization">Synchronization</a></h4>
1.331 + *
1.332 + * <p>
1.333 + * Decimal formats are generally not synchronized.
1.334 + * It is recommended to create separate format instances for each thread.
1.335 + * If multiple threads access a format concurrently, it must be synchronized
1.336 + * externally.
1.337 + *
1.338 + * <h4>Example</h4>
1.339 + *
1.340 + * <blockquote><pre>
1.341 + * <strong>// Print out a number using the localized number, integer, currency,
1.342 + * // and percent format for each locale</strong>
1.343 + * Locale[] locales = NumberFormat.getAvailableLocales();
1.344 + * double myNumber = -1234.56;
1.345 + * NumberFormat form;
1.346 + * for (int j=0; j<4; ++j) {
1.347 + * System.out.println("FORMAT");
1.348 + * for (int i = 0; i < locales.length; ++i) {
1.349 + * if (locales[i].getCountry().length() == 0) {
1.350 + * continue; // Skip language-only locales
1.351 + * }
1.352 + * System.out.print(locales[i].getDisplayName());
1.353 + * switch (j) {
1.354 + * case 0:
1.355 + * form = NumberFormat.getInstance(locales[i]); break;
1.356 + * case 1:
1.357 + * form = NumberFormat.getIntegerInstance(locales[i]); break;
1.358 + * case 2:
1.359 + * form = NumberFormat.getCurrencyInstance(locales[i]); break;
1.360 + * default:
1.361 + * form = NumberFormat.getPercentInstance(locales[i]); break;
1.362 + * }
1.363 + * if (form instanceof DecimalFormat) {
1.364 + * System.out.print(": " + ((DecimalFormat) form).toPattern());
1.365 + * }
1.366 + * System.out.print(" -> " + form.format(myNumber));
1.367 + * try {
1.368 + * System.out.println(" -> " + form.parse(form.format(myNumber)));
1.369 + * } catch (ParseException e) {}
1.370 + * }
1.371 + * }
1.372 + * </pre></blockquote>
1.373 + *
1.374 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
1.375 + * @see NumberFormat
1.376 + * @see DecimalFormatSymbols
1.377 + * @see ParsePosition
1.378 + * @author Mark Davis
1.379 + * @author Alan Liu
1.380 + */
1.381 +public class DecimalFormat extends NumberFormat {
1.382 +
1.383 + /**
1.384 + * Creates a DecimalFormat using the default pattern and symbols
1.385 + * for the default locale. This is a convenient way to obtain a
1.386 + * DecimalFormat when internationalization is not the main concern.
1.387 + * <p>
1.388 + * To obtain standard formats for a given locale, use the factory methods
1.389 + * on NumberFormat such as getNumberInstance. These factories will
1.390 + * return the most appropriate sub-class of NumberFormat for a given
1.391 + * locale.
1.392 + *
1.393 + * @see java.text.NumberFormat#getInstance
1.394 + * @see java.text.NumberFormat#getNumberInstance
1.395 + * @see java.text.NumberFormat#getCurrencyInstance
1.396 + * @see java.text.NumberFormat#getPercentInstance
1.397 + */
1.398 + public DecimalFormat() {
1.399 + Locale def = Locale.getDefault(Locale.Category.FORMAT);
1.400 + // try to get the pattern from the cache
1.401 + String pattern = cachedLocaleData.get(def);
1.402 + if (pattern == null) { /* cache miss */
1.403 + // Get the pattern for the default locale.
1.404 + ResourceBundle rb = LocaleData.getNumberFormatData(def);
1.405 + String[] all = rb.getStringArray("NumberPatterns");
1.406 + pattern = all[0];
1.407 + /* update cache */
1.408 + cachedLocaleData.putIfAbsent(def, pattern);
1.409 + }
1.410 +
1.411 + // Always applyPattern after the symbols are set
1.412 + this.symbols = new DecimalFormatSymbols(def);
1.413 + applyPattern(pattern, false);
1.414 + }
1.415 +
1.416 +
1.417 + /**
1.418 + * Creates a DecimalFormat using the given pattern and the symbols
1.419 + * for the default locale. This is a convenient way to obtain a
1.420 + * DecimalFormat when internationalization is not the main concern.
1.421 + * <p>
1.422 + * To obtain standard formats for a given locale, use the factory methods
1.423 + * on NumberFormat such as getNumberInstance. These factories will
1.424 + * return the most appropriate sub-class of NumberFormat for a given
1.425 + * locale.
1.426 + *
1.427 + * @param pattern A non-localized pattern string.
1.428 + * @exception NullPointerException if <code>pattern</code> is null
1.429 + * @exception IllegalArgumentException if the given pattern is invalid.
1.430 + * @see java.text.NumberFormat#getInstance
1.431 + * @see java.text.NumberFormat#getNumberInstance
1.432 + * @see java.text.NumberFormat#getCurrencyInstance
1.433 + * @see java.text.NumberFormat#getPercentInstance
1.434 + */
1.435 + public DecimalFormat(String pattern) {
1.436 + // Always applyPattern after the symbols are set
1.437 + this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
1.438 + applyPattern(pattern, false);
1.439 + }
1.440 +
1.441 +
1.442 + /**
1.443 + * Creates a DecimalFormat using the given pattern and symbols.
1.444 + * Use this constructor when you need to completely customize the
1.445 + * behavior of the format.
1.446 + * <p>
1.447 + * To obtain standard formats for a given
1.448 + * locale, use the factory methods on NumberFormat such as
1.449 + * getInstance or getCurrencyInstance. If you need only minor adjustments
1.450 + * to a standard format, you can modify the format returned by
1.451 + * a NumberFormat factory method.
1.452 + *
1.453 + * @param pattern a non-localized pattern string
1.454 + * @param symbols the set of symbols to be used
1.455 + * @exception NullPointerException if any of the given arguments is null
1.456 + * @exception IllegalArgumentException if the given pattern is invalid
1.457 + * @see java.text.NumberFormat#getInstance
1.458 + * @see java.text.NumberFormat#getNumberInstance
1.459 + * @see java.text.NumberFormat#getCurrencyInstance
1.460 + * @see java.text.NumberFormat#getPercentInstance
1.461 + * @see java.text.DecimalFormatSymbols
1.462 + */
1.463 + public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
1.464 + // Always applyPattern after the symbols are set
1.465 + this.symbols = (DecimalFormatSymbols)symbols.clone();
1.466 + applyPattern(pattern, false);
1.467 + }
1.468 +
1.469 +
1.470 + // Overrides
1.471 + /**
1.472 + * Formats a number and appends the resulting text to the given string
1.473 + * buffer.
1.474 + * The number can be of any subclass of {@link java.lang.Number}.
1.475 + * <p>
1.476 + * This implementation uses the maximum precision permitted.
1.477 + * @param number the number to format
1.478 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
1.479 + * text is to be appended
1.480 + * @param pos On input: an alignment field, if desired.
1.481 + * On output: the offsets of the alignment field.
1.482 + * @return the value passed in as <code>toAppendTo</code>
1.483 + * @exception IllegalArgumentException if <code>number</code> is
1.484 + * null or not an instance of <code>Number</code>.
1.485 + * @exception NullPointerException if <code>toAppendTo</code> or
1.486 + * <code>pos</code> is null
1.487 + * @exception ArithmeticException if rounding is needed with rounding
1.488 + * mode being set to RoundingMode.UNNECESSARY
1.489 + * @see java.text.FieldPosition
1.490 + */
1.491 + public final StringBuffer format(Object number,
1.492 + StringBuffer toAppendTo,
1.493 + FieldPosition pos) {
1.494 + if (number instanceof Long || number instanceof Integer ||
1.495 + number instanceof Short || number instanceof Byte ||
1.496 + number instanceof AtomicInteger ||
1.497 + number instanceof AtomicLong ||
1.498 + (number instanceof BigInteger &&
1.499 + ((BigInteger)number).bitLength () < 64)) {
1.500 + return format(((Number)number).longValue(), toAppendTo, pos);
1.501 + } else if (number instanceof BigDecimal) {
1.502 + return format((BigDecimal)number, toAppendTo, pos);
1.503 + } else if (number instanceof BigInteger) {
1.504 + return format((BigInteger)number, toAppendTo, pos);
1.505 + } else if (number instanceof Number) {
1.506 + return format(((Number)number).doubleValue(), toAppendTo, pos);
1.507 + } else {
1.508 + throw new IllegalArgumentException("Cannot format given Object as a Number");
1.509 + }
1.510 + }
1.511 +
1.512 + /**
1.513 + * Formats a double to produce a string.
1.514 + * @param number The double to format
1.515 + * @param result where the text is to be appended
1.516 + * @param fieldPosition On input: an alignment field, if desired.
1.517 + * On output: the offsets of the alignment field.
1.518 + * @exception ArithmeticException if rounding is needed with rounding
1.519 + * mode being set to RoundingMode.UNNECESSARY
1.520 + * @return The formatted number string
1.521 + * @see java.text.FieldPosition
1.522 + */
1.523 + public StringBuffer format(double number, StringBuffer result,
1.524 + FieldPosition fieldPosition) {
1.525 + fieldPosition.setBeginIndex(0);
1.526 + fieldPosition.setEndIndex(0);
1.527 +
1.528 + return format(number, result, fieldPosition.getFieldDelegate());
1.529 + }
1.530 +
1.531 + /**
1.532 + * Formats a double to produce a string.
1.533 + * @param number The double to format
1.534 + * @param result where the text is to be appended
1.535 + * @param delegate notified of locations of sub fields
1.536 + * @exception ArithmeticException if rounding is needed with rounding
1.537 + * mode being set to RoundingMode.UNNECESSARY
1.538 + * @return The formatted number string
1.539 + */
1.540 + private StringBuffer format(double number, StringBuffer result,
1.541 + FieldDelegate delegate) {
1.542 + if (Double.isNaN(number) ||
1.543 + (Double.isInfinite(number) && multiplier == 0)) {
1.544 + int iFieldStart = result.length();
1.545 + result.append(symbols.getNaN());
1.546 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
1.547 + iFieldStart, result.length(), result);
1.548 + return result;
1.549 + }
1.550 +
1.551 + /* Detecting whether a double is negative is easy with the exception of
1.552 + * the value -0.0. This is a double which has a zero mantissa (and
1.553 + * exponent), but a negative sign bit. It is semantically distinct from
1.554 + * a zero with a positive sign bit, and this distinction is important
1.555 + * to certain kinds of computations. However, it's a little tricky to
1.556 + * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
1.557 + * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
1.558 + * -Infinity. Proper detection of -0.0 is needed to deal with the
1.559 + * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
1.560 + */
1.561 + boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
1.562 +
1.563 + if (multiplier != 1) {
1.564 + number *= multiplier;
1.565 + }
1.566 +
1.567 + if (Double.isInfinite(number)) {
1.568 + if (isNegative) {
1.569 + append(result, negativePrefix, delegate,
1.570 + getNegativePrefixFieldPositions(), Field.SIGN);
1.571 + } else {
1.572 + append(result, positivePrefix, delegate,
1.573 + getPositivePrefixFieldPositions(), Field.SIGN);
1.574 + }
1.575 +
1.576 + int iFieldStart = result.length();
1.577 + result.append(symbols.getInfinity());
1.578 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
1.579 + iFieldStart, result.length(), result);
1.580 +
1.581 + if (isNegative) {
1.582 + append(result, negativeSuffix, delegate,
1.583 + getNegativeSuffixFieldPositions(), Field.SIGN);
1.584 + } else {
1.585 + append(result, positiveSuffix, delegate,
1.586 + getPositiveSuffixFieldPositions(), Field.SIGN);
1.587 + }
1.588 +
1.589 + return result;
1.590 + }
1.591 +
1.592 + if (isNegative) {
1.593 + number = -number;
1.594 + }
1.595 +
1.596 + // at this point we are guaranteed a nonnegative finite number.
1.597 + assert(number >= 0 && !Double.isInfinite(number));
1.598 +
1.599 + synchronized(digitList) {
1.600 + int maxIntDigits = super.getMaximumIntegerDigits();
1.601 + int minIntDigits = super.getMinimumIntegerDigits();
1.602 + int maxFraDigits = super.getMaximumFractionDigits();
1.603 + int minFraDigits = super.getMinimumFractionDigits();
1.604 +
1.605 + digitList.set(isNegative, number, useExponentialNotation ?
1.606 + maxIntDigits + maxFraDigits : maxFraDigits,
1.607 + !useExponentialNotation);
1.608 + return subformat(result, delegate, isNegative, false,
1.609 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
1.610 + }
1.611 + }
1.612 +
1.613 + /**
1.614 + * Format a long to produce a string.
1.615 + * @param number The long to format
1.616 + * @param result where the text is to be appended
1.617 + * @param fieldPosition On input: an alignment field, if desired.
1.618 + * On output: the offsets of the alignment field.
1.619 + * @exception ArithmeticException if rounding is needed with rounding
1.620 + * mode being set to RoundingMode.UNNECESSARY
1.621 + * @return The formatted number string
1.622 + * @see java.text.FieldPosition
1.623 + */
1.624 + public StringBuffer format(long number, StringBuffer result,
1.625 + FieldPosition fieldPosition) {
1.626 + fieldPosition.setBeginIndex(0);
1.627 + fieldPosition.setEndIndex(0);
1.628 +
1.629 + return format(number, result, fieldPosition.getFieldDelegate());
1.630 + }
1.631 +
1.632 + /**
1.633 + * Format a long to produce a string.
1.634 + * @param number The long to format
1.635 + * @param result where the text is to be appended
1.636 + * @param delegate notified of locations of sub fields
1.637 + * @return The formatted number string
1.638 + * @exception ArithmeticException if rounding is needed with rounding
1.639 + * mode being set to RoundingMode.UNNECESSARY
1.640 + * @see java.text.FieldPosition
1.641 + */
1.642 + private StringBuffer format(long number, StringBuffer result,
1.643 + FieldDelegate delegate) {
1.644 + boolean isNegative = (number < 0);
1.645 + if (isNegative) {
1.646 + number = -number;
1.647 + }
1.648 +
1.649 + // In general, long values always represent real finite numbers, so
1.650 + // we don't have to check for +/- Infinity or NaN. However, there
1.651 + // is one case we have to be careful of: The multiplier can push
1.652 + // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
1.653 + // check for this before multiplying, and if it happens we use
1.654 + // BigInteger instead.
1.655 + boolean useBigInteger = false;
1.656 + if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
1.657 + if (multiplier != 0) {
1.658 + useBigInteger = true;
1.659 + }
1.660 + } else if (multiplier != 1 && multiplier != 0) {
1.661 + long cutoff = Long.MAX_VALUE / multiplier;
1.662 + if (cutoff < 0) {
1.663 + cutoff = -cutoff;
1.664 + }
1.665 + useBigInteger = (number > cutoff);
1.666 + }
1.667 +
1.668 + if (useBigInteger) {
1.669 + if (isNegative) {
1.670 + number = -number;
1.671 + }
1.672 + BigInteger bigIntegerValue = BigInteger.valueOf(number);
1.673 + return format(bigIntegerValue, result, delegate, true);
1.674 + }
1.675 +
1.676 + number *= multiplier;
1.677 + if (number == 0) {
1.678 + isNegative = false;
1.679 + } else {
1.680 + if (multiplier < 0) {
1.681 + number = -number;
1.682 + isNegative = !isNegative;
1.683 + }
1.684 + }
1.685 +
1.686 + synchronized(digitList) {
1.687 + int maxIntDigits = super.getMaximumIntegerDigits();
1.688 + int minIntDigits = super.getMinimumIntegerDigits();
1.689 + int maxFraDigits = super.getMaximumFractionDigits();
1.690 + int minFraDigits = super.getMinimumFractionDigits();
1.691 +
1.692 + digitList.set(isNegative, number,
1.693 + useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
1.694 +
1.695 + return subformat(result, delegate, isNegative, true,
1.696 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
1.697 + }
1.698 + }
1.699 +
1.700 + /**
1.701 + * Formats a BigDecimal to produce a string.
1.702 + * @param number The BigDecimal to format
1.703 + * @param result where the text is to be appended
1.704 + * @param fieldPosition On input: an alignment field, if desired.
1.705 + * On output: the offsets of the alignment field.
1.706 + * @return The formatted number string
1.707 + * @exception ArithmeticException if rounding is needed with rounding
1.708 + * mode being set to RoundingMode.UNNECESSARY
1.709 + * @see java.text.FieldPosition
1.710 + */
1.711 + private StringBuffer format(BigDecimal number, StringBuffer result,
1.712 + FieldPosition fieldPosition) {
1.713 + fieldPosition.setBeginIndex(0);
1.714 + fieldPosition.setEndIndex(0);
1.715 + return format(number, result, fieldPosition.getFieldDelegate());
1.716 + }
1.717 +
1.718 + /**
1.719 + * Formats a BigDecimal to produce a string.
1.720 + * @param number The BigDecimal to format
1.721 + * @param result where the text is to be appended
1.722 + * @param delegate notified of locations of sub fields
1.723 + * @exception ArithmeticException if rounding is needed with rounding
1.724 + * mode being set to RoundingMode.UNNECESSARY
1.725 + * @return The formatted number string
1.726 + */
1.727 + private StringBuffer format(BigDecimal number, StringBuffer result,
1.728 + FieldDelegate delegate) {
1.729 + if (multiplier != 1) {
1.730 + number = number.multiply(getBigDecimalMultiplier());
1.731 + }
1.732 + boolean isNegative = number.signum() == -1;
1.733 + if (isNegative) {
1.734 + number = number.negate();
1.735 + }
1.736 +
1.737 + synchronized(digitList) {
1.738 + int maxIntDigits = getMaximumIntegerDigits();
1.739 + int minIntDigits = getMinimumIntegerDigits();
1.740 + int maxFraDigits = getMaximumFractionDigits();
1.741 + int minFraDigits = getMinimumFractionDigits();
1.742 + int maximumDigits = maxIntDigits + maxFraDigits;
1.743 +
1.744 + digitList.set(isNegative, number, useExponentialNotation ?
1.745 + ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
1.746 + maxFraDigits, !useExponentialNotation);
1.747 +
1.748 + return subformat(result, delegate, isNegative, false,
1.749 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
1.750 + }
1.751 + }
1.752 +
1.753 + /**
1.754 + * Format a BigInteger to produce a string.
1.755 + * @param number The BigInteger to format
1.756 + * @param result where the text is to be appended
1.757 + * @param fieldPosition On input: an alignment field, if desired.
1.758 + * On output: the offsets of the alignment field.
1.759 + * @return The formatted number string
1.760 + * @exception ArithmeticException if rounding is needed with rounding
1.761 + * mode being set to RoundingMode.UNNECESSARY
1.762 + * @see java.text.FieldPosition
1.763 + */
1.764 + private StringBuffer format(BigInteger number, StringBuffer result,
1.765 + FieldPosition fieldPosition) {
1.766 + fieldPosition.setBeginIndex(0);
1.767 + fieldPosition.setEndIndex(0);
1.768 +
1.769 + return format(number, result, fieldPosition.getFieldDelegate(), false);
1.770 + }
1.771 +
1.772 + /**
1.773 + * Format a BigInteger to produce a string.
1.774 + * @param number The BigInteger to format
1.775 + * @param result where the text is to be appended
1.776 + * @param delegate notified of locations of sub fields
1.777 + * @return The formatted number string
1.778 + * @exception ArithmeticException if rounding is needed with rounding
1.779 + * mode being set to RoundingMode.UNNECESSARY
1.780 + * @see java.text.FieldPosition
1.781 + */
1.782 + private StringBuffer format(BigInteger number, StringBuffer result,
1.783 + FieldDelegate delegate, boolean formatLong) {
1.784 + if (multiplier != 1) {
1.785 + number = number.multiply(getBigIntegerMultiplier());
1.786 + }
1.787 + boolean isNegative = number.signum() == -1;
1.788 + if (isNegative) {
1.789 + number = number.negate();
1.790 + }
1.791 +
1.792 + synchronized(digitList) {
1.793 + int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
1.794 + if (formatLong) {
1.795 + maxIntDigits = super.getMaximumIntegerDigits();
1.796 + minIntDigits = super.getMinimumIntegerDigits();
1.797 + maxFraDigits = super.getMaximumFractionDigits();
1.798 + minFraDigits = super.getMinimumFractionDigits();
1.799 + maximumDigits = maxIntDigits + maxFraDigits;
1.800 + } else {
1.801 + maxIntDigits = getMaximumIntegerDigits();
1.802 + minIntDigits = getMinimumIntegerDigits();
1.803 + maxFraDigits = getMaximumFractionDigits();
1.804 + minFraDigits = getMinimumFractionDigits();
1.805 + maximumDigits = maxIntDigits + maxFraDigits;
1.806 + if (maximumDigits < 0) {
1.807 + maximumDigits = Integer.MAX_VALUE;
1.808 + }
1.809 + }
1.810 +
1.811 + digitList.set(isNegative, number,
1.812 + useExponentialNotation ? maximumDigits : 0);
1.813 +
1.814 + return subformat(result, delegate, isNegative, true,
1.815 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
1.816 + }
1.817 + }
1.818 +
1.819 + /**
1.820 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
1.821 + * You can use the returned <code>AttributedCharacterIterator</code>
1.822 + * to build the resulting String, as well as to determine information
1.823 + * about the resulting String.
1.824 + * <p>
1.825 + * Each attribute key of the AttributedCharacterIterator will be of type
1.826 + * <code>NumberFormat.Field</code>, with the attribute value being the
1.827 + * same as the attribute key.
1.828 + *
1.829 + * @exception NullPointerException if obj is null.
1.830 + * @exception IllegalArgumentException when the Format cannot format the
1.831 + * given object.
1.832 + * @exception ArithmeticException if rounding is needed with rounding
1.833 + * mode being set to RoundingMode.UNNECESSARY
1.834 + * @param obj The object to format
1.835 + * @return AttributedCharacterIterator describing the formatted value.
1.836 + * @since 1.4
1.837 + */
1.838 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
1.839 + CharacterIteratorFieldDelegate delegate =
1.840 + new CharacterIteratorFieldDelegate();
1.841 + StringBuffer sb = new StringBuffer();
1.842 +
1.843 + if (obj instanceof Double || obj instanceof Float) {
1.844 + format(((Number)obj).doubleValue(), sb, delegate);
1.845 + } else if (obj instanceof Long || obj instanceof Integer ||
1.846 + obj instanceof Short || obj instanceof Byte ||
1.847 + obj instanceof AtomicInteger || obj instanceof AtomicLong) {
1.848 + format(((Number)obj).longValue(), sb, delegate);
1.849 + } else if (obj instanceof BigDecimal) {
1.850 + format((BigDecimal)obj, sb, delegate);
1.851 + } else if (obj instanceof BigInteger) {
1.852 + format((BigInteger)obj, sb, delegate, false);
1.853 + } else if (obj == null) {
1.854 + throw new NullPointerException(
1.855 + "formatToCharacterIterator must be passed non-null object");
1.856 + } else {
1.857 + throw new IllegalArgumentException(
1.858 + "Cannot format given Object as a Number");
1.859 + }
1.860 + return delegate.getIterator(sb.toString());
1.861 + }
1.862 +
1.863 + /**
1.864 + * Complete the formatting of a finite number. On entry, the digitList must
1.865 + * be filled in with the correct digits.
1.866 + */
1.867 + private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
1.868 + boolean isNegative, boolean isInteger,
1.869 + int maxIntDigits, int minIntDigits,
1.870 + int maxFraDigits, int minFraDigits) {
1.871 + // NOTE: This isn't required anymore because DigitList takes care of this.
1.872 + //
1.873 + // // The negative of the exponent represents the number of leading
1.874 + // // zeros between the decimal and the first non-zero digit, for
1.875 + // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
1.876 + // // is more than the maximum fraction digits, then we have an underflow
1.877 + // // for the printed representation. We recognize this here and set
1.878 + // // the DigitList representation to zero in this situation.
1.879 + //
1.880 + // if (-digitList.decimalAt >= getMaximumFractionDigits())
1.881 + // {
1.882 + // digitList.count = 0;
1.883 + // }
1.884 +
1.885 + char zero = symbols.getZeroDigit();
1.886 + int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
1.887 + char grouping = symbols.getGroupingSeparator();
1.888 + char decimal = isCurrencyFormat ?
1.889 + symbols.getMonetaryDecimalSeparator() :
1.890 + symbols.getDecimalSeparator();
1.891 +
1.892 + /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
1.893 + * format as zero. This allows sensible computations and preserves
1.894 + * relations such as signum(1/x) = signum(x), where x is +Infinity or
1.895 + * -Infinity. Prior to this fix, we always formatted zero values as if
1.896 + * they were positive. Liu 7/6/98.
1.897 + */
1.898 + if (digitList.isZero()) {
1.899 + digitList.decimalAt = 0; // Normalize
1.900 + }
1.901 +
1.902 + if (isNegative) {
1.903 + append(result, negativePrefix, delegate,
1.904 + getNegativePrefixFieldPositions(), Field.SIGN);
1.905 + } else {
1.906 + append(result, positivePrefix, delegate,
1.907 + getPositivePrefixFieldPositions(), Field.SIGN);
1.908 + }
1.909 +
1.910 + if (useExponentialNotation) {
1.911 + int iFieldStart = result.length();
1.912 + int iFieldEnd = -1;
1.913 + int fFieldStart = -1;
1.914 +
1.915 + // Minimum integer digits are handled in exponential format by
1.916 + // adjusting the exponent. For example, 0.01234 with 3 minimum
1.917 + // integer digits is "123.4E-4".
1.918 +
1.919 + // Maximum integer digits are interpreted as indicating the
1.920 + // repeating range. This is useful for engineering notation, in
1.921 + // which the exponent is restricted to a multiple of 3. For
1.922 + // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
1.923 + // If maximum integer digits are > 1 and are larger than
1.924 + // minimum integer digits, then minimum integer digits are
1.925 + // ignored.
1.926 + int exponent = digitList.decimalAt;
1.927 + int repeat = maxIntDigits;
1.928 + int minimumIntegerDigits = minIntDigits;
1.929 + if (repeat > 1 && repeat > minIntDigits) {
1.930 + // A repeating range is defined; adjust to it as follows.
1.931 + // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
1.932 + // -3,-4,-5=>-6, etc. This takes into account that the
1.933 + // exponent we have here is off by one from what we expect;
1.934 + // it is for the format 0.MMMMMx10^n.
1.935 + if (exponent >= 1) {
1.936 + exponent = ((exponent - 1) / repeat) * repeat;
1.937 + } else {
1.938 + // integer division rounds towards 0
1.939 + exponent = ((exponent - repeat) / repeat) * repeat;
1.940 + }
1.941 + minimumIntegerDigits = 1;
1.942 + } else {
1.943 + // No repeating range is defined; use minimum integer digits.
1.944 + exponent -= minimumIntegerDigits;
1.945 + }
1.946 +
1.947 + // We now output a minimum number of digits, and more if there
1.948 + // are more digits, up to the maximum number of digits. We
1.949 + // place the decimal point after the "integer" digits, which
1.950 + // are the first (decimalAt - exponent) digits.
1.951 + int minimumDigits = minIntDigits + minFraDigits;
1.952 + if (minimumDigits < 0) { // overflow?
1.953 + minimumDigits = Integer.MAX_VALUE;
1.954 + }
1.955 +
1.956 + // The number of integer digits is handled specially if the number
1.957 + // is zero, since then there may be no digits.
1.958 + int integerDigits = digitList.isZero() ? minimumIntegerDigits :
1.959 + digitList.decimalAt - exponent;
1.960 + if (minimumDigits < integerDigits) {
1.961 + minimumDigits = integerDigits;
1.962 + }
1.963 + int totalDigits = digitList.count;
1.964 + if (minimumDigits > totalDigits) {
1.965 + totalDigits = minimumDigits;
1.966 + }
1.967 + boolean addedDecimalSeparator = false;
1.968 +
1.969 + for (int i=0; i<totalDigits; ++i) {
1.970 + if (i == integerDigits) {
1.971 + // Record field information for caller.
1.972 + iFieldEnd = result.length();
1.973 +
1.974 + result.append(decimal);
1.975 + addedDecimalSeparator = true;
1.976 +
1.977 + // Record field information for caller.
1.978 + fFieldStart = result.length();
1.979 + }
1.980 + result.append((i < digitList.count) ?
1.981 + (char)(digitList.digits[i] + zeroDelta) :
1.982 + zero);
1.983 + }
1.984 +
1.985 + if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
1.986 + // Record field information for caller.
1.987 + iFieldEnd = result.length();
1.988 +
1.989 + result.append(decimal);
1.990 + addedDecimalSeparator = true;
1.991 +
1.992 + // Record field information for caller.
1.993 + fFieldStart = result.length();
1.994 + }
1.995 +
1.996 + // Record field information
1.997 + if (iFieldEnd == -1) {
1.998 + iFieldEnd = result.length();
1.999 + }
1.1000 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
1.1001 + iFieldStart, iFieldEnd, result);
1.1002 + if (addedDecimalSeparator) {
1.1003 + delegate.formatted(Field.DECIMAL_SEPARATOR,
1.1004 + Field.DECIMAL_SEPARATOR,
1.1005 + iFieldEnd, fFieldStart, result);
1.1006 + }
1.1007 + if (fFieldStart == -1) {
1.1008 + fFieldStart = result.length();
1.1009 + }
1.1010 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
1.1011 + fFieldStart, result.length(), result);
1.1012 +
1.1013 + // The exponent is output using the pattern-specified minimum
1.1014 + // exponent digits. There is no maximum limit to the exponent
1.1015 + // digits, since truncating the exponent would result in an
1.1016 + // unacceptable inaccuracy.
1.1017 + int fieldStart = result.length();
1.1018 +
1.1019 + result.append(symbols.getExponentSeparator());
1.1020 +
1.1021 + delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
1.1022 + fieldStart, result.length(), result);
1.1023 +
1.1024 + // For zero values, we force the exponent to zero. We
1.1025 + // must do this here, and not earlier, because the value
1.1026 + // is used to determine integer digit count above.
1.1027 + if (digitList.isZero()) {
1.1028 + exponent = 0;
1.1029 + }
1.1030 +
1.1031 + boolean negativeExponent = exponent < 0;
1.1032 + if (negativeExponent) {
1.1033 + exponent = -exponent;
1.1034 + fieldStart = result.length();
1.1035 + result.append(symbols.getMinusSign());
1.1036 + delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
1.1037 + fieldStart, result.length(), result);
1.1038 + }
1.1039 + digitList.set(negativeExponent, exponent);
1.1040 +
1.1041 + int eFieldStart = result.length();
1.1042 +
1.1043 + for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
1.1044 + result.append(zero);
1.1045 + }
1.1046 + for (int i=0; i<digitList.decimalAt; ++i) {
1.1047 + result.append((i < digitList.count) ?
1.1048 + (char)(digitList.digits[i] + zeroDelta) : zero);
1.1049 + }
1.1050 + delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
1.1051 + result.length(), result);
1.1052 + } else {
1.1053 + int iFieldStart = result.length();
1.1054 +
1.1055 + // Output the integer portion. Here 'count' is the total
1.1056 + // number of integer digits we will display, including both
1.1057 + // leading zeros required to satisfy getMinimumIntegerDigits,
1.1058 + // and actual digits present in the number.
1.1059 + int count = minIntDigits;
1.1060 + int digitIndex = 0; // Index into digitList.fDigits[]
1.1061 + if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
1.1062 + count = digitList.decimalAt;
1.1063 + }
1.1064 +
1.1065 + // Handle the case where getMaximumIntegerDigits() is smaller
1.1066 + // than the real number of integer digits. If this is so, we
1.1067 + // output the least significant max integer digits. For example,
1.1068 + // the value 1997 printed with 2 max integer digits is just "97".
1.1069 + if (count > maxIntDigits) {
1.1070 + count = maxIntDigits;
1.1071 + digitIndex = digitList.decimalAt - count;
1.1072 + }
1.1073 +
1.1074 + int sizeBeforeIntegerPart = result.length();
1.1075 + for (int i=count-1; i>=0; --i) {
1.1076 + if (i < digitList.decimalAt && digitIndex < digitList.count) {
1.1077 + // Output a real digit
1.1078 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
1.1079 + } else {
1.1080 + // Output a leading zero
1.1081 + result.append(zero);
1.1082 + }
1.1083 +
1.1084 + // Output grouping separator if necessary. Don't output a
1.1085 + // grouping separator if i==0 though; that's at the end of
1.1086 + // the integer part.
1.1087 + if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
1.1088 + (i % groupingSize == 0)) {
1.1089 + int gStart = result.length();
1.1090 + result.append(grouping);
1.1091 + delegate.formatted(Field.GROUPING_SEPARATOR,
1.1092 + Field.GROUPING_SEPARATOR, gStart,
1.1093 + result.length(), result);
1.1094 + }
1.1095 + }
1.1096 +
1.1097 + // Determine whether or not there are any printable fractional
1.1098 + // digits. If we've used up the digits we know there aren't.
1.1099 + boolean fractionPresent = (minFraDigits > 0) ||
1.1100 + (!isInteger && digitIndex < digitList.count);
1.1101 +
1.1102 + // If there is no fraction present, and we haven't printed any
1.1103 + // integer digits, then print a zero. Otherwise we won't print
1.1104 + // _any_ digits, and we won't be able to parse this string.
1.1105 + if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
1.1106 + result.append(zero);
1.1107 + }
1.1108 +
1.1109 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
1.1110 + iFieldStart, result.length(), result);
1.1111 +
1.1112 + // Output the decimal separator if we always do so.
1.1113 + int sStart = result.length();
1.1114 + if (decimalSeparatorAlwaysShown || fractionPresent) {
1.1115 + result.append(decimal);
1.1116 + }
1.1117 +
1.1118 + if (sStart != result.length()) {
1.1119 + delegate.formatted(Field.DECIMAL_SEPARATOR,
1.1120 + Field.DECIMAL_SEPARATOR,
1.1121 + sStart, result.length(), result);
1.1122 + }
1.1123 + int fFieldStart = result.length();
1.1124 +
1.1125 + for (int i=0; i < maxFraDigits; ++i) {
1.1126 + // Here is where we escape from the loop. We escape if we've
1.1127 + // output the maximum fraction digits (specified in the for
1.1128 + // expression above).
1.1129 + // We also stop when we've output the minimum digits and either:
1.1130 + // we have an integer, so there is no fractional stuff to
1.1131 + // display, or we're out of significant digits.
1.1132 + if (i >= minFraDigits &&
1.1133 + (isInteger || digitIndex >= digitList.count)) {
1.1134 + break;
1.1135 + }
1.1136 +
1.1137 + // Output leading fractional zeros. These are zeros that come
1.1138 + // after the decimal but before any significant digits. These
1.1139 + // are only output if abs(number being formatted) < 1.0.
1.1140 + if (-1-i > (digitList.decimalAt-1)) {
1.1141 + result.append(zero);
1.1142 + continue;
1.1143 + }
1.1144 +
1.1145 + // Output a digit, if we have any precision left, or a
1.1146 + // zero if we don't. We don't want to output noise digits.
1.1147 + if (!isInteger && digitIndex < digitList.count) {
1.1148 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
1.1149 + } else {
1.1150 + result.append(zero);
1.1151 + }
1.1152 + }
1.1153 +
1.1154 + // Record field information for caller.
1.1155 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
1.1156 + fFieldStart, result.length(), result);
1.1157 + }
1.1158 +
1.1159 + if (isNegative) {
1.1160 + append(result, negativeSuffix, delegate,
1.1161 + getNegativeSuffixFieldPositions(), Field.SIGN);
1.1162 + }
1.1163 + else {
1.1164 + append(result, positiveSuffix, delegate,
1.1165 + getPositiveSuffixFieldPositions(), Field.SIGN);
1.1166 + }
1.1167 +
1.1168 + return result;
1.1169 + }
1.1170 +
1.1171 + /**
1.1172 + * Appends the String <code>string</code> to <code>result</code>.
1.1173 + * <code>delegate</code> is notified of all the
1.1174 + * <code>FieldPosition</code>s in <code>positions</code>.
1.1175 + * <p>
1.1176 + * If one of the <code>FieldPosition</code>s in <code>positions</code>
1.1177 + * identifies a <code>SIGN</code> attribute, it is mapped to
1.1178 + * <code>signAttribute</code>. This is used
1.1179 + * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
1.1180 + * attribute as necessary.
1.1181 + * <p>
1.1182 + * This is used by <code>subformat</code> to add the prefix/suffix.
1.1183 + */
1.1184 + private void append(StringBuffer result, String string,
1.1185 + FieldDelegate delegate,
1.1186 + FieldPosition[] positions,
1.1187 + Format.Field signAttribute) {
1.1188 + int start = result.length();
1.1189 +
1.1190 + if (string.length() > 0) {
1.1191 + result.append(string);
1.1192 + for (int counter = 0, max = positions.length; counter < max;
1.1193 + counter++) {
1.1194 + FieldPosition fp = positions[counter];
1.1195 + Format.Field attribute = fp.getFieldAttribute();
1.1196 +
1.1197 + if (attribute == Field.SIGN) {
1.1198 + attribute = signAttribute;
1.1199 + }
1.1200 + delegate.formatted(attribute, attribute,
1.1201 + start + fp.getBeginIndex(),
1.1202 + start + fp.getEndIndex(), result);
1.1203 + }
1.1204 + }
1.1205 + }
1.1206 +
1.1207 + /**
1.1208 + * Parses text from a string to produce a <code>Number</code>.
1.1209 + * <p>
1.1210 + * The method attempts to parse text starting at the index given by
1.1211 + * <code>pos</code>.
1.1212 + * If parsing succeeds, then the index of <code>pos</code> is updated
1.1213 + * to the index after the last character used (parsing does not necessarily
1.1214 + * use all characters up to the end of the string), and the parsed
1.1215 + * number is returned. The updated <code>pos</code> can be used to
1.1216 + * indicate the starting point for the next call to this method.
1.1217 + * If an error occurs, then the index of <code>pos</code> is not
1.1218 + * changed, the error index of <code>pos</code> is set to the index of
1.1219 + * the character where the error occurred, and null is returned.
1.1220 + * <p>
1.1221 + * The subclass returned depends on the value of {@link #isParseBigDecimal}
1.1222 + * as well as on the string being parsed.
1.1223 + * <ul>
1.1224 + * <li>If <code>isParseBigDecimal()</code> is false (the default),
1.1225 + * most integer values are returned as <code>Long</code>
1.1226 + * objects, no matter how they are written: <code>"17"</code> and
1.1227 + * <code>"17.000"</code> both parse to <code>Long(17)</code>.
1.1228 + * Values that cannot fit into a <code>Long</code> are returned as
1.1229 + * <code>Double</code>s. This includes values with a fractional part,
1.1230 + * infinite values, <code>NaN</code>, and the value -0.0.
1.1231 + * <code>DecimalFormat</code> does <em>not</em> decide whether to
1.1232 + * return a <code>Double</code> or a <code>Long</code> based on the
1.1233 + * presence of a decimal separator in the source string. Doing so
1.1234 + * would prevent integers that overflow the mantissa of a double,
1.1235 + * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
1.1236 + * parsed accurately.
1.1237 + * <p>
1.1238 + * Callers may use the <code>Number</code> methods
1.1239 + * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
1.1240 + * the type they want.
1.1241 + * <li>If <code>isParseBigDecimal()</code> is true, values are returned
1.1242 + * as <code>BigDecimal</code> objects. The values are the ones
1.1243 + * constructed by {@link java.math.BigDecimal#BigDecimal(String)}
1.1244 + * for corresponding strings in locale-independent format. The
1.1245 + * special cases negative and positive infinity and NaN are returned
1.1246 + * as <code>Double</code> instances holding the values of the
1.1247 + * corresponding <code>Double</code> constants.
1.1248 + * </ul>
1.1249 + * <p>
1.1250 + * <code>DecimalFormat</code> parses all Unicode characters that represent
1.1251 + * decimal digits, as defined by <code>Character.digit()</code>. In
1.1252 + * addition, <code>DecimalFormat</code> also recognizes as digits the ten
1.1253 + * consecutive characters starting with the localized zero digit defined in
1.1254 + * the <code>DecimalFormatSymbols</code> object.
1.1255 + *
1.1256 + * @param text the string to be parsed
1.1257 + * @param pos A <code>ParsePosition</code> object with index and error
1.1258 + * index information as described above.
1.1259 + * @return the parsed value, or <code>null</code> if the parse fails
1.1260 + * @exception NullPointerException if <code>text</code> or
1.1261 + * <code>pos</code> is null.
1.1262 + */
1.1263 + public Number parse(String text, ParsePosition pos) {
1.1264 + // special case NaN
1.1265 + if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
1.1266 + pos.index = pos.index + symbols.getNaN().length();
1.1267 + return new Double(Double.NaN);
1.1268 + }
1.1269 +
1.1270 + boolean[] status = new boolean[STATUS_LENGTH];
1.1271 + if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
1.1272 + return null;
1.1273 + }
1.1274 +
1.1275 + // special case INFINITY
1.1276 + if (status[STATUS_INFINITE]) {
1.1277 + if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
1.1278 + return new Double(Double.POSITIVE_INFINITY);
1.1279 + } else {
1.1280 + return new Double(Double.NEGATIVE_INFINITY);
1.1281 + }
1.1282 + }
1.1283 +
1.1284 + if (multiplier == 0) {
1.1285 + if (digitList.isZero()) {
1.1286 + return new Double(Double.NaN);
1.1287 + } else if (status[STATUS_POSITIVE]) {
1.1288 + return new Double(Double.POSITIVE_INFINITY);
1.1289 + } else {
1.1290 + return new Double(Double.NEGATIVE_INFINITY);
1.1291 + }
1.1292 + }
1.1293 +
1.1294 + if (isParseBigDecimal()) {
1.1295 + BigDecimal bigDecimalResult = digitList.getBigDecimal();
1.1296 +
1.1297 + if (multiplier != 1) {
1.1298 + try {
1.1299 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
1.1300 + }
1.1301 + catch (ArithmeticException e) { // non-terminating decimal expansion
1.1302 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
1.1303 + }
1.1304 + }
1.1305 +
1.1306 + if (!status[STATUS_POSITIVE]) {
1.1307 + bigDecimalResult = bigDecimalResult.negate();
1.1308 + }
1.1309 + return bigDecimalResult;
1.1310 + } else {
1.1311 + boolean gotDouble = true;
1.1312 + boolean gotLongMinimum = false;
1.1313 + double doubleResult = 0.0;
1.1314 + long longResult = 0;
1.1315 +
1.1316 + // Finally, have DigitList parse the digits into a value.
1.1317 + if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
1.1318 + gotDouble = false;
1.1319 + longResult = digitList.getLong();
1.1320 + if (longResult < 0) { // got Long.MIN_VALUE
1.1321 + gotLongMinimum = true;
1.1322 + }
1.1323 + } else {
1.1324 + doubleResult = digitList.getDouble();
1.1325 + }
1.1326 +
1.1327 + // Divide by multiplier. We have to be careful here not to do
1.1328 + // unneeded conversions between double and long.
1.1329 + if (multiplier != 1) {
1.1330 + if (gotDouble) {
1.1331 + doubleResult /= multiplier;
1.1332 + } else {
1.1333 + // Avoid converting to double if we can
1.1334 + if (longResult % multiplier == 0) {
1.1335 + longResult /= multiplier;
1.1336 + } else {
1.1337 + doubleResult = ((double)longResult) / multiplier;
1.1338 + gotDouble = true;
1.1339 + }
1.1340 + }
1.1341 + }
1.1342 +
1.1343 + if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
1.1344 + doubleResult = -doubleResult;
1.1345 + longResult = -longResult;
1.1346 + }
1.1347 +
1.1348 + // At this point, if we divided the result by the multiplier, the
1.1349 + // result may fit into a long. We check for this case and return
1.1350 + // a long if possible.
1.1351 + // We must do this AFTER applying the negative (if appropriate)
1.1352 + // in order to handle the case of LONG_MIN; otherwise, if we do
1.1353 + // this with a positive value -LONG_MIN, the double is > 0, but
1.1354 + // the long is < 0. We also must retain a double in the case of
1.1355 + // -0.0, which will compare as == to a long 0 cast to a double
1.1356 + // (bug 4162852).
1.1357 + if (multiplier != 1 && gotDouble) {
1.1358 + longResult = (long)doubleResult;
1.1359 + gotDouble = ((doubleResult != (double)longResult) ||
1.1360 + (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
1.1361 + !isParseIntegerOnly();
1.1362 + }
1.1363 +
1.1364 + return gotDouble ?
1.1365 + (Number)new Double(doubleResult) : (Number)new Long(longResult);
1.1366 + }
1.1367 + }
1.1368 +
1.1369 + /**
1.1370 + * Return a BigInteger multiplier.
1.1371 + */
1.1372 + private BigInteger getBigIntegerMultiplier() {
1.1373 + if (bigIntegerMultiplier == null) {
1.1374 + bigIntegerMultiplier = BigInteger.valueOf(multiplier);
1.1375 + }
1.1376 + return bigIntegerMultiplier;
1.1377 + }
1.1378 + private transient BigInteger bigIntegerMultiplier;
1.1379 +
1.1380 + /**
1.1381 + * Return a BigDecimal multiplier.
1.1382 + */
1.1383 + private BigDecimal getBigDecimalMultiplier() {
1.1384 + if (bigDecimalMultiplier == null) {
1.1385 + bigDecimalMultiplier = new BigDecimal(multiplier);
1.1386 + }
1.1387 + return bigDecimalMultiplier;
1.1388 + }
1.1389 + private transient BigDecimal bigDecimalMultiplier;
1.1390 +
1.1391 + private static final int STATUS_INFINITE = 0;
1.1392 + private static final int STATUS_POSITIVE = 1;
1.1393 + private static final int STATUS_LENGTH = 2;
1.1394 +
1.1395 + /**
1.1396 + * Parse the given text into a number. The text is parsed beginning at
1.1397 + * parsePosition, until an unparseable character is seen.
1.1398 + * @param text The string to parse.
1.1399 + * @param parsePosition The position at which to being parsing. Upon
1.1400 + * return, the first unparseable character.
1.1401 + * @param digits The DigitList to set to the parsed value.
1.1402 + * @param isExponent If true, parse an exponent. This means no
1.1403 + * infinite values and integer only.
1.1404 + * @param status Upon return contains boolean status flags indicating
1.1405 + * whether the value was infinite and whether it was positive.
1.1406 + */
1.1407 + private final boolean subparse(String text, ParsePosition parsePosition,
1.1408 + String positivePrefix, String negativePrefix,
1.1409 + DigitList digits, boolean isExponent,
1.1410 + boolean status[]) {
1.1411 + int position = parsePosition.index;
1.1412 + int oldStart = parsePosition.index;
1.1413 + int backup;
1.1414 + boolean gotPositive, gotNegative;
1.1415 +
1.1416 + // check for positivePrefix; take longest
1.1417 + gotPositive = text.regionMatches(position, positivePrefix, 0,
1.1418 + positivePrefix.length());
1.1419 + gotNegative = text.regionMatches(position, negativePrefix, 0,
1.1420 + negativePrefix.length());
1.1421 +
1.1422 + if (gotPositive && gotNegative) {
1.1423 + if (positivePrefix.length() > negativePrefix.length()) {
1.1424 + gotNegative = false;
1.1425 + } else if (positivePrefix.length() < negativePrefix.length()) {
1.1426 + gotPositive = false;
1.1427 + }
1.1428 + }
1.1429 +
1.1430 + if (gotPositive) {
1.1431 + position += positivePrefix.length();
1.1432 + } else if (gotNegative) {
1.1433 + position += negativePrefix.length();
1.1434 + } else {
1.1435 + parsePosition.errorIndex = position;
1.1436 + return false;
1.1437 + }
1.1438 +
1.1439 + // process digits or Inf, find decimal position
1.1440 + status[STATUS_INFINITE] = false;
1.1441 + if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
1.1442 + symbols.getInfinity().length())) {
1.1443 + position += symbols.getInfinity().length();
1.1444 + status[STATUS_INFINITE] = true;
1.1445 + } else {
1.1446 + // We now have a string of digits, possibly with grouping symbols,
1.1447 + // and decimal points. We want to process these into a DigitList.
1.1448 + // We don't want to put a bunch of leading zeros into the DigitList
1.1449 + // though, so we keep track of the location of the decimal point,
1.1450 + // put only significant digits into the DigitList, and adjust the
1.1451 + // exponent as needed.
1.1452 +
1.1453 + digits.decimalAt = digits.count = 0;
1.1454 + char zero = symbols.getZeroDigit();
1.1455 + char decimal = isCurrencyFormat ?
1.1456 + symbols.getMonetaryDecimalSeparator() :
1.1457 + symbols.getDecimalSeparator();
1.1458 + char grouping = symbols.getGroupingSeparator();
1.1459 + String exponentString = symbols.getExponentSeparator();
1.1460 + boolean sawDecimal = false;
1.1461 + boolean sawExponent = false;
1.1462 + boolean sawDigit = false;
1.1463 + int exponent = 0; // Set to the exponent value, if any
1.1464 +
1.1465 + // We have to track digitCount ourselves, because digits.count will
1.1466 + // pin when the maximum allowable digits is reached.
1.1467 + int digitCount = 0;
1.1468 +
1.1469 + backup = -1;
1.1470 + for (; position < text.length(); ++position) {
1.1471 + char ch = text.charAt(position);
1.1472 +
1.1473 + /* We recognize all digit ranges, not only the Latin digit range
1.1474 + * '0'..'9'. We do so by using the Character.digit() method,
1.1475 + * which converts a valid Unicode digit to the range 0..9.
1.1476 + *
1.1477 + * The character 'ch' may be a digit. If so, place its value
1.1478 + * from 0 to 9 in 'digit'. First try using the locale digit,
1.1479 + * which may or MAY NOT be a standard Unicode digit range. If
1.1480 + * this fails, try using the standard Unicode digit ranges by
1.1481 + * calling Character.digit(). If this also fails, digit will
1.1482 + * have a value outside the range 0..9.
1.1483 + */
1.1484 + int digit = ch - zero;
1.1485 + if (digit < 0 || digit > 9) {
1.1486 + digit = Character.digit(ch, 10);
1.1487 + }
1.1488 +
1.1489 + if (digit == 0) {
1.1490 + // Cancel out backup setting (see grouping handler below)
1.1491 + backup = -1; // Do this BEFORE continue statement below!!!
1.1492 + sawDigit = true;
1.1493 +
1.1494 + // Handle leading zeros
1.1495 + if (digits.count == 0) {
1.1496 + // Ignore leading zeros in integer part of number.
1.1497 + if (!sawDecimal) {
1.1498 + continue;
1.1499 + }
1.1500 +
1.1501 + // If we have seen the decimal, but no significant
1.1502 + // digits yet, then we account for leading zeros by
1.1503 + // decrementing the digits.decimalAt into negative
1.1504 + // values.
1.1505 + --digits.decimalAt;
1.1506 + } else {
1.1507 + ++digitCount;
1.1508 + digits.append((char)(digit + '0'));
1.1509 + }
1.1510 + } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
1.1511 + sawDigit = true;
1.1512 + ++digitCount;
1.1513 + digits.append((char)(digit + '0'));
1.1514 +
1.1515 + // Cancel out backup setting (see grouping handler below)
1.1516 + backup = -1;
1.1517 + } else if (!isExponent && ch == decimal) {
1.1518 + // If we're only parsing integers, or if we ALREADY saw the
1.1519 + // decimal, then don't parse this one.
1.1520 + if (isParseIntegerOnly() || sawDecimal) {
1.1521 + break;
1.1522 + }
1.1523 + digits.decimalAt = digitCount; // Not digits.count!
1.1524 + sawDecimal = true;
1.1525 + } else if (!isExponent && ch == grouping && isGroupingUsed()) {
1.1526 + if (sawDecimal) {
1.1527 + break;
1.1528 + }
1.1529 + // Ignore grouping characters, if we are using them, but
1.1530 + // require that they be followed by a digit. Otherwise
1.1531 + // we backup and reprocess them.
1.1532 + backup = position;
1.1533 + } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
1.1534 + && !sawExponent) {
1.1535 + // Process the exponent by recursively calling this method.
1.1536 + ParsePosition pos = new ParsePosition(position + exponentString.length());
1.1537 + boolean[] stat = new boolean[STATUS_LENGTH];
1.1538 + DigitList exponentDigits = new DigitList();
1.1539 +
1.1540 + if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
1.1541 + exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
1.1542 + position = pos.index; // Advance past the exponent
1.1543 + exponent = (int)exponentDigits.getLong();
1.1544 + if (!stat[STATUS_POSITIVE]) {
1.1545 + exponent = -exponent;
1.1546 + }
1.1547 + sawExponent = true;
1.1548 + }
1.1549 + break; // Whether we fail or succeed, we exit this loop
1.1550 + }
1.1551 + else {
1.1552 + break;
1.1553 + }
1.1554 + }
1.1555 +
1.1556 + if (backup != -1) {
1.1557 + position = backup;
1.1558 + }
1.1559 +
1.1560 + // If there was no decimal point we have an integer
1.1561 + if (!sawDecimal) {
1.1562 + digits.decimalAt = digitCount; // Not digits.count!
1.1563 + }
1.1564 +
1.1565 + // Adjust for exponent, if any
1.1566 + digits.decimalAt += exponent;
1.1567 +
1.1568 + // If none of the text string was recognized. For example, parse
1.1569 + // "x" with pattern "#0.00" (return index and error index both 0)
1.1570 + // parse "$" with pattern "$#0.00". (return index 0 and error
1.1571 + // index 1).
1.1572 + if (!sawDigit && digitCount == 0) {
1.1573 + parsePosition.index = oldStart;
1.1574 + parsePosition.errorIndex = oldStart;
1.1575 + return false;
1.1576 + }
1.1577 + }
1.1578 +
1.1579 + // check for suffix
1.1580 + if (!isExponent) {
1.1581 + if (gotPositive) {
1.1582 + gotPositive = text.regionMatches(position,positiveSuffix,0,
1.1583 + positiveSuffix.length());
1.1584 + }
1.1585 + if (gotNegative) {
1.1586 + gotNegative = text.regionMatches(position,negativeSuffix,0,
1.1587 + negativeSuffix.length());
1.1588 + }
1.1589 +
1.1590 + // if both match, take longest
1.1591 + if (gotPositive && gotNegative) {
1.1592 + if (positiveSuffix.length() > negativeSuffix.length()) {
1.1593 + gotNegative = false;
1.1594 + } else if (positiveSuffix.length() < negativeSuffix.length()) {
1.1595 + gotPositive = false;
1.1596 + }
1.1597 + }
1.1598 +
1.1599 + // fail if neither or both
1.1600 + if (gotPositive == gotNegative) {
1.1601 + parsePosition.errorIndex = position;
1.1602 + return false;
1.1603 + }
1.1604 +
1.1605 + parsePosition.index = position +
1.1606 + (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
1.1607 + } else {
1.1608 + parsePosition.index = position;
1.1609 + }
1.1610 +
1.1611 + status[STATUS_POSITIVE] = gotPositive;
1.1612 + if (parsePosition.index == oldStart) {
1.1613 + parsePosition.errorIndex = position;
1.1614 + return false;
1.1615 + }
1.1616 + return true;
1.1617 + }
1.1618 +
1.1619 + /**
1.1620 + * Returns a copy of the decimal format symbols, which is generally not
1.1621 + * changed by the programmer or user.
1.1622 + * @return a copy of the desired DecimalFormatSymbols
1.1623 + * @see java.text.DecimalFormatSymbols
1.1624 + */
1.1625 + public DecimalFormatSymbols getDecimalFormatSymbols() {
1.1626 + try {
1.1627 + // don't allow multiple references
1.1628 + return (DecimalFormatSymbols) symbols.clone();
1.1629 + } catch (Exception foo) {
1.1630 + return null; // should never happen
1.1631 + }
1.1632 + }
1.1633 +
1.1634 +
1.1635 + /**
1.1636 + * Sets the decimal format symbols, which is generally not changed
1.1637 + * by the programmer or user.
1.1638 + * @param newSymbols desired DecimalFormatSymbols
1.1639 + * @see java.text.DecimalFormatSymbols
1.1640 + */
1.1641 + public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
1.1642 + try {
1.1643 + // don't allow multiple references
1.1644 + symbols = (DecimalFormatSymbols) newSymbols.clone();
1.1645 + expandAffixes();
1.1646 + } catch (Exception foo) {
1.1647 + // should never happen
1.1648 + }
1.1649 + }
1.1650 +
1.1651 + /**
1.1652 + * Get the positive prefix.
1.1653 + * <P>Examples: +123, $123, sFr123
1.1654 + */
1.1655 + public String getPositivePrefix () {
1.1656 + return positivePrefix;
1.1657 + }
1.1658 +
1.1659 + /**
1.1660 + * Set the positive prefix.
1.1661 + * <P>Examples: +123, $123, sFr123
1.1662 + */
1.1663 + public void setPositivePrefix (String newValue) {
1.1664 + positivePrefix = newValue;
1.1665 + posPrefixPattern = null;
1.1666 + positivePrefixFieldPositions = null;
1.1667 + }
1.1668 +
1.1669 + /**
1.1670 + * Returns the FieldPositions of the fields in the prefix used for
1.1671 + * positive numbers. This is not used if the user has explicitly set
1.1672 + * a positive prefix via <code>setPositivePrefix</code>. This is
1.1673 + * lazily created.
1.1674 + *
1.1675 + * @return FieldPositions in positive prefix
1.1676 + */
1.1677 + private FieldPosition[] getPositivePrefixFieldPositions() {
1.1678 + if (positivePrefixFieldPositions == null) {
1.1679 + if (posPrefixPattern != null) {
1.1680 + positivePrefixFieldPositions = expandAffix(posPrefixPattern);
1.1681 + }
1.1682 + else {
1.1683 + positivePrefixFieldPositions = EmptyFieldPositionArray;
1.1684 + }
1.1685 + }
1.1686 + return positivePrefixFieldPositions;
1.1687 + }
1.1688 +
1.1689 + /**
1.1690 + * Get the negative prefix.
1.1691 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1.1692 + */
1.1693 + public String getNegativePrefix () {
1.1694 + return negativePrefix;
1.1695 + }
1.1696 +
1.1697 + /**
1.1698 + * Set the negative prefix.
1.1699 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1.1700 + */
1.1701 + public void setNegativePrefix (String newValue) {
1.1702 + negativePrefix = newValue;
1.1703 + negPrefixPattern = null;
1.1704 + }
1.1705 +
1.1706 + /**
1.1707 + * Returns the FieldPositions of the fields in the prefix used for
1.1708 + * negative numbers. This is not used if the user has explicitly set
1.1709 + * a negative prefix via <code>setNegativePrefix</code>. This is
1.1710 + * lazily created.
1.1711 + *
1.1712 + * @return FieldPositions in positive prefix
1.1713 + */
1.1714 + private FieldPosition[] getNegativePrefixFieldPositions() {
1.1715 + if (negativePrefixFieldPositions == null) {
1.1716 + if (negPrefixPattern != null) {
1.1717 + negativePrefixFieldPositions = expandAffix(negPrefixPattern);
1.1718 + }
1.1719 + else {
1.1720 + negativePrefixFieldPositions = EmptyFieldPositionArray;
1.1721 + }
1.1722 + }
1.1723 + return negativePrefixFieldPositions;
1.1724 + }
1.1725 +
1.1726 + /**
1.1727 + * Get the positive suffix.
1.1728 + * <P>Example: 123%
1.1729 + */
1.1730 + public String getPositiveSuffix () {
1.1731 + return positiveSuffix;
1.1732 + }
1.1733 +
1.1734 + /**
1.1735 + * Set the positive suffix.
1.1736 + * <P>Example: 123%
1.1737 + */
1.1738 + public void setPositiveSuffix (String newValue) {
1.1739 + positiveSuffix = newValue;
1.1740 + posSuffixPattern = null;
1.1741 + }
1.1742 +
1.1743 + /**
1.1744 + * Returns the FieldPositions of the fields in the suffix used for
1.1745 + * positive numbers. This is not used if the user has explicitly set
1.1746 + * a positive suffix via <code>setPositiveSuffix</code>. This is
1.1747 + * lazily created.
1.1748 + *
1.1749 + * @return FieldPositions in positive prefix
1.1750 + */
1.1751 + private FieldPosition[] getPositiveSuffixFieldPositions() {
1.1752 + if (positiveSuffixFieldPositions == null) {
1.1753 + if (posSuffixPattern != null) {
1.1754 + positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
1.1755 + }
1.1756 + else {
1.1757 + positiveSuffixFieldPositions = EmptyFieldPositionArray;
1.1758 + }
1.1759 + }
1.1760 + return positiveSuffixFieldPositions;
1.1761 + }
1.1762 +
1.1763 + /**
1.1764 + * Get the negative suffix.
1.1765 + * <P>Examples: -123%, ($123) (with positive suffixes)
1.1766 + */
1.1767 + public String getNegativeSuffix () {
1.1768 + return negativeSuffix;
1.1769 + }
1.1770 +
1.1771 + /**
1.1772 + * Set the negative suffix.
1.1773 + * <P>Examples: 123%
1.1774 + */
1.1775 + public void setNegativeSuffix (String newValue) {
1.1776 + negativeSuffix = newValue;
1.1777 + negSuffixPattern = null;
1.1778 + }
1.1779 +
1.1780 + /**
1.1781 + * Returns the FieldPositions of the fields in the suffix used for
1.1782 + * negative numbers. This is not used if the user has explicitly set
1.1783 + * a negative suffix via <code>setNegativeSuffix</code>. This is
1.1784 + * lazily created.
1.1785 + *
1.1786 + * @return FieldPositions in positive prefix
1.1787 + */
1.1788 + private FieldPosition[] getNegativeSuffixFieldPositions() {
1.1789 + if (negativeSuffixFieldPositions == null) {
1.1790 + if (negSuffixPattern != null) {
1.1791 + negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
1.1792 + }
1.1793 + else {
1.1794 + negativeSuffixFieldPositions = EmptyFieldPositionArray;
1.1795 + }
1.1796 + }
1.1797 + return negativeSuffixFieldPositions;
1.1798 + }
1.1799 +
1.1800 + /**
1.1801 + * Gets the multiplier for use in percent, per mille, and similar
1.1802 + * formats.
1.1803 + *
1.1804 + * @see #setMultiplier(int)
1.1805 + */
1.1806 + public int getMultiplier () {
1.1807 + return multiplier;
1.1808 + }
1.1809 +
1.1810 + /**
1.1811 + * Sets the multiplier for use in percent, per mille, and similar
1.1812 + * formats.
1.1813 + * For a percent format, set the multiplier to 100 and the suffixes to
1.1814 + * have '%' (for Arabic, use the Arabic percent sign).
1.1815 + * For a per mille format, set the multiplier to 1000 and the suffixes to
1.1816 + * have '\u2030'.
1.1817 + *
1.1818 + * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
1.1819 + * "123" is parsed into 1.23.
1.1820 + *
1.1821 + * @see #getMultiplier
1.1822 + */
1.1823 + public void setMultiplier (int newValue) {
1.1824 + multiplier = newValue;
1.1825 + bigDecimalMultiplier = null;
1.1826 + bigIntegerMultiplier = null;
1.1827 + }
1.1828 +
1.1829 + /**
1.1830 + * Return the grouping size. Grouping size is the number of digits between
1.1831 + * grouping separators in the integer portion of a number. For example,
1.1832 + * in the number "123,456.78", the grouping size is 3.
1.1833 + * @see #setGroupingSize
1.1834 + * @see java.text.NumberFormat#isGroupingUsed
1.1835 + * @see java.text.DecimalFormatSymbols#getGroupingSeparator
1.1836 + */
1.1837 + public int getGroupingSize () {
1.1838 + return groupingSize;
1.1839 + }
1.1840 +
1.1841 + /**
1.1842 + * Set the grouping size. Grouping size is the number of digits between
1.1843 + * grouping separators in the integer portion of a number. For example,
1.1844 + * in the number "123,456.78", the grouping size is 3.
1.1845 + * <br>
1.1846 + * The value passed in is converted to a byte, which may lose information.
1.1847 + * @see #getGroupingSize
1.1848 + * @see java.text.NumberFormat#setGroupingUsed
1.1849 + * @see java.text.DecimalFormatSymbols#setGroupingSeparator
1.1850 + */
1.1851 + public void setGroupingSize (int newValue) {
1.1852 + groupingSize = (byte)newValue;
1.1853 + }
1.1854 +
1.1855 + /**
1.1856 + * Allows you to get the behavior of the decimal separator with integers.
1.1857 + * (The decimal separator will always appear with decimals.)
1.1858 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1.1859 + */
1.1860 + public boolean isDecimalSeparatorAlwaysShown() {
1.1861 + return decimalSeparatorAlwaysShown;
1.1862 + }
1.1863 +
1.1864 + /**
1.1865 + * Allows you to set the behavior of the decimal separator with integers.
1.1866 + * (The decimal separator will always appear with decimals.)
1.1867 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1.1868 + */
1.1869 + public void setDecimalSeparatorAlwaysShown(boolean newValue) {
1.1870 + decimalSeparatorAlwaysShown = newValue;
1.1871 + }
1.1872 +
1.1873 + /**
1.1874 + * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
1.1875 + * method returns <code>BigDecimal</code>. The default value is false.
1.1876 + * @see #setParseBigDecimal
1.1877 + * @since 1.5
1.1878 + */
1.1879 + public boolean isParseBigDecimal() {
1.1880 + return parseBigDecimal;
1.1881 + }
1.1882 +
1.1883 + /**
1.1884 + * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
1.1885 + * method returns <code>BigDecimal</code>.
1.1886 + * @see #isParseBigDecimal
1.1887 + * @since 1.5
1.1888 + */
1.1889 + public void setParseBigDecimal(boolean newValue) {
1.1890 + parseBigDecimal = newValue;
1.1891 + }
1.1892 +
1.1893 + /**
1.1894 + * Standard override; no change in semantics.
1.1895 + */
1.1896 + public Object clone() {
1.1897 + try {
1.1898 + DecimalFormat other = (DecimalFormat) super.clone();
1.1899 + other.symbols = (DecimalFormatSymbols) symbols.clone();
1.1900 + other.digitList = (DigitList) digitList.clone();
1.1901 + return other;
1.1902 + } catch (Exception e) {
1.1903 + throw new InternalError();
1.1904 + }
1.1905 + }
1.1906 +
1.1907 + /**
1.1908 + * Overrides equals
1.1909 + */
1.1910 + public boolean equals(Object obj)
1.1911 + {
1.1912 + if (obj == null) return false;
1.1913 + if (!super.equals(obj)) return false; // super does class check
1.1914 + DecimalFormat other = (DecimalFormat) obj;
1.1915 + return ((posPrefixPattern == other.posPrefixPattern &&
1.1916 + positivePrefix.equals(other.positivePrefix))
1.1917 + || (posPrefixPattern != null &&
1.1918 + posPrefixPattern.equals(other.posPrefixPattern)))
1.1919 + && ((posSuffixPattern == other.posSuffixPattern &&
1.1920 + positiveSuffix.equals(other.positiveSuffix))
1.1921 + || (posSuffixPattern != null &&
1.1922 + posSuffixPattern.equals(other.posSuffixPattern)))
1.1923 + && ((negPrefixPattern == other.negPrefixPattern &&
1.1924 + negativePrefix.equals(other.negativePrefix))
1.1925 + || (negPrefixPattern != null &&
1.1926 + negPrefixPattern.equals(other.negPrefixPattern)))
1.1927 + && ((negSuffixPattern == other.negSuffixPattern &&
1.1928 + negativeSuffix.equals(other.negativeSuffix))
1.1929 + || (negSuffixPattern != null &&
1.1930 + negSuffixPattern.equals(other.negSuffixPattern)))
1.1931 + && multiplier == other.multiplier
1.1932 + && groupingSize == other.groupingSize
1.1933 + && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
1.1934 + && parseBigDecimal == other.parseBigDecimal
1.1935 + && useExponentialNotation == other.useExponentialNotation
1.1936 + && (!useExponentialNotation ||
1.1937 + minExponentDigits == other.minExponentDigits)
1.1938 + && maximumIntegerDigits == other.maximumIntegerDigits
1.1939 + && minimumIntegerDigits == other.minimumIntegerDigits
1.1940 + && maximumFractionDigits == other.maximumFractionDigits
1.1941 + && minimumFractionDigits == other.minimumFractionDigits
1.1942 + && roundingMode == other.roundingMode
1.1943 + && symbols.equals(other.symbols);
1.1944 + }
1.1945 +
1.1946 + /**
1.1947 + * Overrides hashCode
1.1948 + */
1.1949 + public int hashCode() {
1.1950 + return super.hashCode() * 37 + positivePrefix.hashCode();
1.1951 + // just enough fields for a reasonable distribution
1.1952 + }
1.1953 +
1.1954 + /**
1.1955 + * Synthesizes a pattern string that represents the current state
1.1956 + * of this Format object.
1.1957 + * @see #applyPattern
1.1958 + */
1.1959 + public String toPattern() {
1.1960 + return toPattern( false );
1.1961 + }
1.1962 +
1.1963 + /**
1.1964 + * Synthesizes a localized pattern string that represents the current
1.1965 + * state of this Format object.
1.1966 + * @see #applyPattern
1.1967 + */
1.1968 + public String toLocalizedPattern() {
1.1969 + return toPattern( true );
1.1970 + }
1.1971 +
1.1972 + /**
1.1973 + * Expand the affix pattern strings into the expanded affix strings. If any
1.1974 + * affix pattern string is null, do not expand it. This method should be
1.1975 + * called any time the symbols or the affix patterns change in order to keep
1.1976 + * the expanded affix strings up to date.
1.1977 + */
1.1978 + private void expandAffixes() {
1.1979 + // Reuse one StringBuffer for better performance
1.1980 + StringBuffer buffer = new StringBuffer();
1.1981 + if (posPrefixPattern != null) {
1.1982 + positivePrefix = expandAffix(posPrefixPattern, buffer);
1.1983 + positivePrefixFieldPositions = null;
1.1984 + }
1.1985 + if (posSuffixPattern != null) {
1.1986 + positiveSuffix = expandAffix(posSuffixPattern, buffer);
1.1987 + positiveSuffixFieldPositions = null;
1.1988 + }
1.1989 + if (negPrefixPattern != null) {
1.1990 + negativePrefix = expandAffix(negPrefixPattern, buffer);
1.1991 + negativePrefixFieldPositions = null;
1.1992 + }
1.1993 + if (negSuffixPattern != null) {
1.1994 + negativeSuffix = expandAffix(negSuffixPattern, buffer);
1.1995 + negativeSuffixFieldPositions = null;
1.1996 + }
1.1997 + }
1.1998 +
1.1999 + /**
1.2000 + * Expand an affix pattern into an affix string. All characters in the
1.2001 + * pattern are literal unless prefixed by QUOTE. The following characters
1.2002 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
1.2003 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
1.2004 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
1.2005 + * currency code. Any other character after a QUOTE represents itself.
1.2006 + * QUOTE must be followed by another character; QUOTE may not occur by
1.2007 + * itself at the end of the pattern.
1.2008 + *
1.2009 + * @param pattern the non-null, possibly empty pattern
1.2010 + * @param buffer a scratch StringBuffer; its contents will be lost
1.2011 + * @return the expanded equivalent of pattern
1.2012 + */
1.2013 + private String expandAffix(String pattern, StringBuffer buffer) {
1.2014 + buffer.setLength(0);
1.2015 + for (int i=0; i<pattern.length(); ) {
1.2016 + char c = pattern.charAt(i++);
1.2017 + if (c == QUOTE) {
1.2018 + c = pattern.charAt(i++);
1.2019 + switch (c) {
1.2020 + case CURRENCY_SIGN:
1.2021 + if (i<pattern.length() &&
1.2022 + pattern.charAt(i) == CURRENCY_SIGN) {
1.2023 + ++i;
1.2024 + buffer.append(symbols.getInternationalCurrencySymbol());
1.2025 + } else {
1.2026 + buffer.append(symbols.getCurrencySymbol());
1.2027 + }
1.2028 + continue;
1.2029 + case PATTERN_PERCENT:
1.2030 + c = symbols.getPercent();
1.2031 + break;
1.2032 + case PATTERN_PER_MILLE:
1.2033 + c = symbols.getPerMill();
1.2034 + break;
1.2035 + case PATTERN_MINUS:
1.2036 + c = symbols.getMinusSign();
1.2037 + break;
1.2038 + }
1.2039 + }
1.2040 + buffer.append(c);
1.2041 + }
1.2042 + return buffer.toString();
1.2043 + }
1.2044 +
1.2045 + /**
1.2046 + * Expand an affix pattern into an array of FieldPositions describing
1.2047 + * how the pattern would be expanded.
1.2048 + * All characters in the
1.2049 + * pattern are literal unless prefixed by QUOTE. The following characters
1.2050 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
1.2051 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
1.2052 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
1.2053 + * currency code. Any other character after a QUOTE represents itself.
1.2054 + * QUOTE must be followed by another character; QUOTE may not occur by
1.2055 + * itself at the end of the pattern.
1.2056 + *
1.2057 + * @param pattern the non-null, possibly empty pattern
1.2058 + * @return FieldPosition array of the resulting fields.
1.2059 + */
1.2060 + private FieldPosition[] expandAffix(String pattern) {
1.2061 + ArrayList positions = null;
1.2062 + int stringIndex = 0;
1.2063 + for (int i=0; i<pattern.length(); ) {
1.2064 + char c = pattern.charAt(i++);
1.2065 + if (c == QUOTE) {
1.2066 + int field = -1;
1.2067 + Format.Field fieldID = null;
1.2068 + c = pattern.charAt(i++);
1.2069 + switch (c) {
1.2070 + case CURRENCY_SIGN:
1.2071 + String string;
1.2072 + if (i<pattern.length() &&
1.2073 + pattern.charAt(i) == CURRENCY_SIGN) {
1.2074 + ++i;
1.2075 + string = symbols.getInternationalCurrencySymbol();
1.2076 + } else {
1.2077 + string = symbols.getCurrencySymbol();
1.2078 + }
1.2079 + if (string.length() > 0) {
1.2080 + if (positions == null) {
1.2081 + positions = new ArrayList(2);
1.2082 + }
1.2083 + FieldPosition fp = new FieldPosition(Field.CURRENCY);
1.2084 + fp.setBeginIndex(stringIndex);
1.2085 + fp.setEndIndex(stringIndex + string.length());
1.2086 + positions.add(fp);
1.2087 + stringIndex += string.length();
1.2088 + }
1.2089 + continue;
1.2090 + case PATTERN_PERCENT:
1.2091 + c = symbols.getPercent();
1.2092 + field = -1;
1.2093 + fieldID = Field.PERCENT;
1.2094 + break;
1.2095 + case PATTERN_PER_MILLE:
1.2096 + c = symbols.getPerMill();
1.2097 + field = -1;
1.2098 + fieldID = Field.PERMILLE;
1.2099 + break;
1.2100 + case PATTERN_MINUS:
1.2101 + c = symbols.getMinusSign();
1.2102 + field = -1;
1.2103 + fieldID = Field.SIGN;
1.2104 + break;
1.2105 + }
1.2106 + if (fieldID != null) {
1.2107 + if (positions == null) {
1.2108 + positions = new ArrayList(2);
1.2109 + }
1.2110 + FieldPosition fp = new FieldPosition(fieldID, field);
1.2111 + fp.setBeginIndex(stringIndex);
1.2112 + fp.setEndIndex(stringIndex + 1);
1.2113 + positions.add(fp);
1.2114 + }
1.2115 + }
1.2116 + stringIndex++;
1.2117 + }
1.2118 + if (positions != null) {
1.2119 + return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
1.2120 + }
1.2121 + return EmptyFieldPositionArray;
1.2122 + }
1.2123 +
1.2124 + /**
1.2125 + * Appends an affix pattern to the given StringBuffer, quoting special
1.2126 + * characters as needed. Uses the internal affix pattern, if that exists,
1.2127 + * or the literal affix, if the internal affix pattern is null. The
1.2128 + * appended string will generate the same affix pattern (or literal affix)
1.2129 + * when passed to toPattern().
1.2130 + *
1.2131 + * @param buffer the affix string is appended to this
1.2132 + * @param affixPattern a pattern such as posPrefixPattern; may be null
1.2133 + * @param expAffix a corresponding expanded affix, such as positivePrefix.
1.2134 + * Ignored unless affixPattern is null. If affixPattern is null, then
1.2135 + * expAffix is appended as a literal affix.
1.2136 + * @param localized true if the appended pattern should contain localized
1.2137 + * pattern characters; otherwise, non-localized pattern chars are appended
1.2138 + */
1.2139 + private void appendAffix(StringBuffer buffer, String affixPattern,
1.2140 + String expAffix, boolean localized) {
1.2141 + if (affixPattern == null) {
1.2142 + appendAffix(buffer, expAffix, localized);
1.2143 + } else {
1.2144 + int i;
1.2145 + for (int pos=0; pos<affixPattern.length(); pos=i) {
1.2146 + i = affixPattern.indexOf(QUOTE, pos);
1.2147 + if (i < 0) {
1.2148 + appendAffix(buffer, affixPattern.substring(pos), localized);
1.2149 + break;
1.2150 + }
1.2151 + if (i > pos) {
1.2152 + appendAffix(buffer, affixPattern.substring(pos, i), localized);
1.2153 + }
1.2154 + char c = affixPattern.charAt(++i);
1.2155 + ++i;
1.2156 + if (c == QUOTE) {
1.2157 + buffer.append(c);
1.2158 + // Fall through and append another QUOTE below
1.2159 + } else if (c == CURRENCY_SIGN &&
1.2160 + i<affixPattern.length() &&
1.2161 + affixPattern.charAt(i) == CURRENCY_SIGN) {
1.2162 + ++i;
1.2163 + buffer.append(c);
1.2164 + // Fall through and append another CURRENCY_SIGN below
1.2165 + } else if (localized) {
1.2166 + switch (c) {
1.2167 + case PATTERN_PERCENT:
1.2168 + c = symbols.getPercent();
1.2169 + break;
1.2170 + case PATTERN_PER_MILLE:
1.2171 + c = symbols.getPerMill();
1.2172 + break;
1.2173 + case PATTERN_MINUS:
1.2174 + c = symbols.getMinusSign();
1.2175 + break;
1.2176 + }
1.2177 + }
1.2178 + buffer.append(c);
1.2179 + }
1.2180 + }
1.2181 + }
1.2182 +
1.2183 + /**
1.2184 + * Append an affix to the given StringBuffer, using quotes if
1.2185 + * there are special characters. Single quotes themselves must be
1.2186 + * escaped in either case.
1.2187 + */
1.2188 + private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
1.2189 + boolean needQuote;
1.2190 + if (localized) {
1.2191 + needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
1.2192 + || affix.indexOf(symbols.getGroupingSeparator()) >= 0
1.2193 + || affix.indexOf(symbols.getDecimalSeparator()) >= 0
1.2194 + || affix.indexOf(symbols.getPercent()) >= 0
1.2195 + || affix.indexOf(symbols.getPerMill()) >= 0
1.2196 + || affix.indexOf(symbols.getDigit()) >= 0
1.2197 + || affix.indexOf(symbols.getPatternSeparator()) >= 0
1.2198 + || affix.indexOf(symbols.getMinusSign()) >= 0
1.2199 + || affix.indexOf(CURRENCY_SIGN) >= 0;
1.2200 + }
1.2201 + else {
1.2202 + needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
1.2203 + || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
1.2204 + || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
1.2205 + || affix.indexOf(PATTERN_PERCENT) >= 0
1.2206 + || affix.indexOf(PATTERN_PER_MILLE) >= 0
1.2207 + || affix.indexOf(PATTERN_DIGIT) >= 0
1.2208 + || affix.indexOf(PATTERN_SEPARATOR) >= 0
1.2209 + || affix.indexOf(PATTERN_MINUS) >= 0
1.2210 + || affix.indexOf(CURRENCY_SIGN) >= 0;
1.2211 + }
1.2212 + if (needQuote) buffer.append('\'');
1.2213 + if (affix.indexOf('\'') < 0) buffer.append(affix);
1.2214 + else {
1.2215 + for (int j=0; j<affix.length(); ++j) {
1.2216 + char c = affix.charAt(j);
1.2217 + buffer.append(c);
1.2218 + if (c == '\'') buffer.append(c);
1.2219 + }
1.2220 + }
1.2221 + if (needQuote) buffer.append('\'');
1.2222 + }
1.2223 +
1.2224 + /**
1.2225 + * Does the real work of generating a pattern. */
1.2226 + private String toPattern(boolean localized) {
1.2227 + StringBuffer result = new StringBuffer();
1.2228 + for (int j = 1; j >= 0; --j) {
1.2229 + if (j == 1)
1.2230 + appendAffix(result, posPrefixPattern, positivePrefix, localized);
1.2231 + else appendAffix(result, negPrefixPattern, negativePrefix, localized);
1.2232 + int i;
1.2233 + int digitCount = useExponentialNotation
1.2234 + ? getMaximumIntegerDigits()
1.2235 + : Math.max(groupingSize, getMinimumIntegerDigits())+1;
1.2236 + for (i = digitCount; i > 0; --i) {
1.2237 + if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
1.2238 + i % groupingSize == 0) {
1.2239 + result.append(localized ? symbols.getGroupingSeparator() :
1.2240 + PATTERN_GROUPING_SEPARATOR);
1.2241 + }
1.2242 + result.append(i <= getMinimumIntegerDigits()
1.2243 + ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
1.2244 + : (localized ? symbols.getDigit() : PATTERN_DIGIT));
1.2245 + }
1.2246 + if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
1.2247 + result.append(localized ? symbols.getDecimalSeparator() :
1.2248 + PATTERN_DECIMAL_SEPARATOR);
1.2249 + for (i = 0; i < getMaximumFractionDigits(); ++i) {
1.2250 + if (i < getMinimumFractionDigits()) {
1.2251 + result.append(localized ? symbols.getZeroDigit() :
1.2252 + PATTERN_ZERO_DIGIT);
1.2253 + } else {
1.2254 + result.append(localized ? symbols.getDigit() :
1.2255 + PATTERN_DIGIT);
1.2256 + }
1.2257 + }
1.2258 + if (useExponentialNotation)
1.2259 + {
1.2260 + result.append(localized ? symbols.getExponentSeparator() :
1.2261 + PATTERN_EXPONENT);
1.2262 + for (i=0; i<minExponentDigits; ++i)
1.2263 + result.append(localized ? symbols.getZeroDigit() :
1.2264 + PATTERN_ZERO_DIGIT);
1.2265 + }
1.2266 + if (j == 1) {
1.2267 + appendAffix(result, posSuffixPattern, positiveSuffix, localized);
1.2268 + if ((negSuffixPattern == posSuffixPattern && // n == p == null
1.2269 + negativeSuffix.equals(positiveSuffix))
1.2270 + || (negSuffixPattern != null &&
1.2271 + negSuffixPattern.equals(posSuffixPattern))) {
1.2272 + if ((negPrefixPattern != null && posPrefixPattern != null &&
1.2273 + negPrefixPattern.equals("'-" + posPrefixPattern)) ||
1.2274 + (negPrefixPattern == posPrefixPattern && // n == p == null
1.2275 + negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
1.2276 + break;
1.2277 + }
1.2278 + result.append(localized ? symbols.getPatternSeparator() :
1.2279 + PATTERN_SEPARATOR);
1.2280 + } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
1.2281 + }
1.2282 + return result.toString();
1.2283 + }
1.2284 +
1.2285 + /**
1.2286 + * Apply the given pattern to this Format object. A pattern is a
1.2287 + * short-hand specification for the various formatting properties.
1.2288 + * These properties can also be changed individually through the
1.2289 + * various setter methods.
1.2290 + * <p>
1.2291 + * There is no limit to integer digits set
1.2292 + * by this routine, since that is the typical end-user desire;
1.2293 + * use setMaximumInteger if you want to set a real value.
1.2294 + * For negative numbers, use a second pattern, separated by a semicolon
1.2295 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
1.2296 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
1.2297 + * a maximum of 2 fraction digits.
1.2298 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
1.2299 + * parentheses.
1.2300 + * <p>In negative patterns, the minimum and maximum counts are ignored;
1.2301 + * these are presumed to be set in the positive pattern.
1.2302 + *
1.2303 + * @exception NullPointerException if <code>pattern</code> is null
1.2304 + * @exception IllegalArgumentException if the given pattern is invalid.
1.2305 + */
1.2306 + public void applyPattern(String pattern) {
1.2307 + applyPattern(pattern, false);
1.2308 + }
1.2309 +
1.2310 + /**
1.2311 + * Apply the given pattern to this Format object. The pattern
1.2312 + * is assumed to be in a localized notation. A pattern is a
1.2313 + * short-hand specification for the various formatting properties.
1.2314 + * These properties can also be changed individually through the
1.2315 + * various setter methods.
1.2316 + * <p>
1.2317 + * There is no limit to integer digits set
1.2318 + * by this routine, since that is the typical end-user desire;
1.2319 + * use setMaximumInteger if you want to set a real value.
1.2320 + * For negative numbers, use a second pattern, separated by a semicolon
1.2321 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
1.2322 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
1.2323 + * a maximum of 2 fraction digits.
1.2324 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
1.2325 + * parentheses.
1.2326 + * <p>In negative patterns, the minimum and maximum counts are ignored;
1.2327 + * these are presumed to be set in the positive pattern.
1.2328 + *
1.2329 + * @exception NullPointerException if <code>pattern</code> is null
1.2330 + * @exception IllegalArgumentException if the given pattern is invalid.
1.2331 + */
1.2332 + public void applyLocalizedPattern(String pattern) {
1.2333 + applyPattern(pattern, true);
1.2334 + }
1.2335 +
1.2336 + /**
1.2337 + * Does the real work of applying a pattern.
1.2338 + */
1.2339 + private void applyPattern(String pattern, boolean localized) {
1.2340 + char zeroDigit = PATTERN_ZERO_DIGIT;
1.2341 + char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
1.2342 + char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
1.2343 + char percent = PATTERN_PERCENT;
1.2344 + char perMill = PATTERN_PER_MILLE;
1.2345 + char digit = PATTERN_DIGIT;
1.2346 + char separator = PATTERN_SEPARATOR;
1.2347 + String exponent = PATTERN_EXPONENT;
1.2348 + char minus = PATTERN_MINUS;
1.2349 + if (localized) {
1.2350 + zeroDigit = symbols.getZeroDigit();
1.2351 + groupingSeparator = symbols.getGroupingSeparator();
1.2352 + decimalSeparator = symbols.getDecimalSeparator();
1.2353 + percent = symbols.getPercent();
1.2354 + perMill = symbols.getPerMill();
1.2355 + digit = symbols.getDigit();
1.2356 + separator = symbols.getPatternSeparator();
1.2357 + exponent = symbols.getExponentSeparator();
1.2358 + minus = symbols.getMinusSign();
1.2359 + }
1.2360 + boolean gotNegative = false;
1.2361 + decimalSeparatorAlwaysShown = false;
1.2362 + isCurrencyFormat = false;
1.2363 + useExponentialNotation = false;
1.2364 +
1.2365 + // Two variables are used to record the subrange of the pattern
1.2366 + // occupied by phase 1. This is used during the processing of the
1.2367 + // second pattern (the one representing negative numbers) to ensure
1.2368 + // that no deviation exists in phase 1 between the two patterns.
1.2369 + int phaseOneStart = 0;
1.2370 + int phaseOneLength = 0;
1.2371 +
1.2372 + int start = 0;
1.2373 + for (int j = 1; j >= 0 && start < pattern.length(); --j) {
1.2374 + boolean inQuote = false;
1.2375 + StringBuffer prefix = new StringBuffer();
1.2376 + StringBuffer suffix = new StringBuffer();
1.2377 + int decimalPos = -1;
1.2378 + int multiplier = 1;
1.2379 + int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
1.2380 + byte groupingCount = -1;
1.2381 +
1.2382 + // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
1.2383 + // the section of the pattern with digits, decimal separator,
1.2384 + // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
1.2385 + // percent, per mille, and currency symbols are recognized and
1.2386 + // translated. The separation of the characters into phases is
1.2387 + // strictly enforced; if phase 1 characters are to appear in the
1.2388 + // suffix, for example, they must be quoted.
1.2389 + int phase = 0;
1.2390 +
1.2391 + // The affix is either the prefix or the suffix.
1.2392 + StringBuffer affix = prefix;
1.2393 +
1.2394 + for (int pos = start; pos < pattern.length(); ++pos) {
1.2395 + char ch = pattern.charAt(pos);
1.2396 + switch (phase) {
1.2397 + case 0:
1.2398 + case 2:
1.2399 + // Process the prefix / suffix characters
1.2400 + if (inQuote) {
1.2401 + // A quote within quotes indicates either the closing
1.2402 + // quote or two quotes, which is a quote literal. That
1.2403 + // is, we have the second quote in 'do' or 'don''t'.
1.2404 + if (ch == QUOTE) {
1.2405 + if ((pos+1) < pattern.length() &&
1.2406 + pattern.charAt(pos+1) == QUOTE) {
1.2407 + ++pos;
1.2408 + affix.append("''"); // 'don''t'
1.2409 + } else {
1.2410 + inQuote = false; // 'do'
1.2411 + }
1.2412 + continue;
1.2413 + }
1.2414 + } else {
1.2415 + // Process unquoted characters seen in prefix or suffix
1.2416 + // phase.
1.2417 + if (ch == digit ||
1.2418 + ch == zeroDigit ||
1.2419 + ch == groupingSeparator ||
1.2420 + ch == decimalSeparator) {
1.2421 + phase = 1;
1.2422 + if (j == 1) {
1.2423 + phaseOneStart = pos;
1.2424 + }
1.2425 + --pos; // Reprocess this character
1.2426 + continue;
1.2427 + } else if (ch == CURRENCY_SIGN) {
1.2428 + // Use lookahead to determine if the currency sign
1.2429 + // is doubled or not.
1.2430 + boolean doubled = (pos + 1) < pattern.length() &&
1.2431 + pattern.charAt(pos + 1) == CURRENCY_SIGN;
1.2432 + if (doubled) { // Skip over the doubled character
1.2433 + ++pos;
1.2434 + }
1.2435 + isCurrencyFormat = true;
1.2436 + affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
1.2437 + continue;
1.2438 + } else if (ch == QUOTE) {
1.2439 + // A quote outside quotes indicates either the
1.2440 + // opening quote or two quotes, which is a quote
1.2441 + // literal. That is, we have the first quote in 'do'
1.2442 + // or o''clock.
1.2443 + if (ch == QUOTE) {
1.2444 + if ((pos+1) < pattern.length() &&
1.2445 + pattern.charAt(pos+1) == QUOTE) {
1.2446 + ++pos;
1.2447 + affix.append("''"); // o''clock
1.2448 + } else {
1.2449 + inQuote = true; // 'do'
1.2450 + }
1.2451 + continue;
1.2452 + }
1.2453 + } else if (ch == separator) {
1.2454 + // Don't allow separators before we see digit
1.2455 + // characters of phase 1, and don't allow separators
1.2456 + // in the second pattern (j == 0).
1.2457 + if (phase == 0 || j == 0) {
1.2458 + throw new IllegalArgumentException("Unquoted special character '" +
1.2459 + ch + "' in pattern \"" + pattern + '"');
1.2460 + }
1.2461 + start = pos + 1;
1.2462 + pos = pattern.length();
1.2463 + continue;
1.2464 + }
1.2465 +
1.2466 + // Next handle characters which are appended directly.
1.2467 + else if (ch == percent) {
1.2468 + if (multiplier != 1) {
1.2469 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
1.2470 + pattern + '"');
1.2471 + }
1.2472 + multiplier = 100;
1.2473 + affix.append("'%");
1.2474 + continue;
1.2475 + } else if (ch == perMill) {
1.2476 + if (multiplier != 1) {
1.2477 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
1.2478 + pattern + '"');
1.2479 + }
1.2480 + multiplier = 1000;
1.2481 + affix.append("'\u2030");
1.2482 + continue;
1.2483 + } else if (ch == minus) {
1.2484 + affix.append("'-");
1.2485 + continue;
1.2486 + }
1.2487 + }
1.2488 + // Note that if we are within quotes, or if this is an
1.2489 + // unquoted, non-special character, then we usually fall
1.2490 + // through to here.
1.2491 + affix.append(ch);
1.2492 + break;
1.2493 +
1.2494 + case 1:
1.2495 + // Phase one must be identical in the two sub-patterns. We
1.2496 + // enforce this by doing a direct comparison. While
1.2497 + // processing the first sub-pattern, we just record its
1.2498 + // length. While processing the second, we compare
1.2499 + // characters.
1.2500 + if (j == 1) {
1.2501 + ++phaseOneLength;
1.2502 + } else {
1.2503 + if (--phaseOneLength == 0) {
1.2504 + phase = 2;
1.2505 + affix = suffix;
1.2506 + }
1.2507 + continue;
1.2508 + }
1.2509 +
1.2510 + // Process the digits, decimal, and grouping characters. We
1.2511 + // record five pieces of information. We expect the digits
1.2512 + // to occur in the pattern ####0000.####, and we record the
1.2513 + // number of left digits, zero (central) digits, and right
1.2514 + // digits. The position of the last grouping character is
1.2515 + // recorded (should be somewhere within the first two blocks
1.2516 + // of characters), as is the position of the decimal point,
1.2517 + // if any (should be in the zero digits). If there is no
1.2518 + // decimal point, then there should be no right digits.
1.2519 + if (ch == digit) {
1.2520 + if (zeroDigitCount > 0) {
1.2521 + ++digitRightCount;
1.2522 + } else {
1.2523 + ++digitLeftCount;
1.2524 + }
1.2525 + if (groupingCount >= 0 && decimalPos < 0) {
1.2526 + ++groupingCount;
1.2527 + }
1.2528 + } else if (ch == zeroDigit) {
1.2529 + if (digitRightCount > 0) {
1.2530 + throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
1.2531 + pattern + '"');
1.2532 + }
1.2533 + ++zeroDigitCount;
1.2534 + if (groupingCount >= 0 && decimalPos < 0) {
1.2535 + ++groupingCount;
1.2536 + }
1.2537 + } else if (ch == groupingSeparator) {
1.2538 + groupingCount = 0;
1.2539 + } else if (ch == decimalSeparator) {
1.2540 + if (decimalPos >= 0) {
1.2541 + throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
1.2542 + pattern + '"');
1.2543 + }
1.2544 + decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
1.2545 + } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
1.2546 + if (useExponentialNotation) {
1.2547 + throw new IllegalArgumentException("Multiple exponential " +
1.2548 + "symbols in pattern \"" + pattern + '"');
1.2549 + }
1.2550 + useExponentialNotation = true;
1.2551 + minExponentDigits = 0;
1.2552 +
1.2553 + // Use lookahead to parse out the exponential part
1.2554 + // of the pattern, then jump into phase 2.
1.2555 + pos = pos+exponent.length();
1.2556 + while (pos < pattern.length() &&
1.2557 + pattern.charAt(pos) == zeroDigit) {
1.2558 + ++minExponentDigits;
1.2559 + ++phaseOneLength;
1.2560 + ++pos;
1.2561 + }
1.2562 +
1.2563 + if ((digitLeftCount + zeroDigitCount) < 1 ||
1.2564 + minExponentDigits < 1) {
1.2565 + throw new IllegalArgumentException("Malformed exponential " +
1.2566 + "pattern \"" + pattern + '"');
1.2567 + }
1.2568 +
1.2569 + // Transition to phase 2
1.2570 + phase = 2;
1.2571 + affix = suffix;
1.2572 + --pos;
1.2573 + continue;
1.2574 + } else {
1.2575 + phase = 2;
1.2576 + affix = suffix;
1.2577 + --pos;
1.2578 + --phaseOneLength;
1.2579 + continue;
1.2580 + }
1.2581 + break;
1.2582 + }
1.2583 + }
1.2584 +
1.2585 + // Handle patterns with no '0' pattern character. These patterns
1.2586 + // are legal, but must be interpreted. "##.###" -> "#0.###".
1.2587 + // ".###" -> ".0##".
1.2588 + /* We allow patterns of the form "####" to produce a zeroDigitCount
1.2589 + * of zero (got that?); although this seems like it might make it
1.2590 + * possible for format() to produce empty strings, format() checks
1.2591 + * for this condition and outputs a zero digit in this situation.
1.2592 + * Having a zeroDigitCount of zero yields a minimum integer digits
1.2593 + * of zero, which allows proper round-trip patterns. That is, we
1.2594 + * don't want "#" to become "#0" when toPattern() is called (even
1.2595 + * though that's what it really is, semantically).
1.2596 + */
1.2597 + if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
1.2598 + // Handle "###.###" and "###." and ".###"
1.2599 + int n = decimalPos;
1.2600 + if (n == 0) { // Handle ".###"
1.2601 + ++n;
1.2602 + }
1.2603 + digitRightCount = digitLeftCount - n;
1.2604 + digitLeftCount = n - 1;
1.2605 + zeroDigitCount = 1;
1.2606 + }
1.2607 +
1.2608 + // Do syntax checking on the digits.
1.2609 + if ((decimalPos < 0 && digitRightCount > 0) ||
1.2610 + (decimalPos >= 0 && (decimalPos < digitLeftCount ||
1.2611 + decimalPos > (digitLeftCount + zeroDigitCount))) ||
1.2612 + groupingCount == 0 || inQuote) {
1.2613 + throw new IllegalArgumentException("Malformed pattern \"" +
1.2614 + pattern + '"');
1.2615 + }
1.2616 +
1.2617 + if (j == 1) {
1.2618 + posPrefixPattern = prefix.toString();
1.2619 + posSuffixPattern = suffix.toString();
1.2620 + negPrefixPattern = posPrefixPattern; // assume these for now
1.2621 + negSuffixPattern = posSuffixPattern;
1.2622 + int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
1.2623 + /* The effectiveDecimalPos is the position the decimal is at or
1.2624 + * would be at if there is no decimal. Note that if decimalPos<0,
1.2625 + * then digitTotalCount == digitLeftCount + zeroDigitCount.
1.2626 + */
1.2627 + int effectiveDecimalPos = decimalPos >= 0 ?
1.2628 + decimalPos : digitTotalCount;
1.2629 + setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
1.2630 + setMaximumIntegerDigits(useExponentialNotation ?
1.2631 + digitLeftCount + getMinimumIntegerDigits() :
1.2632 + MAXIMUM_INTEGER_DIGITS);
1.2633 + setMaximumFractionDigits(decimalPos >= 0 ?
1.2634 + (digitTotalCount - decimalPos) : 0);
1.2635 + setMinimumFractionDigits(decimalPos >= 0 ?
1.2636 + (digitLeftCount + zeroDigitCount - decimalPos) : 0);
1.2637 + setGroupingUsed(groupingCount > 0);
1.2638 + this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
1.2639 + this.multiplier = multiplier;
1.2640 + setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
1.2641 + decimalPos == digitTotalCount);
1.2642 + } else {
1.2643 + negPrefixPattern = prefix.toString();
1.2644 + negSuffixPattern = suffix.toString();
1.2645 + gotNegative = true;
1.2646 + }
1.2647 + }
1.2648 +
1.2649 + if (pattern.length() == 0) {
1.2650 + posPrefixPattern = posSuffixPattern = "";
1.2651 + setMinimumIntegerDigits(0);
1.2652 + setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
1.2653 + setMinimumFractionDigits(0);
1.2654 + setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
1.2655 + }
1.2656 +
1.2657 + // If there was no negative pattern, or if the negative pattern is
1.2658 + // identical to the positive pattern, then prepend the minus sign to
1.2659 + // the positive pattern to form the negative pattern.
1.2660 + if (!gotNegative ||
1.2661 + (negPrefixPattern.equals(posPrefixPattern)
1.2662 + && negSuffixPattern.equals(posSuffixPattern))) {
1.2663 + negSuffixPattern = posSuffixPattern;
1.2664 + negPrefixPattern = "'-" + posPrefixPattern;
1.2665 + }
1.2666 +
1.2667 + expandAffixes();
1.2668 + }
1.2669 +
1.2670 + /**
1.2671 + * Sets the maximum number of digits allowed in the integer portion of a
1.2672 + * number.
1.2673 + * For formatting numbers other than <code>BigInteger</code> and
1.2674 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
1.2675 + * 309 is used. Negative input values are replaced with 0.
1.2676 + * @see NumberFormat#setMaximumIntegerDigits
1.2677 + */
1.2678 + public void setMaximumIntegerDigits(int newValue) {
1.2679 + maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
1.2680 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
1.2681 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
1.2682 + if (minimumIntegerDigits > maximumIntegerDigits) {
1.2683 + minimumIntegerDigits = maximumIntegerDigits;
1.2684 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
1.2685 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
1.2686 + }
1.2687 + }
1.2688 +
1.2689 + /**
1.2690 + * Sets the minimum number of digits allowed in the integer portion of a
1.2691 + * number.
1.2692 + * For formatting numbers other than <code>BigInteger</code> and
1.2693 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
1.2694 + * 309 is used. Negative input values are replaced with 0.
1.2695 + * @see NumberFormat#setMinimumIntegerDigits
1.2696 + */
1.2697 + public void setMinimumIntegerDigits(int newValue) {
1.2698 + minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
1.2699 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
1.2700 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
1.2701 + if (minimumIntegerDigits > maximumIntegerDigits) {
1.2702 + maximumIntegerDigits = minimumIntegerDigits;
1.2703 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
1.2704 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
1.2705 + }
1.2706 + }
1.2707 +
1.2708 + /**
1.2709 + * Sets the maximum number of digits allowed in the fraction portion of a
1.2710 + * number.
1.2711 + * For formatting numbers other than <code>BigInteger</code> and
1.2712 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
1.2713 + * 340 is used. Negative input values are replaced with 0.
1.2714 + * @see NumberFormat#setMaximumFractionDigits
1.2715 + */
1.2716 + public void setMaximumFractionDigits(int newValue) {
1.2717 + maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
1.2718 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
1.2719 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
1.2720 + if (minimumFractionDigits > maximumFractionDigits) {
1.2721 + minimumFractionDigits = maximumFractionDigits;
1.2722 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
1.2723 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
1.2724 + }
1.2725 + }
1.2726 +
1.2727 + /**
1.2728 + * Sets the minimum number of digits allowed in the fraction portion of a
1.2729 + * number.
1.2730 + * For formatting numbers other than <code>BigInteger</code> and
1.2731 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
1.2732 + * 340 is used. Negative input values are replaced with 0.
1.2733 + * @see NumberFormat#setMinimumFractionDigits
1.2734 + */
1.2735 + public void setMinimumFractionDigits(int newValue) {
1.2736 + minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
1.2737 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
1.2738 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
1.2739 + if (minimumFractionDigits > maximumFractionDigits) {
1.2740 + maximumFractionDigits = minimumFractionDigits;
1.2741 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
1.2742 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
1.2743 + }
1.2744 + }
1.2745 +
1.2746 + /**
1.2747 + * Gets the maximum number of digits allowed in the integer portion of a
1.2748 + * number.
1.2749 + * For formatting numbers other than <code>BigInteger</code> and
1.2750 + * <code>BigDecimal</code> objects, the lower of the return value and
1.2751 + * 309 is used.
1.2752 + * @see #setMaximumIntegerDigits
1.2753 + */
1.2754 + public int getMaximumIntegerDigits() {
1.2755 + return maximumIntegerDigits;
1.2756 + }
1.2757 +
1.2758 + /**
1.2759 + * Gets the minimum number of digits allowed in the integer portion of a
1.2760 + * number.
1.2761 + * For formatting numbers other than <code>BigInteger</code> and
1.2762 + * <code>BigDecimal</code> objects, the lower of the return value and
1.2763 + * 309 is used.
1.2764 + * @see #setMinimumIntegerDigits
1.2765 + */
1.2766 + public int getMinimumIntegerDigits() {
1.2767 + return minimumIntegerDigits;
1.2768 + }
1.2769 +
1.2770 + /**
1.2771 + * Gets the maximum number of digits allowed in the fraction portion of a
1.2772 + * number.
1.2773 + * For formatting numbers other than <code>BigInteger</code> and
1.2774 + * <code>BigDecimal</code> objects, the lower of the return value and
1.2775 + * 340 is used.
1.2776 + * @see #setMaximumFractionDigits
1.2777 + */
1.2778 + public int getMaximumFractionDigits() {
1.2779 + return maximumFractionDigits;
1.2780 + }
1.2781 +
1.2782 + /**
1.2783 + * Gets the minimum number of digits allowed in the fraction portion of a
1.2784 + * number.
1.2785 + * For formatting numbers other than <code>BigInteger</code> and
1.2786 + * <code>BigDecimal</code> objects, the lower of the return value and
1.2787 + * 340 is used.
1.2788 + * @see #setMinimumFractionDigits
1.2789 + */
1.2790 + public int getMinimumFractionDigits() {
1.2791 + return minimumFractionDigits;
1.2792 + }
1.2793 +
1.2794 + /**
1.2795 + * Gets the currency used by this decimal format when formatting
1.2796 + * currency values.
1.2797 + * The currency is obtained by calling
1.2798 + * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
1.2799 + * on this number format's symbols.
1.2800 + *
1.2801 + * @return the currency used by this decimal format, or <code>null</code>
1.2802 + * @since 1.4
1.2803 + */
1.2804 + public Currency getCurrency() {
1.2805 + return symbols.getCurrency();
1.2806 + }
1.2807 +
1.2808 + /**
1.2809 + * Sets the currency used by this number format when formatting
1.2810 + * currency values. This does not update the minimum or maximum
1.2811 + * number of fraction digits used by the number format.
1.2812 + * The currency is set by calling
1.2813 + * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
1.2814 + * on this number format's symbols.
1.2815 + *
1.2816 + * @param currency the new currency to be used by this decimal format
1.2817 + * @exception NullPointerException if <code>currency</code> is null
1.2818 + * @since 1.4
1.2819 + */
1.2820 + public void setCurrency(Currency currency) {
1.2821 + if (currency != symbols.getCurrency()) {
1.2822 + symbols.setCurrency(currency);
1.2823 + if (isCurrencyFormat) {
1.2824 + expandAffixes();
1.2825 + }
1.2826 + }
1.2827 + }
1.2828 +
1.2829 + /**
1.2830 + * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
1.2831 + *
1.2832 + * @return The <code>RoundingMode</code> used for this DecimalFormat.
1.2833 + * @see #setRoundingMode(RoundingMode)
1.2834 + * @since 1.6
1.2835 + */
1.2836 + public RoundingMode getRoundingMode() {
1.2837 + return roundingMode;
1.2838 + }
1.2839 +
1.2840 + /**
1.2841 + * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
1.2842 + *
1.2843 + * @param roundingMode The <code>RoundingMode</code> to be used
1.2844 + * @see #getRoundingMode()
1.2845 + * @exception NullPointerException if <code>roundingMode</code> is null.
1.2846 + * @since 1.6
1.2847 + */
1.2848 + public void setRoundingMode(RoundingMode roundingMode) {
1.2849 + if (roundingMode == null) {
1.2850 + throw new NullPointerException();
1.2851 + }
1.2852 +
1.2853 + this.roundingMode = roundingMode;
1.2854 + digitList.setRoundingMode(roundingMode);
1.2855 + }
1.2856 +
1.2857 + /**
1.2858 + * Adjusts the minimum and maximum fraction digits to values that
1.2859 + * are reasonable for the currency's default fraction digits.
1.2860 + */
1.2861 + void adjustForCurrencyDefaultFractionDigits() {
1.2862 + Currency currency = symbols.getCurrency();
1.2863 + if (currency == null) {
1.2864 + try {
1.2865 + currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
1.2866 + } catch (IllegalArgumentException e) {
1.2867 + }
1.2868 + }
1.2869 + if (currency != null) {
1.2870 + int digits = currency.getDefaultFractionDigits();
1.2871 + if (digits != -1) {
1.2872 + int oldMinDigits = getMinimumFractionDigits();
1.2873 + // Common patterns are "#.##", "#.00", "#".
1.2874 + // Try to adjust all of them in a reasonable way.
1.2875 + if (oldMinDigits == getMaximumFractionDigits()) {
1.2876 + setMinimumFractionDigits(digits);
1.2877 + setMaximumFractionDigits(digits);
1.2878 + } else {
1.2879 + setMinimumFractionDigits(Math.min(digits, oldMinDigits));
1.2880 + setMaximumFractionDigits(digits);
1.2881 + }
1.2882 + }
1.2883 + }
1.2884 + }
1.2885 +
1.2886 + /**
1.2887 + * Reads the default serializable fields from the stream and performs
1.2888 + * validations and adjustments for older serialized versions. The
1.2889 + * validations and adjustments are:
1.2890 + * <ol>
1.2891 + * <li>
1.2892 + * Verify that the superclass's digit count fields correctly reflect
1.2893 + * the limits imposed on formatting numbers other than
1.2894 + * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
1.2895 + * limits are stored in the superclass for serialization compatibility
1.2896 + * with older versions, while the limits for <code>BigInteger</code> and
1.2897 + * <code>BigDecimal</code> objects are kept in this class.
1.2898 + * If, in the superclass, the minimum or maximum integer digit count is
1.2899 + * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
1.2900 + * maximum fraction digit count is larger than
1.2901 + * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
1.2902 + * and this method throws an <code>InvalidObjectException</code>.
1.2903 + * <li>
1.2904 + * If <code>serialVersionOnStream</code> is less than 4, initialize
1.2905 + * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
1.2906 + * RoundingMode.HALF_EVEN}. This field is new with version 4.
1.2907 + * <li>
1.2908 + * If <code>serialVersionOnStream</code> is less than 3, then call
1.2909 + * the setters for the minimum and maximum integer and fraction digits with
1.2910 + * the values of the corresponding superclass getters to initialize the
1.2911 + * fields in this class. The fields in this class are new with version 3.
1.2912 + * <li>
1.2913 + * If <code>serialVersionOnStream</code> is less than 1, indicating that
1.2914 + * the stream was written by JDK 1.1, initialize
1.2915 + * <code>useExponentialNotation</code>
1.2916 + * to false, since it was not present in JDK 1.1.
1.2917 + * <li>
1.2918 + * Set <code>serialVersionOnStream</code> to the maximum allowed value so
1.2919 + * that default serialization will work properly if this object is streamed
1.2920 + * out again.
1.2921 + * </ol>
1.2922 + *
1.2923 + * <p>Stream versions older than 2 will not have the affix pattern variables
1.2924 + * <code>posPrefixPattern</code> etc. As a result, they will be initialized
1.2925 + * to <code>null</code>, which means the affix strings will be taken as
1.2926 + * literal values. This is exactly what we want, since that corresponds to
1.2927 + * the pre-version-2 behavior.
1.2928 + */
1.2929 + private void readObject(ObjectInputStream stream)
1.2930 + throws IOException, ClassNotFoundException
1.2931 + {
1.2932 + stream.defaultReadObject();
1.2933 + digitList = new DigitList();
1.2934 +
1.2935 + if (serialVersionOnStream < 4) {
1.2936 + setRoundingMode(RoundingMode.HALF_EVEN);
1.2937 + }
1.2938 + // We only need to check the maximum counts because NumberFormat
1.2939 + // .readObject has already ensured that the maximum is greater than the
1.2940 + // minimum count.
1.2941 + if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
1.2942 + super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
1.2943 + throw new InvalidObjectException("Digit count out of range");
1.2944 + }
1.2945 + if (serialVersionOnStream < 3) {
1.2946 + setMaximumIntegerDigits(super.getMaximumIntegerDigits());
1.2947 + setMinimumIntegerDigits(super.getMinimumIntegerDigits());
1.2948 + setMaximumFractionDigits(super.getMaximumFractionDigits());
1.2949 + setMinimumFractionDigits(super.getMinimumFractionDigits());
1.2950 + }
1.2951 + if (serialVersionOnStream < 1) {
1.2952 + // Didn't have exponential fields
1.2953 + useExponentialNotation = false;
1.2954 + }
1.2955 + serialVersionOnStream = currentSerialVersion;
1.2956 + }
1.2957 +
1.2958 + //----------------------------------------------------------------------
1.2959 + // INSTANCE VARIABLES
1.2960 + //----------------------------------------------------------------------
1.2961 +
1.2962 + private transient DigitList digitList = new DigitList();
1.2963 +
1.2964 + /**
1.2965 + * The symbol used as a prefix when formatting positive numbers, e.g. "+".
1.2966 + *
1.2967 + * @serial
1.2968 + * @see #getPositivePrefix
1.2969 + */
1.2970 + private String positivePrefix = "";
1.2971 +
1.2972 + /**
1.2973 + * The symbol used as a suffix when formatting positive numbers.
1.2974 + * This is often an empty string.
1.2975 + *
1.2976 + * @serial
1.2977 + * @see #getPositiveSuffix
1.2978 + */
1.2979 + private String positiveSuffix = "";
1.2980 +
1.2981 + /**
1.2982 + * The symbol used as a prefix when formatting negative numbers, e.g. "-".
1.2983 + *
1.2984 + * @serial
1.2985 + * @see #getNegativePrefix
1.2986 + */
1.2987 + private String negativePrefix = "-";
1.2988 +
1.2989 + /**
1.2990 + * The symbol used as a suffix when formatting negative numbers.
1.2991 + * This is often an empty string.
1.2992 + *
1.2993 + * @serial
1.2994 + * @see #getNegativeSuffix
1.2995 + */
1.2996 + private String negativeSuffix = "";
1.2997 +
1.2998 + /**
1.2999 + * The prefix pattern for non-negative numbers. This variable corresponds
1.3000 + * to <code>positivePrefix</code>.
1.3001 + *
1.3002 + * <p>This pattern is expanded by the method <code>expandAffix()</code> to
1.3003 + * <code>positivePrefix</code> to update the latter to reflect changes in
1.3004 + * <code>symbols</code>. If this variable is <code>null</code> then
1.3005 + * <code>positivePrefix</code> is taken as a literal value that does not
1.3006 + * change when <code>symbols</code> changes. This variable is always
1.3007 + * <code>null</code> for <code>DecimalFormat</code> objects older than
1.3008 + * stream version 2 restored from stream.
1.3009 + *
1.3010 + * @serial
1.3011 + * @since 1.3
1.3012 + */
1.3013 + private String posPrefixPattern;
1.3014 +
1.3015 + /**
1.3016 + * The suffix pattern for non-negative numbers. This variable corresponds
1.3017 + * to <code>positiveSuffix</code>. This variable is analogous to
1.3018 + * <code>posPrefixPattern</code>; see that variable for further
1.3019 + * documentation.
1.3020 + *
1.3021 + * @serial
1.3022 + * @since 1.3
1.3023 + */
1.3024 + private String posSuffixPattern;
1.3025 +
1.3026 + /**
1.3027 + * The prefix pattern for negative numbers. This variable corresponds
1.3028 + * to <code>negativePrefix</code>. This variable is analogous to
1.3029 + * <code>posPrefixPattern</code>; see that variable for further
1.3030 + * documentation.
1.3031 + *
1.3032 + * @serial
1.3033 + * @since 1.3
1.3034 + */
1.3035 + private String negPrefixPattern;
1.3036 +
1.3037 + /**
1.3038 + * The suffix pattern for negative numbers. This variable corresponds
1.3039 + * to <code>negativeSuffix</code>. This variable is analogous to
1.3040 + * <code>posPrefixPattern</code>; see that variable for further
1.3041 + * documentation.
1.3042 + *
1.3043 + * @serial
1.3044 + * @since 1.3
1.3045 + */
1.3046 + private String negSuffixPattern;
1.3047 +
1.3048 + /**
1.3049 + * The multiplier for use in percent, per mille, etc.
1.3050 + *
1.3051 + * @serial
1.3052 + * @see #getMultiplier
1.3053 + */
1.3054 + private int multiplier = 1;
1.3055 +
1.3056 + /**
1.3057 + * The number of digits between grouping separators in the integer
1.3058 + * portion of a number. Must be greater than 0 if
1.3059 + * <code>NumberFormat.groupingUsed</code> is true.
1.3060 + *
1.3061 + * @serial
1.3062 + * @see #getGroupingSize
1.3063 + * @see java.text.NumberFormat#isGroupingUsed
1.3064 + */
1.3065 + private byte groupingSize = 3; // invariant, > 0 if useThousands
1.3066 +
1.3067 + /**
1.3068 + * If true, forces the decimal separator to always appear in a formatted
1.3069 + * number, even if the fractional part of the number is zero.
1.3070 + *
1.3071 + * @serial
1.3072 + * @see #isDecimalSeparatorAlwaysShown
1.3073 + */
1.3074 + private boolean decimalSeparatorAlwaysShown = false;
1.3075 +
1.3076 + /**
1.3077 + * If true, parse returns BigDecimal wherever possible.
1.3078 + *
1.3079 + * @serial
1.3080 + * @see #isParseBigDecimal
1.3081 + * @since 1.5
1.3082 + */
1.3083 + private boolean parseBigDecimal = false;
1.3084 +
1.3085 +
1.3086 + /**
1.3087 + * True if this object represents a currency format. This determines
1.3088 + * whether the monetary decimal separator is used instead of the normal one.
1.3089 + */
1.3090 + private transient boolean isCurrencyFormat = false;
1.3091 +
1.3092 + /**
1.3093 + * The <code>DecimalFormatSymbols</code> object used by this format.
1.3094 + * It contains the symbols used to format numbers, e.g. the grouping separator,
1.3095 + * decimal separator, and so on.
1.3096 + *
1.3097 + * @serial
1.3098 + * @see #setDecimalFormatSymbols
1.3099 + * @see java.text.DecimalFormatSymbols
1.3100 + */
1.3101 + private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
1.3102 +
1.3103 + /**
1.3104 + * True to force the use of exponential (i.e. scientific) notation when formatting
1.3105 + * numbers.
1.3106 + *
1.3107 + * @serial
1.3108 + * @since 1.2
1.3109 + */
1.3110 + private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2
1.3111 +
1.3112 + /**
1.3113 + * FieldPositions describing the positive prefix String. This is
1.3114 + * lazily created. Use <code>getPositivePrefixFieldPositions</code>
1.3115 + * when needed.
1.3116 + */
1.3117 + private transient FieldPosition[] positivePrefixFieldPositions;
1.3118 +
1.3119 + /**
1.3120 + * FieldPositions describing the positive suffix String. This is
1.3121 + * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
1.3122 + * when needed.
1.3123 + */
1.3124 + private transient FieldPosition[] positiveSuffixFieldPositions;
1.3125 +
1.3126 + /**
1.3127 + * FieldPositions describing the negative prefix String. This is
1.3128 + * lazily created. Use <code>getNegativePrefixFieldPositions</code>
1.3129 + * when needed.
1.3130 + */
1.3131 + private transient FieldPosition[] negativePrefixFieldPositions;
1.3132 +
1.3133 + /**
1.3134 + * FieldPositions describing the negative suffix String. This is
1.3135 + * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
1.3136 + * when needed.
1.3137 + */
1.3138 + private transient FieldPosition[] negativeSuffixFieldPositions;
1.3139 +
1.3140 + /**
1.3141 + * The minimum number of digits used to display the exponent when a number is
1.3142 + * formatted in exponential notation. This field is ignored if
1.3143 + * <code>useExponentialNotation</code> is not true.
1.3144 + *
1.3145 + * @serial
1.3146 + * @since 1.2
1.3147 + */
1.3148 + private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2
1.3149 +
1.3150 + /**
1.3151 + * The maximum number of digits allowed in the integer portion of a
1.3152 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
1.3153 + * <code>maximumIntegerDigits</code> must be greater than or equal to
1.3154 + * <code>minimumIntegerDigits</code>.
1.3155 + *
1.3156 + * @serial
1.3157 + * @see #getMaximumIntegerDigits
1.3158 + * @since 1.5
1.3159 + */
1.3160 + private int maximumIntegerDigits = super.getMaximumIntegerDigits();
1.3161 +
1.3162 + /**
1.3163 + * The minimum number of digits allowed in the integer portion of a
1.3164 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
1.3165 + * <code>minimumIntegerDigits</code> must be less than or equal to
1.3166 + * <code>maximumIntegerDigits</code>.
1.3167 + *
1.3168 + * @serial
1.3169 + * @see #getMinimumIntegerDigits
1.3170 + * @since 1.5
1.3171 + */
1.3172 + private int minimumIntegerDigits = super.getMinimumIntegerDigits();
1.3173 +
1.3174 + /**
1.3175 + * The maximum number of digits allowed in the fractional portion of a
1.3176 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
1.3177 + * <code>maximumFractionDigits</code> must be greater than or equal to
1.3178 + * <code>minimumFractionDigits</code>.
1.3179 + *
1.3180 + * @serial
1.3181 + * @see #getMaximumFractionDigits
1.3182 + * @since 1.5
1.3183 + */
1.3184 + private int maximumFractionDigits = super.getMaximumFractionDigits();
1.3185 +
1.3186 + /**
1.3187 + * The minimum number of digits allowed in the fractional portion of a
1.3188 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
1.3189 + * <code>minimumFractionDigits</code> must be less than or equal to
1.3190 + * <code>maximumFractionDigits</code>.
1.3191 + *
1.3192 + * @serial
1.3193 + * @see #getMinimumFractionDigits
1.3194 + * @since 1.5
1.3195 + */
1.3196 + private int minimumFractionDigits = super.getMinimumFractionDigits();
1.3197 +
1.3198 + /**
1.3199 + * The {@link java.math.RoundingMode} used in this DecimalFormat.
1.3200 + *
1.3201 + * @serial
1.3202 + * @since 1.6
1.3203 + */
1.3204 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
1.3205 +
1.3206 + //----------------------------------------------------------------------
1.3207 +
1.3208 + static final int currentSerialVersion = 4;
1.3209 +
1.3210 + /**
1.3211 + * The internal serial version which says which version was written.
1.3212 + * Possible values are:
1.3213 + * <ul>
1.3214 + * <li><b>0</b> (default): versions before the Java 2 platform v1.2
1.3215 + * <li><b>1</b>: version for 1.2, which includes the two new fields
1.3216 + * <code>useExponentialNotation</code> and
1.3217 + * <code>minExponentDigits</code>.
1.3218 + * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
1.3219 + * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
1.3220 + * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
1.3221 + * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
1.3222 + * <code>maximumIntegerDigits</code>,
1.3223 + * <code>minimumIntegerDigits</code>,
1.3224 + * <code>maximumFractionDigits</code>,
1.3225 + * <code>minimumFractionDigits</code>, and
1.3226 + * <code>parseBigDecimal</code>.
1.3227 + * <li><b>4</b>: version for 1.6 and later, which adds one new field:
1.3228 + * <code>roundingMode</code>.
1.3229 + * </ul>
1.3230 + * @since 1.2
1.3231 + * @serial
1.3232 + */
1.3233 + private int serialVersionOnStream = currentSerialVersion;
1.3234 +
1.3235 + //----------------------------------------------------------------------
1.3236 + // CONSTANTS
1.3237 + //----------------------------------------------------------------------
1.3238 +
1.3239 + // Constants for characters used in programmatic (unlocalized) patterns.
1.3240 + private static final char PATTERN_ZERO_DIGIT = '0';
1.3241 + private static final char PATTERN_GROUPING_SEPARATOR = ',';
1.3242 + private static final char PATTERN_DECIMAL_SEPARATOR = '.';
1.3243 + private static final char PATTERN_PER_MILLE = '\u2030';
1.3244 + private static final char PATTERN_PERCENT = '%';
1.3245 + private static final char PATTERN_DIGIT = '#';
1.3246 + private static final char PATTERN_SEPARATOR = ';';
1.3247 + private static final String PATTERN_EXPONENT = "E";
1.3248 + private static final char PATTERN_MINUS = '-';
1.3249 +
1.3250 + /**
1.3251 + * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
1.3252 + * is used in patterns and substituted with either the currency symbol,
1.3253 + * or if it is doubled, with the international currency symbol. If the
1.3254 + * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
1.3255 + * replaced with the monetary decimal separator.
1.3256 + *
1.3257 + * The CURRENCY_SIGN is not localized.
1.3258 + */
1.3259 + private static final char CURRENCY_SIGN = '\u00A4';
1.3260 +
1.3261 + private static final char QUOTE = '\'';
1.3262 +
1.3263 + private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
1.3264 +
1.3265 + // Upper limit on integer and fraction digits for a Java double
1.3266 + static final int DOUBLE_INTEGER_DIGITS = 309;
1.3267 + static final int DOUBLE_FRACTION_DIGITS = 340;
1.3268 +
1.3269 + // Upper limit on integer and fraction digits for BigDecimal and BigInteger
1.3270 + static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE;
1.3271 + static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
1.3272 +
1.3273 + // Proclaim JDK 1.1 serial compatibility.
1.3274 + static final long serialVersionUID = 864413376551465018L;
1.3275 +
1.3276 + /**
1.3277 + * Cache to hold the NumberPattern of a Locale.
1.3278 + */
1.3279 + private static final ConcurrentMap<Locale, String> cachedLocaleData
1.3280 + = new ConcurrentHashMap<Locale, String>(3);
1.3281 +}