1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 /* 28 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 29 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 30 * 31 * The original version of this source code and documentation is copyrighted 32 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These 33 * materials are provided under terms of a License Agreement between Taligent 34 * and Sun. This technology is protected by multiple US and International 35 * patents. This notice and attribution to Taligent may not be removed. 36 * Taligent is a registered trademark of Taligent, Inc. 37 * 38 */ 39 40 package java.text; 41 42 import java.io.IOException; 43 import java.io.ObjectInputStream; 44 import java.io.ObjectOutputStream; 45 import java.io.ObjectStreamField; 46 import java.math.BigDecimal; 47 import java.math.BigInteger; 48 import java.math.RoundingMode; 49 import java.util.Currency; 50 import java.util.Locale; 51 import java.util.Objects; 52 import java.util.concurrent.atomic.AtomicInteger; 53 import java.util.concurrent.atomic.AtomicLong; 54 import libcore.icu.DecimalFormatData; 55 import libcore.icu.LocaleData; 56 import android.icu.math.MathContext; 57 58 import com.android.icu.text.CompatibleDecimalFormatFactory; 59 60 /** 61 * {@code DecimalFormat} is a concrete subclass of 62 * {@code NumberFormat} that formats decimal numbers. It has a variety of 63 * features designed to make it possible to parse and format numbers in any 64 * locale, including support for Western, Arabic, and Indic digits. It also 65 * supports different kinds of numbers, including integers (123), fixed-point 66 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and 67 * currency amounts ($123). All of these can be localized. 68 * 69 * <p>To obtain a {@code NumberFormat} for a specific locale, including the 70 * default locale, call one of {@code NumberFormat}'s factory methods, such 71 * as {@code getInstance()}. In general, do not call the 72 * {@code DecimalFormat} constructors directly, since the 73 * {@code NumberFormat} factory methods may return subclasses other than 74 * {@code DecimalFormat}. If you need to customize the format object, do 75 * something like this: 76 * 77 * <blockquote><pre> 78 * NumberFormat f = NumberFormat.getInstance(loc); 79 * if (f instanceof DecimalFormat) { 80 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true); 81 * } 82 * </pre></blockquote> 83 * 84 * <p>A {@code DecimalFormat} comprises a <em>pattern</em> and a set of 85 * <em>symbols</em>. The pattern may be set directly using 86 * {@code applyPattern()}, or indirectly using the API methods. The 87 * symbols are stored in a {@code DecimalFormatSymbols} object. When using 88 * the {@code NumberFormat} factory methods, the pattern and symbols are 89 * read from localized {@code ResourceBundle}s. 90 * 91 * <h2>Patterns</h2> 92 * 93 * {@code DecimalFormat} patterns have the following syntax: 94 * <blockquote><pre> 95 * <i>Pattern:</i> 96 * <i>PositivePattern</i> 97 * <i>PositivePattern</i> ; <i>NegativePattern</i> 98 * <i>PositivePattern:</i> 99 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 100 * <i>NegativePattern:</i> 101 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 102 * <i>Prefix:</i> 103 * any Unicode characters except \uFFFE, \uFFFF, and special characters 104 * <i>Suffix:</i> 105 * any Unicode characters except \uFFFE, \uFFFF, and special characters 106 * <i>Number:</i> 107 * <i>Integer</i> <i>Exponent<sub>opt</sub></i> 108 * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i> 109 * <i>Integer:</i> 110 * <i>MinimumInteger</i> 111 * # 112 * # <i>Integer</i> 113 * # , <i>Integer</i> 114 * <i>MinimumInteger:</i> 115 * 0 116 * 0 <i>MinimumInteger</i> 117 * 0 , <i>MinimumInteger</i> 118 * <i>Fraction:</i> 119 * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i> 120 * <i>MinimumFraction:</i> 121 * 0 <i>MinimumFraction<sub>opt</sub></i> 122 * <i>OptionalFraction:</i> 123 * # <i>OptionalFraction<sub>opt</sub></i> 124 * <i>Exponent:</i> 125 * E <i>MinimumExponent</i> 126 * <i>MinimumExponent:</i> 127 * 0 <i>MinimumExponent<sub>opt</sub></i> 128 * </pre></blockquote> 129 * 130 * <p>A {@code DecimalFormat} pattern contains a positive and negative 131 * subpattern, for example, {@code "#,##0.00;(#,##0.00)"}. Each 132 * subpattern has a prefix, numeric part, and suffix. The negative subpattern 133 * is optional; if absent, then the positive subpattern prefixed with the 134 * minus sign ({@code '-' U+002D HYPHEN-MINUS}) is used as the 135 * negative subpattern. That is, {@code "0.00"} alone is equivalent to 136 * {@code "0.00;-0.00"}. If there is an explicit negative subpattern, it 137 * serves only to specify the negative prefix and suffix; the number of digits, 138 * minimal digits, and other characteristics are all the same as the positive 139 * pattern. That means that {@code "#,##0.0#;(#)"} produces precisely 140 * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}. 141 * 142 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, 143 * grouping separators, decimal separators, etc. may be set to arbitrary 144 * values, and they will appear properly during formatting. However, care must 145 * be taken that the symbols and strings do not conflict, or parsing will be 146 * unreliable. For example, either the positive and negative prefixes or the 147 * suffixes must be distinct for {@code DecimalFormat.parse()} to be able 148 * to distinguish positive from negative values. (If they are identical, then 149 * {@code DecimalFormat} will behave as if no negative subpattern was 150 * specified.) Another example is that the decimal separator and grouping 151 * separator should be distinct characters, or parsing will be impossible. 152 * 153 * <p>The grouping separator is commonly used for thousands, but in some 154 * countries it separates ten-thousands. The grouping size is a constant number 155 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for 156 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the 157 * interval between the last one and the end of the integer is the one that is 158 * used. So {@code "#,##,###,####"} == {@code "######,####"} == 159 * {@code "##,####,####"}. 160 * 161 * <h3><a id="special_pattern_character">Special Pattern Characters</a></h3> 162 * 163 * <p>Many characters in a pattern are taken literally; they are matched during 164 * parsing and output unchanged during formatting. Special characters, on the 165 * other hand, stand for other characters, strings, or classes of characters. 166 * They must be quoted, unless noted otherwise, if they are to appear in the 167 * prefix or suffix as literals. 168 * 169 * <p>The characters listed here are used in non-localized patterns. Localized 170 * patterns use the corresponding characters taken from this formatter's 171 * {@code DecimalFormatSymbols} object instead, and these characters lose 172 * their special status. Two exceptions are the currency sign and quote, which 173 * are not localized. 174 * 175 * <blockquote> 176 * <table class="striped"> 177 * <caption style="display:none">Chart showing symbol, location, localized, and meaning.</caption> 178 * <thead> 179 * <tr> 180 * <th scope="col" style="text-align:left">Symbol 181 * <th scope="col" style="text-align:left">Location 182 * <th scope="col" style="text-align:left">Localized? 183 * <th scope="col" style="text-align:left">Meaning 184 * </thead> 185 * <tbody> 186 * <tr style="vertical-align:top"> 187 * <th scope="row">{@code 0} 188 * <td>Number 189 * <td>Yes 190 * <td>Digit 191 * <tr style="vertical-align: top"> 192 * <th scope="row">{@code #} 193 * <td>Number 194 * <td>Yes 195 * <td>Digit, zero shows as absent 196 * <tr style="vertical-align:top"> 197 * <th scope="row">{@code .} 198 * <td>Number 199 * <td>Yes 200 * <td>Decimal separator or monetary decimal separator 201 * <tr style="vertical-align: top"> 202 * <th scope="row">{@code -} 203 * <td>Number 204 * <td>Yes 205 * <td>Minus sign 206 * <tr style="vertical-align:top"> 207 * <th scope="row">{@code ,} 208 * <td>Number 209 * <td>Yes 210 * <td>Grouping separator or monetary grouping separator 211 * <tr style="vertical-align: top"> 212 * <th scope="row">{@code E} 213 * <td>Number 214 * <td>Yes 215 * <td>Separates mantissa and exponent in scientific notation. 216 * <em>Need not be quoted in prefix or suffix.</em> 217 * <tr style="vertical-align:top"> 218 * <th scope="row">{@code ;} 219 * <td>Subpattern boundary 220 * <td>Yes 221 * <td>Separates positive and negative subpatterns 222 * <tr style="vertical-align: top"> 223 * <th scope="row">{@code %} 224 * <td>Prefix or suffix 225 * <td>Yes 226 * <td>Multiply by 100 and show as percentage 227 * <tr style="vertical-align:top"> 228 * <th scope="row">{@code \u2030} 229 * <td>Prefix or suffix 230 * <td>Yes 231 * <td>Multiply by 1000 and show as per mille value 232 * <tr style="vertical-align: top"> 233 * <th scope="row">{@code ¤} ({@code \u00A4}) 234 * <td>Prefix or suffix 235 * <td>No 236 * <td>Currency sign, replaced by currency symbol. If 237 * doubled, replaced by international currency symbol. 238 * If present in a pattern, the monetary decimal/grouping separators 239 * are used instead of the decimal/grouping separators. 240 * <tr style="vertical-align:top"> 241 * <th scope="row">{@code '} 242 * <td>Prefix or suffix 243 * <td>No 244 * <td>Used to quote special characters in a prefix or suffix, 245 * for example, {@code "'#'#"} formats 123 to 246 * {@code "#123"}. To create a single quote 247 * itself, use two in a row: {@code "# o''clock"}. 248 * </tbody> 249 * </table> 250 * </blockquote> 251 * 252 * <h3>Scientific Notation</h3> 253 * 254 * <p>Numbers in scientific notation are expressed as the product of a mantissa 255 * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The 256 * mantissa is often in the range 1.0 ≤ x {@literal <} 10.0, but it need not 257 * be. 258 * {@code DecimalFormat} can be instructed to format and parse scientific 259 * notation <em>only via a pattern</em>; there is currently no factory method 260 * that creates a scientific notation format. In a pattern, the exponent 261 * character immediately followed by one or more digit characters indicates 262 * scientific notation. Example: {@code "0.###E0"} formats the number 263 * 1234 as {@code "1.234E3"}. 264 * 265 * <ul> 266 * <li>The number of digit characters after the exponent character gives the 267 * minimum exponent digit count. There is no maximum. Negative exponents are 268 * formatted using the localized minus sign, <em>not</em> the prefix and suffix 269 * from the pattern. This allows patterns such as {@code "0.###E0 m/s"}. 270 * 271 * <li>The minimum and maximum number of integer digits are interpreted 272 * together: 273 * 274 * <ul> 275 * <li>If the maximum number of integer digits is greater than their minimum number 276 * and greater than 1, it forces the exponent to be a multiple of the maximum 277 * number of integer digits, and the minimum number of integer digits to be 278 * interpreted as 1. The most common use of this is to generate 279 * <em>engineering notation</em>, in which the exponent is a multiple of three, 280 * e.g., {@code "##0.#####E0"}. Using this pattern, the number 12345 281 * formats to {@code "12.345E3"}, and 123456 formats to 282 * {@code "123.456E3"}. 283 * 284 * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the 285 * exponent. Example: 0.00123 formatted with {@code "00.###E0"} yields 286 * {@code "12.3E-4"}. 287 * </ul> 288 * 289 * <li>The number of significant digits in the mantissa is the sum of the 290 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is 291 * unaffected by the maximum integer digits. For example, 12345 formatted with 292 * {@code "##0.##E0"} is {@code "12.3E3"}. To show all digits, set 293 * the significant digits count to zero. The number of significant digits 294 * does not affect parsing. 295 * 296 * <li>Exponential patterns may not contain grouping separators. 297 * </ul> 298 * 299 * <h3>Rounding</h3> 300 * 301 * {@code DecimalFormat} provides rounding modes defined in 302 * {@link java.math.RoundingMode} for formatting. By default, it uses 303 * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}. 304 * 305 * <h3>Digits</h3> 306 * 307 * For formatting, {@code DecimalFormat} uses the ten consecutive 308 * characters starting with the localized zero digit defined in the 309 * {@code DecimalFormatSymbols} object as digits. For parsing, these 310 * digits as well as all Unicode decimal digits, as defined by 311 * {@link Character#digit Character.digit}, are recognized. 312 * 313 * <h4>Special Values</h4> 314 * 315 * <p>{@code NaN} is formatted as a string, which typically has a single character 316 * {@code \uFFFD}. This string is determined by the 317 * {@code DecimalFormatSymbols} object. This is the only value for which 318 * the prefixes and suffixes are not used. 319 * 320 * <p>Infinity is formatted as a string, which typically has a single character 321 * {@code \u221E}, with the positive or negative prefixes and suffixes 322 * applied. The infinity string is determined by the 323 * {@code DecimalFormatSymbols} object. 324 * 325 * <p>Negative zero ({@code "-0"}) parses to 326 * <ul> 327 * <li>{@code BigDecimal(0)} if {@code isParseBigDecimal()} is 328 * true, 329 * <li>{@code Long(0)} if {@code isParseBigDecimal()} is false 330 * and {@code isParseIntegerOnly()} is true, 331 * <li>{@code Double(-0.0)} if both {@code isParseBigDecimal()} 332 * and {@code isParseIntegerOnly()} are false. 333 * </ul> 334 * 335 * <h3><a id="synchronization">Synchronization</a></h3> 336 * 337 * <p> 338 * Decimal formats are generally not synchronized. 339 * It is recommended to create separate format instances for each thread. 340 * If multiple threads access a format concurrently, it must be synchronized 341 * externally. 342 * 343 * <h3>Example</h3> 344 * 345 * <blockquote><pre><strong>{@code 346 * // Print out a number using the localized number, integer, currency, 347 * // and percent format for each locale}</strong>{@code 348 * Locale[] locales = NumberFormat.getAvailableLocales(); 349 * double myNumber = -1234.56; 350 * NumberFormat form; 351 * for (int j = 0; j < 4; ++j) { 352 * System.out.println("FORMAT"); 353 * for (int i = 0; i < locales.length; ++i) { 354 * if (locales[i].getCountry().length() == 0) { 355 * continue; // Skip language-only locales 356 * } 357 * System.out.print(locales[i].getDisplayName()); 358 * switch (j) { 359 * case 0: 360 * form = NumberFormat.getInstance(locales[i]); break; 361 * case 1: 362 * form = NumberFormat.getIntegerInstance(locales[i]); break; 363 * case 2: 364 * form = NumberFormat.getCurrencyInstance(locales[i]); break; 365 * default: 366 * form = NumberFormat.getPercentInstance(locales[i]); break; 367 * } 368 * if (form instanceof DecimalFormat) { 369 * System.out.print(": " + ((DecimalFormat) form).toPattern()); 370 * } 371 * System.out.print(" -> " + form.format(myNumber)); 372 * try { 373 * System.out.println(" -> " + form.parse(form.format(myNumber))); 374 * } catch (ParseException e) {} 375 * } 376 * } 377 * }</pre></blockquote> 378 * 379 * @see <a href="http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a> 380 * @see NumberFormat 381 * @see DecimalFormatSymbols 382 * @see ParsePosition 383 * @author Mark Davis 384 * @author Alan Liu 385 * @since 1.1 386 */ 387 public class DecimalFormat extends NumberFormat { 388 389 // Android-note: This class is heavily modified from upstream OpenJDK. 390 // Android's version delegates most of its work to android.icu.text.DecimalFormat. This is done 391 // to avoid code duplication and to stay compatible with earlier releases that used ICU4C/ICU4J 392 // to implement DecimalFormat. 393 394 // Android-added: ICU DecimalFormat to delegate to. 395 private transient android.icu.text.DecimalFormat icuDecimalFormat; 396 397 /** 398 * Creates a DecimalFormat using the default pattern and symbols 399 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 400 * This is a convenient way to obtain a 401 * DecimalFormat when internationalization is not the main concern. 402 * <p> 403 * To obtain standard formats for a given locale, use the factory methods 404 * on NumberFormat such as getNumberInstance. These factories will 405 * return the most appropriate sub-class of NumberFormat for a given 406 * locale. 407 * 408 * @see java.text.NumberFormat#getInstance 409 * @see java.text.NumberFormat#getNumberInstance 410 * @see java.text.NumberFormat#getCurrencyInstance 411 * @see java.text.NumberFormat#getPercentInstance 412 */ DecimalFormat()413 public DecimalFormat() { 414 // Get the pattern for the default locale. 415 Locale def = Locale.getDefault(Locale.Category.FORMAT); 416 // BEGIN Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 417 /* 418 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); 419 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 420 adapter = LocaleProviderAdapter.getResourceBundleBased(); 421 } 422 String[] all = adapter.getLocaleResources(def).getNumberPatterns(); 423 */ 424 String pattern = DecimalFormatData.getInstance(def).getNumberPattern(); 425 // END Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 426 427 // Always applyPattern after the symbols are set 428 this.symbols = DecimalFormatSymbols.getInstance(def); 429 // Android-changed: initPattern() and conversion methods between ICU and Java values. 430 // applyPattern(all[0], false); 431 initPattern(pattern); 432 } 433 434 435 /** 436 * Creates a DecimalFormat using the given pattern and the symbols 437 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 438 * This is a convenient way to obtain a 439 * DecimalFormat when internationalization is not the main concern. 440 * <p> 441 * To obtain standard formats for a given locale, use the factory methods 442 * on NumberFormat such as getNumberInstance. These factories will 443 * return the most appropriate sub-class of NumberFormat for a given 444 * locale. 445 * 446 * @param pattern a non-localized pattern string. 447 * @throws NullPointerException if {@code pattern} is null 448 * @throws IllegalArgumentException if the given pattern is invalid. 449 * @see java.text.NumberFormat#getInstance 450 * @see java.text.NumberFormat#getNumberInstance 451 * @see java.text.NumberFormat#getCurrencyInstance 452 * @see java.text.NumberFormat#getPercentInstance 453 */ DecimalFormat(String pattern)454 public DecimalFormat(String pattern) { 455 // Always applyPattern after the symbols are set 456 this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT)); 457 // Android-changed: initPattern() and conversion methods between ICU and Java values. 458 // applyPattern(pattern, false); 459 initPattern(pattern); 460 } 461 462 463 /** 464 * Creates a DecimalFormat using the given pattern and symbols. 465 * Use this constructor when you need to completely customize the 466 * behavior of the format. 467 * <p> 468 * To obtain standard formats for a given 469 * locale, use the factory methods on NumberFormat such as 470 * getInstance or getCurrencyInstance. If you need only minor adjustments 471 * to a standard format, you can modify the format returned by 472 * a NumberFormat factory method. 473 * 474 * @param pattern a non-localized pattern string 475 * @param symbols the set of symbols to be used 476 * @throws NullPointerException if any of the given arguments is null 477 * @throws IllegalArgumentException if the given pattern is invalid 478 * @see java.text.NumberFormat#getInstance 479 * @see java.text.NumberFormat#getNumberInstance 480 * @see java.text.NumberFormat#getCurrencyInstance 481 * @see java.text.NumberFormat#getPercentInstance 482 * @see java.text.DecimalFormatSymbols 483 */ DecimalFormat(String pattern, DecimalFormatSymbols symbols)484 public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { 485 // Always applyPattern after the symbols are set 486 this.symbols = (DecimalFormatSymbols)symbols.clone(); 487 // Android-changed: initPattern() and conversion methods between ICU and Java values. 488 initPattern(pattern); 489 } 490 491 // BEGIN Android-added: initPattern() and conversion methods between ICU and Java values. 492 /** 493 * Applies the pattern similarly to {@link #applyPattern(String)}, except it initializes 494 * {@link #icuDecimalFormat} in the process. This should only be called from constructors. 495 */ initPattern(String pattern)496 private void initPattern(String pattern) { 497 // Android-changed: Compatibility mode for j.t.DecimalFormat. http://b/112355520 498 this.icuDecimalFormat = CompatibleDecimalFormatFactory.create(pattern, 499 symbols.getIcuDecimalFormatSymbols()); 500 updateFieldsFromIcu(); 501 } 502 503 /** 504 * Update local fields indicating maximum/minimum integer/fraction digit count from the ICU 505 * DecimalFormat. This needs to be called whenever a new pattern is applied. 506 */ updateFieldsFromIcu()507 private void updateFieldsFromIcu() { 508 // Imitate behaviour of ICU4C NumberFormat that Android used up to M. 509 // If the pattern doesn't enforce a different value (some exponential 510 // patterns do), then set the maximum integer digits to 2 billion. 511 if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) { 512 icuDecimalFormat.setMaximumIntegerDigits(2000000000); 513 } 514 maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits(); 515 minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits(); 516 maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits(); 517 minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits(); 518 } 519 520 /** 521 * Converts between field positions used by Java/ICU. 522 * @param fp The java.text.NumberFormat.Field field position 523 * @return The android.icu.text.NumberFormat.Field field position 524 */ getIcuFieldPosition(FieldPosition fp)525 private static FieldPosition getIcuFieldPosition(FieldPosition fp) { 526 Format.Field fieldAttribute = fp.getFieldAttribute(); 527 if (fieldAttribute == null) return fp; 528 529 android.icu.text.NumberFormat.Field attribute; 530 if (fieldAttribute == Field.INTEGER) { 531 attribute = android.icu.text.NumberFormat.Field.INTEGER; 532 } else if (fieldAttribute == Field.FRACTION) { 533 attribute = android.icu.text.NumberFormat.Field.FRACTION; 534 } else if (fieldAttribute == Field.DECIMAL_SEPARATOR) { 535 attribute = android.icu.text.NumberFormat.Field.DECIMAL_SEPARATOR; 536 } else if (fieldAttribute == Field.EXPONENT_SYMBOL) { 537 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SYMBOL; 538 } else if (fieldAttribute == Field.EXPONENT_SIGN) { 539 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SIGN; 540 } else if (fieldAttribute == Field.EXPONENT) { 541 attribute = android.icu.text.NumberFormat.Field.EXPONENT; 542 } else if (fieldAttribute == Field.GROUPING_SEPARATOR) { 543 attribute = android.icu.text.NumberFormat.Field.GROUPING_SEPARATOR; 544 } else if (fieldAttribute == Field.CURRENCY) { 545 attribute = android.icu.text.NumberFormat.Field.CURRENCY; 546 } else if (fieldAttribute == Field.PERCENT) { 547 attribute = android.icu.text.NumberFormat.Field.PERCENT; 548 } else if (fieldAttribute == Field.PERMILLE) { 549 attribute = android.icu.text.NumberFormat.Field.PERMILLE; 550 } else if (fieldAttribute == Field.SIGN) { 551 attribute = android.icu.text.NumberFormat.Field.SIGN; 552 } else { 553 throw new IllegalArgumentException("Unexpected field position attribute type."); 554 } 555 556 FieldPosition icuFieldPosition = new FieldPosition(attribute); 557 icuFieldPosition.setBeginIndex(fp.getBeginIndex()); 558 icuFieldPosition.setEndIndex(fp.getEndIndex()); 559 return icuFieldPosition; 560 } 561 562 /** 563 * Converts the Attribute that ICU returns in its AttributedCharacterIterator 564 * responses to the type that java uses. 565 * @param icuAttribute The AttributedCharacterIterator.Attribute field. 566 * @return Field converted to a java.text.NumberFormat.Field field. 567 */ toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute)568 private static Field toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute) { 569 String name = icuAttribute.getName(); 570 if (name.equals(Field.INTEGER.getName())) { 571 return Field.INTEGER; 572 } 573 if (name.equals(Field.CURRENCY.getName())) { 574 return Field.CURRENCY; 575 } 576 if (name.equals(Field.DECIMAL_SEPARATOR.getName())) { 577 return Field.DECIMAL_SEPARATOR; 578 } 579 if (name.equals(Field.EXPONENT.getName())) { 580 return Field.EXPONENT; 581 } 582 if (name.equals(Field.EXPONENT_SIGN.getName())) { 583 return Field.EXPONENT_SIGN; 584 } 585 if (name.equals(Field.EXPONENT_SYMBOL.getName())) { 586 return Field.EXPONENT_SYMBOL; 587 } 588 if (name.equals(Field.FRACTION.getName())) { 589 return Field.FRACTION; 590 } 591 if (name.equals(Field.GROUPING_SEPARATOR.getName())) { 592 return Field.GROUPING_SEPARATOR; 593 } 594 if (name.equals(Field.SIGN.getName())) { 595 return Field.SIGN; 596 } 597 if (name.equals(Field.PERCENT.getName())) { 598 return Field.PERCENT; 599 } 600 if (name.equals(Field.PERMILLE.getName())) { 601 return Field.PERMILLE; 602 } 603 throw new IllegalArgumentException("Unrecognized attribute: " + name); 604 } 605 // END Android-added: initPattern() and conversion methods between ICU and Java values. 606 607 // Overrides 608 /** 609 * Formats a number and appends the resulting text to the given string 610 * buffer. 611 * The number can be of any subclass of {@link java.lang.Number}. 612 * <p> 613 * This implementation uses the maximum precision permitted. 614 * @param number the number to format 615 * @param toAppendTo the {@code StringBuffer} to which the formatted 616 * text is to be appended 617 * @param pos keeps track on the position of the field within the 618 * returned string. For example, for formatting a number 619 * {@code 1234567.89} in {@code Locale.US} locale, 620 * if the given {@code fieldPosition} is 621 * {@link NumberFormat#INTEGER_FIELD}, the begin index 622 * and end index of {@code fieldPosition} will be set 623 * to 0 and 9, respectively for the output string 624 * {@code 1,234,567.89}. 625 * @return the value passed in as {@code toAppendTo} 626 * @throws IllegalArgumentException if {@code number} is 627 * null or not an instance of {@code Number}. 628 * @throws NullPointerException if {@code toAppendTo} or 629 * {@code pos} is null 630 * @throws ArithmeticException if rounding is needed with rounding 631 * mode being set to RoundingMode.UNNECESSARY 632 * @see java.text.FieldPosition 633 */ 634 @Override format(Object number, StringBuffer toAppendTo, FieldPosition pos)635 public final StringBuffer format(Object number, 636 StringBuffer toAppendTo, 637 FieldPosition pos) { 638 if (number instanceof Long || number instanceof Integer || 639 number instanceof Short || number instanceof Byte || 640 number instanceof AtomicInteger || 641 number instanceof AtomicLong || 642 (number instanceof BigInteger && 643 ((BigInteger)number).bitLength () < 64)) { 644 return format(((Number)number).longValue(), toAppendTo, pos); 645 } else if (number instanceof BigDecimal) { 646 return format((BigDecimal)number, toAppendTo, pos); 647 } else if (number instanceof BigInteger) { 648 return format((BigInteger)number, toAppendTo, pos); 649 } else if (number instanceof Number) { 650 return format(((Number)number).doubleValue(), toAppendTo, pos); 651 } else { 652 throw new IllegalArgumentException("Cannot format given Object as a Number"); 653 } 654 } 655 656 /** 657 * Formats a double to produce a string. 658 * @param number The double to format 659 * @param result where the text is to be appended 660 * @param fieldPosition keeps track on the position of the field within 661 * the returned string. For example, for formatting 662 * a number {@code 1234567.89} in {@code Locale.US} 663 * locale, if the given {@code fieldPosition} is 664 * {@link NumberFormat#INTEGER_FIELD}, the begin index 665 * and end index of {@code fieldPosition} will be set 666 * to 0 and 9, respectively for the output string 667 * {@code 1,234,567.89}. 668 * @throws NullPointerException if {@code result} or 669 * {@code fieldPosition} is {@code null} 670 * @throws ArithmeticException if rounding is needed with rounding 671 * mode being set to RoundingMode.UNNECESSARY 672 * @return The formatted number string 673 * @see java.text.FieldPosition 674 */ 675 @Override format(double number, StringBuffer result, FieldPosition fieldPosition)676 public StringBuffer format(double number, StringBuffer result, 677 FieldPosition fieldPosition) { 678 // BEGIN Android-changed: Use ICU. 679 /* 680 // If fieldPosition is a DontCareFieldPosition instance we can 681 // try to go to fast-path code. 682 boolean tryFastPath = false; 683 if (fieldPosition == DontCareFieldPosition.INSTANCE) 684 tryFastPath = true; 685 else { 686 fieldPosition.setBeginIndex(0); 687 fieldPosition.setEndIndex(0); 688 } 689 690 if (tryFastPath) { 691 String tempResult = fastFormat(number); 692 if (tempResult != null) { 693 result.append(tempResult); 694 return result; 695 } 696 } 697 698 // if fast-path could not work, we fallback to standard code. 699 return format(number, result, fieldPosition.getFieldDelegate()); 700 */ 701 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 702 icuDecimalFormat.format(number, result, icuFieldPosition); 703 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 704 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 705 return result; 706 // END Android-changed: Use ICU. 707 } 708 709 // BEGIN Android-removed: Use ICU. 710 // Removed unused helper function that was only used from (unused on Android) code 711 // in format(double, StringBuffer, FieldPosition). 712 /* 713 /** 714 * Formats a double to produce a string. 715 * @param number The double to format 716 * @param result where the text is to be appended 717 * @param delegate notified of locations of sub fields 718 * @throws ArithmeticException if rounding is needed with rounding 719 * mode being set to RoundingMode.UNNECESSARY 720 * @return The formatted number string 721 * 722 StringBuffer format(double number, StringBuffer result, 723 FieldDelegate delegate) { 724 725 boolean nanOrInfinity = handleNaN(number, result, delegate); 726 if (nanOrInfinity) { 727 return result; 728 } 729 730 /* Detecting whether a double is negative is easy with the exception of 731 * the value -0.0. This is a double which has a zero mantissa (and 732 * exponent), but a negative sign bit. It is semantically distinct from 733 * a zero with a positive sign bit, and this distinction is important 734 * to certain kinds of computations. However, it's a little tricky to 735 * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may 736 * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == 737 * -Infinity. Proper detection of -0.0 is needed to deal with the 738 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. 739 * 740 boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0); 741 742 if (multiplier != 1) { 743 number *= multiplier; 744 } 745 746 nanOrInfinity = handleInfinity(number, result, delegate, isNegative); 747 if (nanOrInfinity) { 748 return result; 749 } 750 751 if (isNegative) { 752 number = -number; 753 } 754 755 // at this point we are guaranteed a nonnegative finite number. 756 assert (number >= 0 && !Double.isInfinite(number)); 757 return doubleSubformat(number, result, delegate, isNegative); 758 } 759 760 /** 761 * Checks if the given {@code number} is {@code Double.NaN}. if yes; 762 * appends the NaN symbol to the result string. The NaN string is 763 * determined by the DecimalFormatSymbols object. 764 * @param number the double number to format 765 * @param result where the text is to be appended 766 * @param delegate notified of locations of sub fields 767 * @return true, if number is a NaN; false otherwise 768 * 769 boolean handleNaN(double number, StringBuffer result, 770 FieldDelegate delegate) { 771 if (Double.isNaN(number) 772 || (Double.isInfinite(number) && multiplier == 0)) { 773 int iFieldStart = result.length(); 774 result.append(symbols.getNaN()); 775 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 776 iFieldStart, result.length(), result); 777 return true; 778 } 779 return false; 780 } 781 782 /** 783 * Checks if the given {@code number} is {@code Double.NEGATIVE_INFINITY} 784 * or {@code Double.POSITIVE_INFINITY}. if yes; 785 * appends the infinity string to the result string. The infinity string is 786 * determined by the DecimalFormatSymbols object. 787 * @param number the double number to format 788 * @param result where the text is to be appended 789 * @param delegate notified of locations of sub fields 790 * @param isNegative whether the given {@code number} is negative 791 * @return true, if number is a {@code Double.NEGATIVE_INFINITY} or 792 * {@code Double.POSITIVE_INFINITY}; false otherwise 793 * 794 boolean handleInfinity(double number, StringBuffer result, 795 FieldDelegate delegate, boolean isNegative) { 796 if (Double.isInfinite(number)) { 797 if (isNegative) { 798 append(result, negativePrefix, delegate, 799 getNegativePrefixFieldPositions(), Field.SIGN); 800 } else { 801 append(result, positivePrefix, delegate, 802 getPositivePrefixFieldPositions(), Field.SIGN); 803 } 804 805 int iFieldStart = result.length(); 806 result.append(symbols.getInfinity()); 807 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 808 iFieldStart, result.length(), result); 809 810 if (isNegative) { 811 append(result, negativeSuffix, delegate, 812 getNegativeSuffixFieldPositions(), Field.SIGN); 813 } else { 814 append(result, positiveSuffix, delegate, 815 getPositiveSuffixFieldPositions(), Field.SIGN); 816 } 817 818 return true; 819 } 820 return false; 821 } 822 823 StringBuffer doubleSubformat(double number, StringBuffer result, 824 FieldDelegate delegate, boolean isNegative) { 825 synchronized (digitList) { 826 int maxIntDigits = super.getMaximumIntegerDigits(); 827 int minIntDigits = super.getMinimumIntegerDigits(); 828 int maxFraDigits = super.getMaximumFractionDigits(); 829 int minFraDigits = super.getMinimumFractionDigits(); 830 831 digitList.set(isNegative, number, useExponentialNotation 832 ? maxIntDigits + maxFraDigits : maxFraDigits, 833 !useExponentialNotation); 834 return subformat(result, delegate, isNegative, false, 835 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 836 } 837 } 838 */ 839 // END Android-removed: Use ICU. 840 841 /** 842 * Format a long to produce a string. 843 * @param number The long to format 844 * @param result where the text is to be appended 845 * @param fieldPosition keeps track on the position of the field within 846 * the returned string. For example, for formatting 847 * a number {@code 123456789} in {@code Locale.US} 848 * locale, if the given {@code fieldPosition} is 849 * {@link NumberFormat#INTEGER_FIELD}, the begin index 850 * and end index of {@code fieldPosition} will be set 851 * to 0 and 11, respectively for the output string 852 * {@code 123,456,789}. 853 * @throws NullPointerException if {@code result} or 854 * {@code fieldPosition} is {@code null} 855 * @throws ArithmeticException if rounding is needed with rounding 856 * mode being set to RoundingMode.UNNECESSARY 857 * @return The formatted number string 858 * @see java.text.FieldPosition 859 */ 860 @Override format(long number, StringBuffer result, FieldPosition fieldPosition)861 public StringBuffer format(long number, StringBuffer result, 862 FieldPosition fieldPosition) { 863 // BEGIN Android-changed: Use ICU. 864 /* 865 fieldPosition.setBeginIndex(0); 866 fieldPosition.setEndIndex(0); 867 868 return format(number, result, fieldPosition.getFieldDelegate()); 869 */ 870 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 871 icuDecimalFormat.format(number, result, icuFieldPosition); 872 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 873 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 874 return result; 875 // END Android-changed: Use ICU. 876 } 877 878 // BEGIN Android-removed: Use ICU. 879 // Removed unused helper function that was only used from (unused on Android) code 880 // in format(long, StringBuffer, FieldDelegate). 881 /* 882 /** 883 * Format a long to produce a string. 884 * @param number The long to format 885 * @param result where the text is to be appended 886 * @param delegate notified of locations of sub fields 887 * @return The formatted number string 888 * @throws ArithmeticException if rounding is needed with rounding 889 * mode being set to RoundingMode.UNNECESSARY 890 * @see java.text.FieldPosition 891 * 892 StringBuffer format(long number, StringBuffer result, 893 FieldDelegate delegate) { 894 boolean isNegative = (number < 0); 895 if (isNegative) { 896 number = -number; 897 } 898 899 // In general, long values always represent real finite numbers, so 900 // we don't have to check for +/- Infinity or NaN. However, there 901 // is one case we have to be careful of: The multiplier can push 902 // a number near MIN_VALUE or MAX_VALUE outside the legal range. We 903 // check for this before multiplying, and if it happens we use 904 // BigInteger instead. 905 boolean useBigInteger = false; 906 if (number < 0) { // This can only happen if number == Long.MIN_VALUE. 907 if (multiplier != 0) { 908 useBigInteger = true; 909 } 910 } else if (multiplier != 1 && multiplier != 0) { 911 long cutoff = Long.MAX_VALUE / multiplier; 912 if (cutoff < 0) { 913 cutoff = -cutoff; 914 } 915 useBigInteger = (number > cutoff); 916 } 917 918 if (useBigInteger) { 919 if (isNegative) { 920 number = -number; 921 } 922 BigInteger bigIntegerValue = BigInteger.valueOf(number); 923 return format(bigIntegerValue, result, delegate, true); 924 } 925 926 number *= multiplier; 927 if (number == 0) { 928 isNegative = false; 929 } else { 930 if (multiplier < 0) { 931 number = -number; 932 isNegative = !isNegative; 933 } 934 } 935 936 synchronized(digitList) { 937 int maxIntDigits = super.getMaximumIntegerDigits(); 938 int minIntDigits = super.getMinimumIntegerDigits(); 939 int maxFraDigits = super.getMaximumFractionDigits(); 940 int minFraDigits = super.getMinimumFractionDigits(); 941 942 digitList.set(isNegative, number, 943 useExponentialNotation ? maxIntDigits + maxFraDigits : 0); 944 945 return subformat(result, delegate, isNegative, true, 946 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 947 } 948 } 949 */ 950 // END Android-removed: Use ICU. 951 952 /** 953 * Formats a BigDecimal to produce a string. 954 * @param number The BigDecimal to format 955 * @param result where the text is to be appended 956 * @param fieldPosition keeps track on the position of the field within 957 * the returned string. For example, for formatting 958 * a number {@code 1234567.89} in {@code Locale.US} 959 * locale, if the given {@code fieldPosition} is 960 * {@link NumberFormat#INTEGER_FIELD}, the begin index 961 * and end index of {@code fieldPosition} will be set 962 * to 0 and 9, respectively for the output string 963 * {@code 1,234,567.89}. 964 * @return The formatted number string 965 * @throws ArithmeticException if rounding is needed with rounding 966 * mode being set to RoundingMode.UNNECESSARY 967 * @see java.text.FieldPosition 968 */ format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition)969 private StringBuffer format(BigDecimal number, StringBuffer result, 970 FieldPosition fieldPosition) { 971 // BEGIN Android-changed: Use ICU. 972 /* 973 fieldPosition.setBeginIndex(0); 974 fieldPosition.setEndIndex(0); 975 return format(number, result, fieldPosition.getFieldDelegate()); 976 */ 977 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 978 icuDecimalFormat.format(number, result, icuFieldPosition); 979 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 980 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 981 return result; 982 // END Android-changed: Use ICU. 983 } 984 985 // BEGIN Android-removed: Use ICU. 986 // Removed unused helper function that was only used from (unused on Android) code 987 // in format(BigDecimal, StringBuffer, FieldDelegate). 988 /* 989 /** 990 * Formats a BigDecimal to produce a string. 991 * @param number The BigDecimal to format 992 * @param result where the text is to be appended 993 * @param delegate notified of locations of sub fields 994 * @throws ArithmeticException if rounding is needed with rounding 995 * mode being set to RoundingMode.UNNECESSARY 996 * @return The formatted number string 997 * 998 StringBuffer format(BigDecimal number, StringBuffer result, 999 FieldDelegate delegate) { 1000 if (multiplier != 1) { 1001 number = number.multiply(getBigDecimalMultiplier()); 1002 } 1003 boolean isNegative = number.signum() == -1; 1004 if (isNegative) { 1005 number = number.negate(); 1006 } 1007 1008 synchronized(digitList) { 1009 int maxIntDigits = getMaximumIntegerDigits(); 1010 int minIntDigits = getMinimumIntegerDigits(); 1011 int maxFraDigits = getMaximumFractionDigits(); 1012 int minFraDigits = getMinimumFractionDigits(); 1013 int maximumDigits = maxIntDigits + maxFraDigits; 1014 1015 digitList.set(isNegative, number, useExponentialNotation ? 1016 ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) : 1017 maxFraDigits, !useExponentialNotation); 1018 1019 return subformat(result, delegate, isNegative, false, 1020 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 1021 } 1022 } 1023 */ 1024 // END Android-removed: Use ICU. 1025 1026 /** 1027 * Format a BigInteger to produce a string. 1028 * @param number The BigInteger to format 1029 * @param result where the text is to be appended 1030 * @param fieldPosition keeps track on the position of the field within 1031 * the returned string. For example, for formatting 1032 * a number {@code 123456789} in {@code Locale.US} 1033 * locale, if the given {@code fieldPosition} is 1034 * {@link NumberFormat#INTEGER_FIELD}, the begin index 1035 * and end index of {@code fieldPosition} will be set 1036 * to 0 and 11, respectively for the output string 1037 * {@code 123,456,789}. 1038 * @return The formatted number string 1039 * @throws ArithmeticException if rounding is needed with rounding 1040 * mode being set to RoundingMode.UNNECESSARY 1041 * @see java.text.FieldPosition 1042 */ format(BigInteger number, StringBuffer result, FieldPosition fieldPosition)1043 private StringBuffer format(BigInteger number, StringBuffer result, 1044 FieldPosition fieldPosition) { 1045 // BEGIN Android-changed: Use ICU. 1046 /* 1047 fieldPosition.setBeginIndex(0); 1048 fieldPosition.setEndIndex(0); 1049 1050 return format(number, result, fieldPosition.getFieldDelegate(), false); 1051 */ 1052 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 1053 icuDecimalFormat.format(number, result, icuFieldPosition); 1054 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 1055 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 1056 return result; 1057 // END Android-changed: Use ICU. 1058 } 1059 1060 // BEGIN Android-removed: Use ICU. 1061 // Removed unused helper function that was only used from (unused on Android) code 1062 // in format(BigInteger, StringBuffer, FieldDelegate). 1063 /* 1064 /** 1065 * Format a BigInteger to produce a string. 1066 * @param number The BigInteger to format 1067 * @param result where the text is to be appended 1068 * @param delegate notified of locations of sub fields 1069 * @return The formatted number string 1070 * @throws ArithmeticException if rounding is needed with rounding 1071 * mode being set to RoundingMode.UNNECESSARY 1072 * @see java.text.FieldPosition 1073 * 1074 StringBuffer format(BigInteger number, StringBuffer result, 1075 FieldDelegate delegate, boolean formatLong) { 1076 if (multiplier != 1) { 1077 number = number.multiply(getBigIntegerMultiplier()); 1078 } 1079 boolean isNegative = number.signum() == -1; 1080 if (isNegative) { 1081 number = number.negate(); 1082 } 1083 1084 synchronized(digitList) { 1085 int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits; 1086 if (formatLong) { 1087 maxIntDigits = super.getMaximumIntegerDigits(); 1088 minIntDigits = super.getMinimumIntegerDigits(); 1089 maxFraDigits = super.getMaximumFractionDigits(); 1090 minFraDigits = super.getMinimumFractionDigits(); 1091 maximumDigits = maxIntDigits + maxFraDigits; 1092 } else { 1093 maxIntDigits = getMaximumIntegerDigits(); 1094 minIntDigits = getMinimumIntegerDigits(); 1095 maxFraDigits = getMaximumFractionDigits(); 1096 minFraDigits = getMinimumFractionDigits(); 1097 maximumDigits = maxIntDigits + maxFraDigits; 1098 if (maximumDigits < 0) { 1099 maximumDigits = Integer.MAX_VALUE; 1100 } 1101 } 1102 1103 digitList.set(isNegative, number, 1104 useExponentialNotation ? maximumDigits : 0); 1105 1106 return subformat(result, delegate, isNegative, true, 1107 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 1108 } 1109 } 1110 */ 1111 // END Android-removed: Use ICU. 1112 1113 /** 1114 * Formats an Object producing an {@code AttributedCharacterIterator}. 1115 * You can use the returned {@code AttributedCharacterIterator} 1116 * to build the resulting String, as well as to determine information 1117 * about the resulting String. 1118 * <p> 1119 * Each attribute key of the AttributedCharacterIterator will be of type 1120 * {@code NumberFormat.Field}, with the attribute value being the 1121 * same as the attribute key. 1122 * 1123 * @throws NullPointerException if obj is null. 1124 * @throws IllegalArgumentException when the Format cannot format the 1125 * given object. 1126 * @throws ArithmeticException if rounding is needed with rounding 1127 * mode being set to RoundingMode.UNNECESSARY 1128 * @param obj The object to format 1129 * @return AttributedCharacterIterator describing the formatted value. 1130 * @since 1.4 1131 */ 1132 @Override formatToCharacterIterator(Object obj)1133 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 1134 // BEGIN Android-changed: Use ICU. 1135 /* 1136 CharacterIteratorFieldDelegate delegate = 1137 new CharacterIteratorFieldDelegate(); 1138 StringBuffer sb = new StringBuffer(); 1139 1140 if (obj instanceof Double || obj instanceof Float) { 1141 format(((Number)obj).doubleValue(), sb, delegate); 1142 } else if (obj instanceof Long || obj instanceof Integer || 1143 obj instanceof Short || obj instanceof Byte || 1144 obj instanceof AtomicInteger || obj instanceof AtomicLong) { 1145 format(((Number)obj).longValue(), sb, delegate); 1146 } else if (obj instanceof BigDecimal) { 1147 format((BigDecimal)obj, sb, delegate); 1148 } else if (obj instanceof BigInteger) { 1149 format((BigInteger)obj, sb, delegate, false); 1150 } else if (obj == null) { 1151 throw new NullPointerException( 1152 "formatToCharacterIterator must be passed non-null object"); 1153 } else { 1154 throw new IllegalArgumentException( 1155 "Cannot format given Object as a Number"); 1156 } 1157 return delegate.getIterator(sb.toString()); 1158 */ 1159 if (obj == null) { 1160 throw new NullPointerException("object == null"); 1161 } 1162 // Note: formatToCharacterIterator cannot be used directly because it returns attributes 1163 // in terms of its own class: icu.text.NumberFormat instead of java.text.NumberFormat. 1164 // http://bugs.icu-project.org/trac/ticket/11931 Proposes to use the NumberFormat constants. 1165 1166 AttributedCharacterIterator original = icuDecimalFormat.formatToCharacterIterator(obj); 1167 1168 // Extract the text out of the ICU iterator. 1169 StringBuilder textBuilder = new StringBuilder( 1170 original.getEndIndex() - original.getBeginIndex()); 1171 1172 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 1173 textBuilder.append(original.current()); 1174 original.next(); 1175 } 1176 1177 AttributedString result = new AttributedString(textBuilder.toString()); 1178 1179 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 1180 original.setIndex(i); 1181 1182 for (AttributedCharacterIterator.Attribute attribute 1183 : original.getAttributes().keySet()) { 1184 int start = original.getRunStart(); 1185 int end = original.getRunLimit(); 1186 Field javaAttr = toJavaFieldAttribute(attribute); 1187 result.addAttribute(javaAttr, javaAttr, start, end); 1188 } 1189 } 1190 1191 return result.getIterator(); 1192 // END Android-changed: Use ICU. 1193 } 1194 1195 // BEGIN Android-removed: "fast-path formatting logic for double", subformat(), append(). 1196 /* 1197 // ==== Begin fast-path formatting logic for double ========================= 1198 1199 /* Fast-path formatting will be used for format(double ...) methods iff a 1200 * number of conditions are met (see checkAndSetFastPathStatus()): 1201 * - Only if instance properties meet the right predefined conditions. 1202 * - The abs value of the double to format is <= Integer.MAX_VALUE. 1203 * 1204 * The basic approach is to split the binary to decimal conversion of a 1205 * double value into two phases: 1206 * * The conversion of the integer portion of the double. 1207 * * The conversion of the fractional portion of the double 1208 * (limited to two or three digits). 1209 * 1210 * The isolation and conversion of the integer portion of the double is 1211 * straightforward. The conversion of the fraction is more subtle and relies 1212 * on some rounding properties of double to the decimal precisions in 1213 * question. Using the terminology of BigDecimal, this fast-path algorithm 1214 * is applied when a double value has a magnitude less than Integer.MAX_VALUE 1215 * and rounding is to nearest even and the destination format has two or 1216 * three digits of *scale* (digits after the decimal point). 1217 * 1218 * Under a rounding to nearest even policy, the returned result is a digit 1219 * string of a number in the (in this case decimal) destination format 1220 * closest to the exact numerical value of the (in this case binary) input 1221 * value. If two destination format numbers are equally distant, the one 1222 * with the last digit even is returned. To compute such a correctly rounded 1223 * value, some information about digits beyond the smallest returned digit 1224 * position needs to be consulted. 1225 * 1226 * In general, a guard digit, a round digit, and a sticky *bit* are needed 1227 * beyond the returned digit position. If the discarded portion of the input 1228 * is sufficiently large, the returned digit string is incremented. In round 1229 * to nearest even, this threshold to increment occurs near the half-way 1230 * point between digits. The sticky bit records if there are any remaining 1231 * trailing digits of the exact input value in the new format; the sticky bit 1232 * is consulted only in close to half-way rounding cases. 1233 * 1234 * Given the computation of the digit and bit values, rounding is then 1235 * reduced to a table lookup problem. For decimal, the even/odd cases look 1236 * like this: 1237 * 1238 * Last Round Sticky 1239 * 6 5 0 => 6 // exactly halfway, return even digit. 1240 * 6 5 1 => 7 // a little bit more than halfway, round up. 1241 * 7 5 0 => 8 // exactly halfway, round up to even. 1242 * 7 5 1 => 8 // a little bit more than halfway, round up. 1243 * With analogous entries for other even and odd last-returned digits. 1244 * 1245 * However, decimal negative powers of 5 smaller than 0.5 are *not* exactly 1246 * representable as binary fraction. In particular, 0.005 (the round limit 1247 * for a two-digit scale) and 0.0005 (the round limit for a three-digit 1248 * scale) are not representable. Therefore, for input values near these cases 1249 * the sticky bit is known to be set which reduces the rounding logic to: 1250 * 1251 * Last Round Sticky 1252 * 6 5 1 => 7 // a little bit more than halfway, round up. 1253 * 7 5 1 => 8 // a little bit more than halfway, round up. 1254 * 1255 * In other words, if the round digit is 5, the sticky bit is known to be 1256 * set. If the round digit is something other than 5, the sticky bit is not 1257 * relevant. Therefore, some of the logic about whether or not to increment 1258 * the destination *decimal* value can occur based on tests of *binary* 1259 * computations of the binary input number. 1260 * 1261 1262 /** 1263 * Check validity of using fast-path for this instance. If fast-path is valid 1264 * for this instance, sets fast-path state as true and initializes fast-path 1265 * utility fields as needed. 1266 * 1267 * This method is supposed to be called rarely, otherwise that will break the 1268 * fast-path performance. That means avoiding frequent changes of the 1269 * properties of the instance, since for most properties, each time a change 1270 * happens, a call to this method is needed at the next format call. 1271 * 1272 * FAST-PATH RULES: 1273 * Similar to the default DecimalFormat instantiation case. 1274 * More precisely: 1275 * - HALF_EVEN rounding mode, 1276 * - isGroupingUsed() is true, 1277 * - groupingSize of 3, 1278 * - multiplier is 1, 1279 * - Decimal separator not mandatory, 1280 * - No use of exponential notation, 1281 * - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10 1282 * - For number of fractional digits, the exact values found in the default case: 1283 * Currency : min = max = 2. 1284 * Decimal : min = 0. max = 3. 1285 * 1286 * 1287 * 1288 private boolean checkAndSetFastPathStatus() { 1289 1290 boolean fastPathWasOn = isFastPath; 1291 1292 if ((roundingMode == RoundingMode.HALF_EVEN) && 1293 (isGroupingUsed()) && 1294 (groupingSize == 3) && 1295 (multiplier == 1) && 1296 (!decimalSeparatorAlwaysShown) && 1297 (!useExponentialNotation)) { 1298 1299 // The fast-path algorithm is semi-hardcoded against 1300 // minimumIntegerDigits and maximumIntegerDigits. 1301 isFastPath = ((minimumIntegerDigits == 1) && 1302 (maximumIntegerDigits >= 10)); 1303 1304 // The fast-path algorithm is hardcoded against 1305 // minimumFractionDigits and maximumFractionDigits. 1306 if (isFastPath) { 1307 if (isCurrencyFormat) { 1308 if ((minimumFractionDigits != 2) || 1309 (maximumFractionDigits != 2)) 1310 isFastPath = false; 1311 } else if ((minimumFractionDigits != 0) || 1312 (maximumFractionDigits != 3)) 1313 isFastPath = false; 1314 } 1315 } else 1316 isFastPath = false; 1317 1318 resetFastPathData(fastPathWasOn); 1319 fastPathCheckNeeded = false; 1320 1321 /* 1322 * Returns true after successfully checking the fast path condition and 1323 * setting the fast path data. The return value is used by the 1324 * fastFormat() method to decide whether to call the resetFastPathData 1325 * method to reinitialize fast path data or is it already initialized 1326 * in this method. 1327 * 1328 return true; 1329 } 1330 1331 private void resetFastPathData(boolean fastPathWasOn) { 1332 // Since some instance properties may have changed while still falling 1333 // in the fast-path case, we need to reinitialize fastPathData anyway. 1334 if (isFastPath) { 1335 // We need to instantiate fastPathData if not already done. 1336 if (fastPathData == null) { 1337 fastPathData = new FastPathData(); 1338 } 1339 1340 // Sets up the locale specific constants used when formatting. 1341 // '0' is our default representation of zero. 1342 fastPathData.zeroDelta = symbols.getZeroDigit() - '0'; 1343 fastPathData.groupingChar = isCurrencyFormat ? 1344 symbols.getMonetaryGroupingSeparator() : 1345 symbols.getGroupingSeparator(); 1346 1347 // Sets up fractional constants related to currency/decimal pattern. 1348 fastPathData.fractionalMaxIntBound = (isCurrencyFormat) 1349 ? 99 : 999; 1350 fastPathData.fractionalScaleFactor = (isCurrencyFormat) 1351 ? 100.0d : 1000.0d; 1352 1353 // Records the need for adding prefix or suffix 1354 fastPathData.positiveAffixesRequired 1355 = !positivePrefix.isEmpty() || !positiveSuffix.isEmpty(); 1356 fastPathData.negativeAffixesRequired 1357 = !negativePrefix.isEmpty() || !negativeSuffix.isEmpty(); 1358 1359 // Creates a cached char container for result, with max possible size. 1360 int maxNbIntegralDigits = 10; 1361 int maxNbGroups = 3; 1362 int containerSize 1363 = Math.max(positivePrefix.length(), negativePrefix.length()) 1364 + maxNbIntegralDigits + maxNbGroups + 1 1365 + maximumFractionDigits 1366 + Math.max(positiveSuffix.length(), negativeSuffix.length()); 1367 1368 fastPathData.fastPathContainer = new char[containerSize]; 1369 1370 // Sets up prefix and suffix char arrays constants. 1371 fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray(); 1372 fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray(); 1373 fastPathData.charsPositivePrefix = positivePrefix.toCharArray(); 1374 fastPathData.charsNegativePrefix = negativePrefix.toCharArray(); 1375 1376 // Sets up fixed index positions for integral and fractional digits. 1377 // Sets up decimal point in cached result container. 1378 int longestPrefixLength 1379 = Math.max(positivePrefix.length(), 1380 negativePrefix.length()); 1381 int decimalPointIndex 1382 = maxNbIntegralDigits + maxNbGroups + longestPrefixLength; 1383 1384 fastPathData.integralLastIndex = decimalPointIndex - 1; 1385 fastPathData.fractionalFirstIndex = decimalPointIndex + 1; 1386 fastPathData.fastPathContainer[decimalPointIndex] 1387 = isCurrencyFormat 1388 ? symbols.getMonetaryDecimalSeparator() 1389 : symbols.getDecimalSeparator(); 1390 1391 } else if (fastPathWasOn) { 1392 // Previous state was fast-path and is no more. 1393 // Resets cached array constants. 1394 fastPathData.fastPathContainer = null; 1395 fastPathData.charsPositiveSuffix = null; 1396 fastPathData.charsNegativeSuffix = null; 1397 fastPathData.charsPositivePrefix = null; 1398 fastPathData.charsNegativePrefix = null; 1399 } 1400 } 1401 1402 /** 1403 * Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt}, 1404 * false otherwise. 1405 * 1406 * This is a utility method that takes correct half-even rounding decision on 1407 * passed fractional value at the scaled decimal point (2 digits for currency 1408 * case and 3 for decimal case), when the approximated fractional part after 1409 * scaled decimal point is exactly 0.5d. This is done by means of exact 1410 * calculations on the {@code fractionalPart} floating-point value. 1411 * 1412 * This method is supposed to be called by private {@code fastDoubleFormat} 1413 * method only. 1414 * 1415 * The algorithms used for the exact calculations are : 1416 * 1417 * The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the 1418 * papers "<i>A Floating-Point Technique for Extending the Available 1419 * Precision</i>" by Dekker, and in "<i>Adaptive Precision Floating-Point 1420 * Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk. 1421 * 1422 * A modified version of <b><i>Sum2S</i></b> cascaded summation described in 1423 * "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All. As 1424 * Ogita says in this paper this is an equivalent of the Kahan-Babuska's 1425 * summation algorithm because we order the terms by magnitude before summing 1426 * them. For this reason we can use the <i>FastTwoSum</i> algorithm rather 1427 * than the more expensive Knuth's <i>TwoSum</i>. 1428 * 1429 * We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm, 1430 * like those described in Shewchuk's paper above. See comments in the code 1431 * below. 1432 * 1433 * @param fractionalPart The fractional value on which we take rounding 1434 * decision. 1435 * @param scaledFractionalPartAsInt The integral part of the scaled 1436 * fractional value. 1437 * 1438 * @return the decision that must be taken regarding half-even rounding. 1439 * 1440 private boolean exactRoundUp(double fractionalPart, 1441 int scaledFractionalPartAsInt) { 1442 1443 /* exactRoundUp() method is called by fastDoubleFormat() only. 1444 * The precondition expected to be verified by the passed parameters is : 1445 * scaledFractionalPartAsInt == 1446 * (int) (fractionalPart * fastPathData.fractionalScaleFactor). 1447 * This is ensured by fastDoubleFormat() code. 1448 * 1449 1450 /* We first calculate roundoff error made by fastDoubleFormat() on 1451 * the scaled fractional part. We do this with exact calculation on the 1452 * passed fractionalPart. Rounding decision will then be taken from roundoff. 1453 * 1454 1455 /* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)). 1456 * 1457 * The below is an optimized exact "TwoProduct" calculation of passed 1458 * fractional part with scale factor, using Ogita's Sum2S cascaded 1459 * summation adapted as Kahan-Babuska equivalent by using FastTwoSum 1460 * (much faster) rather than Knuth's TwoSum. 1461 * 1462 * We can do this because we order the summation from smallest to 1463 * greatest, so that FastTwoSum can be used without any additional error. 1464 * 1465 * The "TwoProduct" exact calculation needs 17 flops. We replace this by 1466 * a cascaded summation of FastTwoSum calculations, each involving an 1467 * exact multiply by a power of 2. 1468 * 1469 * Doing so saves overall 4 multiplications and 1 addition compared to 1470 * using traditional "TwoProduct". 1471 * 1472 * The scale factor is either 100 (currency case) or 1000 (decimal case). 1473 * - when 1000, we replace it by (1024 - 16 - 8) = 1000. 1474 * - when 100, we replace it by (128 - 32 + 4) = 100. 1475 * Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact. 1476 * 1477 * 1478 double approxMax; // Will always be positive. 1479 double approxMedium; // Will always be negative. 1480 double approxMin; 1481 1482 double fastTwoSumApproximation = 0.0d; 1483 double fastTwoSumRoundOff = 0.0d; 1484 double bVirtual = 0.0d; 1485 1486 if (isCurrencyFormat) { 1487 // Scale is 100 = 128 - 32 + 4. 1488 // Multiply by 2**n is a shift. No roundoff. No error. 1489 approxMax = fractionalPart * 128.00d; 1490 approxMedium = - (fractionalPart * 32.00d); 1491 approxMin = fractionalPart * 4.00d; 1492 } else { 1493 // Scale is 1000 = 1024 - 16 - 8. 1494 // Multiply by 2**n is a shift. No roundoff. No error. 1495 approxMax = fractionalPart * 1024.00d; 1496 approxMedium = - (fractionalPart * 16.00d); 1497 approxMin = - (fractionalPart * 8.00d); 1498 } 1499 1500 // Shewchuk/Dekker's FastTwoSum(approxMedium, approxMin). 1501 assert(-approxMedium >= Math.abs(approxMin)); 1502 fastTwoSumApproximation = approxMedium + approxMin; 1503 bVirtual = fastTwoSumApproximation - approxMedium; 1504 fastTwoSumRoundOff = approxMin - bVirtual; 1505 double approxS1 = fastTwoSumApproximation; 1506 double roundoffS1 = fastTwoSumRoundOff; 1507 1508 // Shewchuk/Dekker's FastTwoSum(approxMax, approxS1); 1509 assert(approxMax >= Math.abs(approxS1)); 1510 fastTwoSumApproximation = approxMax + approxS1; 1511 bVirtual = fastTwoSumApproximation - approxMax; 1512 fastTwoSumRoundOff = approxS1 - bVirtual; 1513 double roundoff1000 = fastTwoSumRoundOff; 1514 double approx1000 = fastTwoSumApproximation; 1515 double roundoffTotal = roundoffS1 + roundoff1000; 1516 1517 // Shewchuk/Dekker's FastTwoSum(approx1000, roundoffTotal); 1518 assert(approx1000 >= Math.abs(roundoffTotal)); 1519 fastTwoSumApproximation = approx1000 + roundoffTotal; 1520 bVirtual = fastTwoSumApproximation - approx1000; 1521 1522 // Now we have got the roundoff for the scaled fractional 1523 double scaledFractionalRoundoff = roundoffTotal - bVirtual; 1524 1525 // ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end. 1526 1527 /* ---- Taking the rounding decision 1528 * 1529 * We take rounding decision based on roundoff and half-even rounding 1530 * rule. 1531 * 1532 * The above TwoProduct gives us the exact roundoff on the approximated 1533 * scaled fractional, and we know that this approximation is exactly 1534 * 0.5d, since that has already been tested by the caller 1535 * (fastDoubleFormat). 1536 * 1537 * Decision comes first from the sign of the calculated exact roundoff. 1538 * - Since being exact roundoff, it cannot be positive with a scaled 1539 * fractional less than 0.5d, as well as negative with a scaled 1540 * fractional greater than 0.5d. That leaves us with following 3 cases. 1541 * - positive, thus scaled fractional == 0.500....0fff ==> round-up. 1542 * - negative, thus scaled fractional == 0.499....9fff ==> don't round-up. 1543 * - is zero, thus scaled fractioanl == 0.5 ==> half-even rounding applies : 1544 * we round-up only if the integral part of the scaled fractional is odd. 1545 * 1546 * 1547 if (scaledFractionalRoundoff > 0.0) { 1548 return true; 1549 } else if (scaledFractionalRoundoff < 0.0) { 1550 return false; 1551 } else if ((scaledFractionalPartAsInt & 1) != 0) { 1552 return true; 1553 } 1554 1555 return false; 1556 1557 // ---- Taking the rounding decision end 1558 } 1559 1560 /** 1561 * Collects integral digits from passed {@code number}, while setting 1562 * grouping chars as needed. Updates {@code firstUsedIndex} accordingly. 1563 * 1564 * Loops downward starting from {@code backwardIndex} position (inclusive). 1565 * 1566 * @param number The int value from which we collect digits. 1567 * @param digitsBuffer The char array container where digits and grouping chars 1568 * are stored. 1569 * @param backwardIndex the position from which we start storing digits in 1570 * digitsBuffer. 1571 * 1572 * 1573 private void collectIntegralDigits(int number, 1574 char[] digitsBuffer, 1575 int backwardIndex) { 1576 int index = backwardIndex; 1577 int q; 1578 int r; 1579 while (number > 999) { 1580 // Generates 3 digits per iteration. 1581 q = number / 1000; 1582 r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000. 1583 number = q; 1584 1585 digitsBuffer[index--] = DigitArrays.DigitOnes1000[r]; 1586 digitsBuffer[index--] = DigitArrays.DigitTens1000[r]; 1587 digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r]; 1588 digitsBuffer[index--] = fastPathData.groupingChar; 1589 } 1590 1591 // Collects last 3 or less digits. 1592 digitsBuffer[index] = DigitArrays.DigitOnes1000[number]; 1593 if (number > 9) { 1594 digitsBuffer[--index] = DigitArrays.DigitTens1000[number]; 1595 if (number > 99) 1596 digitsBuffer[--index] = DigitArrays.DigitHundreds1000[number]; 1597 } 1598 1599 fastPathData.firstUsedIndex = index; 1600 } 1601 1602 /** 1603 * Collects the 2 (currency) or 3 (decimal) fractional digits from passed 1604 * {@code number}, starting at {@code startIndex} position 1605 * inclusive. There is no punctuation to set here (no grouping chars). 1606 * Updates {@code fastPathData.lastFreeIndex} accordingly. 1607 * 1608 * 1609 * @param number The int value from which we collect digits. 1610 * @param digitsBuffer The char array container where digits are stored. 1611 * @param startIndex the position from which we start storing digits in 1612 * digitsBuffer. 1613 * 1614 * 1615 private void collectFractionalDigits(int number, 1616 char[] digitsBuffer, 1617 int startIndex) { 1618 int index = startIndex; 1619 1620 char digitOnes = DigitArrays.DigitOnes1000[number]; 1621 char digitTens = DigitArrays.DigitTens1000[number]; 1622 1623 if (isCurrencyFormat) { 1624 // Currency case. Always collects fractional digits. 1625 digitsBuffer[index++] = digitTens; 1626 digitsBuffer[index++] = digitOnes; 1627 } else if (number != 0) { 1628 // Decimal case. Hundreds will always be collected 1629 digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number]; 1630 1631 // Ending zeros won't be collected. 1632 if (digitOnes != '0') { 1633 digitsBuffer[index++] = digitTens; 1634 digitsBuffer[index++] = digitOnes; 1635 } else if (digitTens != '0') 1636 digitsBuffer[index++] = digitTens; 1637 1638 } else 1639 // This is decimal pattern and fractional part is zero. 1640 // We must remove decimal point from result. 1641 index--; 1642 1643 fastPathData.lastFreeIndex = index; 1644 } 1645 1646 /** 1647 * Internal utility. 1648 * Adds the passed {@code prefix} and {@code suffix} to {@code container}. 1649 * 1650 * @param container Char array container which to prepend/append the 1651 * prefix/suffix. 1652 * @param prefix Char sequence to prepend as a prefix. 1653 * @param suffix Char sequence to append as a suffix. 1654 * 1655 * 1656 // private void addAffixes(boolean isNegative, char[] container) { 1657 private void addAffixes(char[] container, char[] prefix, char[] suffix) { 1658 1659 // We add affixes only if needed (affix length > 0). 1660 int pl = prefix.length; 1661 int sl = suffix.length; 1662 if (pl != 0) prependPrefix(prefix, pl, container); 1663 if (sl != 0) appendSuffix(suffix, sl, container); 1664 1665 } 1666 1667 /** 1668 * Prepends the passed {@code prefix} chars to given result 1669 * {@code container}. Updates {@code fastPathData.firstUsedIndex} 1670 * accordingly. 1671 * 1672 * @param prefix The prefix characters to prepend to result. 1673 * @param len The number of chars to prepend. 1674 * @param container Char array container which to prepend the prefix 1675 * 1676 private void prependPrefix(char[] prefix, 1677 int len, 1678 char[] container) { 1679 1680 fastPathData.firstUsedIndex -= len; 1681 int startIndex = fastPathData.firstUsedIndex; 1682 1683 // If prefix to prepend is only 1 char long, just assigns this char. 1684 // If prefix is less or equal 4, we use a dedicated algorithm that 1685 // has shown to run faster than System.arraycopy. 1686 // If more than 4, we use System.arraycopy. 1687 if (len == 1) 1688 container[startIndex] = prefix[0]; 1689 else if (len <= 4) { 1690 int dstLower = startIndex; 1691 int dstUpper = dstLower + len - 1; 1692 int srcUpper = len - 1; 1693 container[dstLower] = prefix[0]; 1694 container[dstUpper] = prefix[srcUpper]; 1695 1696 if (len > 2) 1697 container[++dstLower] = prefix[1]; 1698 if (len == 4) 1699 container[--dstUpper] = prefix[2]; 1700 } else 1701 System.arraycopy(prefix, 0, container, startIndex, len); 1702 } 1703 1704 /** 1705 * Appends the passed {@code suffix} chars to given result 1706 * {@code container}. Updates {@code fastPathData.lastFreeIndex} 1707 * accordingly. 1708 * 1709 * @param suffix The suffix characters to append to result. 1710 * @param len The number of chars to append. 1711 * @param container Char array container which to append the suffix 1712 * 1713 private void appendSuffix(char[] suffix, 1714 int len, 1715 char[] container) { 1716 1717 int startIndex = fastPathData.lastFreeIndex; 1718 1719 // If suffix to append is only 1 char long, just assigns this char. 1720 // If suffix is less or equal 4, we use a dedicated algorithm that 1721 // has shown to run faster than System.arraycopy. 1722 // If more than 4, we use System.arraycopy. 1723 if (len == 1) 1724 container[startIndex] = suffix[0]; 1725 else if (len <= 4) { 1726 int dstLower = startIndex; 1727 int dstUpper = dstLower + len - 1; 1728 int srcUpper = len - 1; 1729 container[dstLower] = suffix[0]; 1730 container[dstUpper] = suffix[srcUpper]; 1731 1732 if (len > 2) 1733 container[++dstLower] = suffix[1]; 1734 if (len == 4) 1735 container[--dstUpper] = suffix[2]; 1736 } else 1737 System.arraycopy(suffix, 0, container, startIndex, len); 1738 1739 fastPathData.lastFreeIndex += len; 1740 } 1741 1742 /** 1743 * Converts digit chars from {@code digitsBuffer} to current locale. 1744 * 1745 * Must be called before adding affixes since we refer to 1746 * {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex}, 1747 * and do not support affixes (for speed reason). 1748 * 1749 * We loop backward starting from last used index in {@code fastPathData}. 1750 * 1751 * @param digitsBuffer The char array container where the digits are stored. 1752 * 1753 private void localizeDigits(char[] digitsBuffer) { 1754 1755 // We will localize only the digits, using the groupingSize, 1756 // and taking into account fractional part. 1757 1758 // First take into account fractional part. 1759 int digitsCounter = 1760 fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex; 1761 1762 // The case when there is no fractional digits. 1763 if (digitsCounter < 0) 1764 digitsCounter = groupingSize; 1765 1766 // Only the digits remains to localize. 1767 for (int cursor = fastPathData.lastFreeIndex - 1; 1768 cursor >= fastPathData.firstUsedIndex; 1769 cursor--) { 1770 if (digitsCounter != 0) { 1771 // This is a digit char, we must localize it. 1772 digitsBuffer[cursor] += fastPathData.zeroDelta; 1773 digitsCounter--; 1774 } else { 1775 // Decimal separator or grouping char. Reinit counter only. 1776 digitsCounter = groupingSize; 1777 } 1778 } 1779 } 1780 1781 /** 1782 * This is the main entry point for the fast-path format algorithm. 1783 * 1784 * At this point we are sure to be in the expected conditions to run it. 1785 * This algorithm builds the formatted result and puts it in the dedicated 1786 * {@code fastPathData.fastPathContainer}. 1787 * 1788 * @param d the double value to be formatted. 1789 * @param negative Flag precising if {@code d} is negative. 1790 * 1791 private void fastDoubleFormat(double d, 1792 boolean negative) { 1793 1794 char[] container = fastPathData.fastPathContainer; 1795 1796 /* 1797 * The principle of the algorithm is to : 1798 * - Break the passed double into its integral and fractional parts 1799 * converted into integers. 1800 * - Then decide if rounding up must be applied or not by following 1801 * the half-even rounding rule, first using approximated scaled 1802 * fractional part. 1803 * - For the difficult cases (approximated scaled fractional part 1804 * being exactly 0.5d), we refine the rounding decision by calling 1805 * exactRoundUp utility method that both calculates the exact roundoff 1806 * on the approximation and takes correct rounding decision. 1807 * - We round-up the fractional part if needed, possibly propagating the 1808 * rounding to integral part if we meet a "all-nine" case for the 1809 * scaled fractional part. 1810 * - We then collect digits from the resulting integral and fractional 1811 * parts, also setting the required grouping chars on the fly. 1812 * - Then we localize the collected digits if needed, and 1813 * - Finally prepend/append prefix/suffix if any is needed. 1814 * 1815 1816 // Exact integral part of d. 1817 int integralPartAsInt = (int) d; 1818 1819 // Exact fractional part of d (since we subtract it's integral part). 1820 double exactFractionalPart = d - (double) integralPartAsInt; 1821 1822 // Approximated scaled fractional part of d (due to multiplication). 1823 double scaledFractional = 1824 exactFractionalPart * fastPathData.fractionalScaleFactor; 1825 1826 // Exact integral part of scaled fractional above. 1827 int fractionalPartAsInt = (int) scaledFractional; 1828 1829 // Exact fractional part of scaled fractional above. 1830 scaledFractional = scaledFractional - (double) fractionalPartAsInt; 1831 1832 // Only when scaledFractional is exactly 0.5d do we have to do exact 1833 // calculations and take fine-grained rounding decision, since 1834 // approximated results above may lead to incorrect decision. 1835 // Otherwise comparing against 0.5d (strictly greater or less) is ok. 1836 boolean roundItUp = false; 1837 if (scaledFractional >= 0.5d) { 1838 if (scaledFractional == 0.5d) 1839 // Rounding need fine-grained decision. 1840 roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt); 1841 else 1842 roundItUp = true; 1843 1844 if (roundItUp) { 1845 // Rounds up both fractional part (and also integral if needed). 1846 if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) { 1847 fractionalPartAsInt++; 1848 } else { 1849 // Propagates rounding to integral part since "all nines" case. 1850 fractionalPartAsInt = 0; 1851 integralPartAsInt++; 1852 } 1853 } 1854 } 1855 1856 // Collecting digits. 1857 collectFractionalDigits(fractionalPartAsInt, container, 1858 fastPathData.fractionalFirstIndex); 1859 collectIntegralDigits(integralPartAsInt, container, 1860 fastPathData.integralLastIndex); 1861 1862 // Localizing digits. 1863 if (fastPathData.zeroDelta != 0) 1864 localizeDigits(container); 1865 1866 // Adding prefix and suffix. 1867 if (negative) { 1868 if (fastPathData.negativeAffixesRequired) 1869 addAffixes(container, 1870 fastPathData.charsNegativePrefix, 1871 fastPathData.charsNegativeSuffix); 1872 } else if (fastPathData.positiveAffixesRequired) 1873 addAffixes(container, 1874 fastPathData.charsPositivePrefix, 1875 fastPathData.charsPositiveSuffix); 1876 } 1877 1878 /** 1879 * A fast-path shortcut of format(double) to be called by NumberFormat, or by 1880 * format(double, ...) public methods. 1881 * 1882 * If instance can be applied fast-path and passed double is not NaN or 1883 * Infinity, is in the integer range, we call {@code fastDoubleFormat} 1884 * after changing {@code d} to its positive value if necessary. 1885 * 1886 * Otherwise returns null by convention since fast-path can't be exercized. 1887 * 1888 * @param d The double value to be formatted 1889 * 1890 * @return the formatted result for {@code d} as a string. 1891 * 1892 String fastFormat(double d) { 1893 boolean isDataSet = false; 1894 // (Re-)Evaluates fast-path status if needed. 1895 if (fastPathCheckNeeded) { 1896 isDataSet = checkAndSetFastPathStatus(); 1897 } 1898 1899 if (!isFastPath ) 1900 // DecimalFormat instance is not in a fast-path state. 1901 return null; 1902 1903 if (!Double.isFinite(d)) 1904 // Should not use fast-path for Infinity and NaN. 1905 return null; 1906 1907 // Extracts and records sign of double value, possibly changing it 1908 // to a positive one, before calling fastDoubleFormat(). 1909 boolean negative = false; 1910 if (d < 0.0d) { 1911 negative = true; 1912 d = -d; 1913 } else if (d == 0.0d) { 1914 negative = (Math.copySign(1.0d, d) == -1.0d); 1915 d = +0.0d; 1916 } 1917 1918 if (d > MAX_INT_AS_DOUBLE) 1919 // Filters out values that are outside expected fast-path range 1920 return null; 1921 else { 1922 if (!isDataSet) { 1923 /* 1924 * If the fast path data is not set through 1925 * checkAndSetFastPathStatus() and fulfil the 1926 * fast path conditions then reset the data 1927 * directly through resetFastPathData() 1928 * 1929 resetFastPathData(isFastPath); 1930 } 1931 fastDoubleFormat(d, negative); 1932 1933 } 1934 1935 1936 // Returns a new string from updated fastPathContainer. 1937 return new String(fastPathData.fastPathContainer, 1938 fastPathData.firstUsedIndex, 1939 fastPathData.lastFreeIndex - fastPathData.firstUsedIndex); 1940 1941 } 1942 1943 /** 1944 * Sets the {@code DigitList} used by this {@code DecimalFormat} 1945 * instance. 1946 * @param number the number to format 1947 * @param isNegative true, if the number is negative; false otherwise 1948 * @param maxDigits the max digits 1949 * 1950 void setDigitList(Number number, boolean isNegative, int maxDigits) { 1951 1952 if (number instanceof Double) { 1953 digitList.set(isNegative, (Double) number, maxDigits, true); 1954 } else if (number instanceof BigDecimal) { 1955 digitList.set(isNegative, (BigDecimal) number, maxDigits, true); 1956 } else if (number instanceof Long) { 1957 digitList.set(isNegative, (Long) number, maxDigits); 1958 } else if (number instanceof BigInteger) { 1959 digitList.set(isNegative, (BigInteger) number, maxDigits); 1960 } 1961 } 1962 1963 // ======== End fast-path formating logic for double ========================= 1964 1965 /** 1966 * Complete the formatting of a finite number. On entry, the digitList must 1967 * be filled in with the correct digits. 1968 * 1969 private StringBuffer subformat(StringBuffer result, FieldDelegate delegate, 1970 boolean isNegative, boolean isInteger, 1971 int maxIntDigits, int minIntDigits, 1972 int maxFraDigits, int minFraDigits) { 1973 1974 // Process prefix 1975 if (isNegative) { 1976 append(result, negativePrefix, delegate, 1977 getNegativePrefixFieldPositions(), Field.SIGN); 1978 } else { 1979 append(result, positivePrefix, delegate, 1980 getPositivePrefixFieldPositions(), Field.SIGN); 1981 } 1982 1983 // Process number 1984 subformatNumber(result, delegate, isNegative, isInteger, 1985 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 1986 1987 // Process suffix 1988 if (isNegative) { 1989 append(result, negativeSuffix, delegate, 1990 getNegativeSuffixFieldPositions(), Field.SIGN); 1991 } else { 1992 append(result, positiveSuffix, delegate, 1993 getPositiveSuffixFieldPositions(), Field.SIGN); 1994 } 1995 1996 return result; 1997 } 1998 1999 /** 2000 * Subformats number part using the {@code DigitList} of this 2001 * {@code DecimalFormat} instance. 2002 * @param result where the text is to be appended 2003 * @param delegate notified of the location of sub fields 2004 * @param isNegative true, if the number is negative; false otherwise 2005 * @param isInteger true, if the number is an integer; false otherwise 2006 * @param maxIntDigits maximum integer digits 2007 * @param minIntDigits minimum integer digits 2008 * @param maxFraDigits maximum fraction digits 2009 * @param minFraDigits minimum fraction digits 2010 * 2011 void subformatNumber(StringBuffer result, FieldDelegate delegate, 2012 boolean isNegative, boolean isInteger, 2013 int maxIntDigits, int minIntDigits, 2014 int maxFraDigits, int minFraDigits) { 2015 2016 char grouping = isCurrencyFormat ? 2017 symbols.getMonetaryGroupingSeparator() : 2018 symbols.getGroupingSeparator(); 2019 char zero = symbols.getZeroDigit(); 2020 int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero 2021 2022 char decimal = isCurrencyFormat ? 2023 symbols.getMonetaryDecimalSeparator() : 2024 symbols.getDecimalSeparator(); 2025 2026 /* Per bug 4147706, DecimalFormat must respect the sign of numbers which 2027 * format as zero. This allows sensible computations and preserves 2028 * relations such as signum(1/x) = signum(x), where x is +Infinity or 2029 * -Infinity. Prior to this fix, we always formatted zero values as if 2030 * they were positive. Liu 7/6/98. 2031 * 2032 if (digitList.isZero()) { 2033 digitList.decimalAt = 0; // Normalize 2034 } 2035 2036 if (useExponentialNotation) { 2037 int iFieldStart = result.length(); 2038 int iFieldEnd = -1; 2039 int fFieldStart = -1; 2040 2041 // Minimum integer digits are handled in exponential format by 2042 // adjusting the exponent. For example, 0.01234 with 3 minimum 2043 // integer digits is "123.4E-4". 2044 // Maximum integer digits are interpreted as indicating the 2045 // repeating range. This is useful for engineering notation, in 2046 // which the exponent is restricted to a multiple of 3. For 2047 // example, 0.01234 with 3 maximum integer digits is "12.34e-3". 2048 // If maximum integer digits are > 1 and are larger than 2049 // minimum integer digits, then minimum integer digits are 2050 // ignored. 2051 int exponent = digitList.decimalAt; 2052 int repeat = maxIntDigits; 2053 int minimumIntegerDigits = minIntDigits; 2054 if (repeat > 1 && repeat > minIntDigits) { 2055 // A repeating range is defined; adjust to it as follows. 2056 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; 2057 // -3,-4,-5=>-6, etc. This takes into account that the 2058 // exponent we have here is off by one from what we expect; 2059 // it is for the format 0.MMMMMx10^n. 2060 if (exponent >= 1) { 2061 exponent = ((exponent - 1) / repeat) * repeat; 2062 } else { 2063 // integer division rounds towards 0 2064 exponent = ((exponent - repeat) / repeat) * repeat; 2065 } 2066 minimumIntegerDigits = 1; 2067 } else { 2068 // No repeating range is defined; use minimum integer digits. 2069 exponent -= minimumIntegerDigits; 2070 } 2071 2072 // We now output a minimum number of digits, and more if there 2073 // are more digits, up to the maximum number of digits. We 2074 // place the decimal point after the "integer" digits, which 2075 // are the first (decimalAt - exponent) digits. 2076 int minimumDigits = minIntDigits + minFraDigits; 2077 if (minimumDigits < 0) { // overflow? 2078 minimumDigits = Integer.MAX_VALUE; 2079 } 2080 2081 // The number of integer digits is handled specially if the number 2082 // is zero, since then there may be no digits. 2083 int integerDigits = digitList.isZero() ? minimumIntegerDigits : 2084 digitList.decimalAt - exponent; 2085 if (minimumDigits < integerDigits) { 2086 minimumDigits = integerDigits; 2087 } 2088 int totalDigits = digitList.count; 2089 if (minimumDigits > totalDigits) { 2090 totalDigits = minimumDigits; 2091 } 2092 boolean addedDecimalSeparator = false; 2093 2094 for (int i=0; i<totalDigits; ++i) { 2095 if (i == integerDigits) { 2096 // Record field information for caller. 2097 iFieldEnd = result.length(); 2098 2099 result.append(decimal); 2100 addedDecimalSeparator = true; 2101 2102 // Record field information for caller. 2103 fFieldStart = result.length(); 2104 } 2105 result.append((i < digitList.count) ? 2106 (char)(digitList.digits[i] + zeroDelta) : 2107 zero); 2108 } 2109 2110 if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) { 2111 // Record field information for caller. 2112 iFieldEnd = result.length(); 2113 2114 result.append(decimal); 2115 addedDecimalSeparator = true; 2116 2117 // Record field information for caller. 2118 fFieldStart = result.length(); 2119 } 2120 2121 // Record field information 2122 if (iFieldEnd == -1) { 2123 iFieldEnd = result.length(); 2124 } 2125 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 2126 iFieldStart, iFieldEnd, result); 2127 if (addedDecimalSeparator) { 2128 delegate.formatted(Field.DECIMAL_SEPARATOR, 2129 Field.DECIMAL_SEPARATOR, 2130 iFieldEnd, fFieldStart, result); 2131 } 2132 if (fFieldStart == -1) { 2133 fFieldStart = result.length(); 2134 } 2135 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 2136 fFieldStart, result.length(), result); 2137 2138 // The exponent is output using the pattern-specified minimum 2139 // exponent digits. There is no maximum limit to the exponent 2140 // digits, since truncating the exponent would result in an 2141 // unacceptable inaccuracy. 2142 int fieldStart = result.length(); 2143 2144 result.append(symbols.getExponentSeparator()); 2145 2146 delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL, 2147 fieldStart, result.length(), result); 2148 2149 // For zero values, we force the exponent to zero. We 2150 // must do this here, and not earlier, because the value 2151 // is used to determine integer digit count above. 2152 if (digitList.isZero()) { 2153 exponent = 0; 2154 } 2155 2156 boolean negativeExponent = exponent < 0; 2157 if (negativeExponent) { 2158 exponent = -exponent; 2159 fieldStart = result.length(); 2160 result.append(symbols.getMinusSignText()); 2161 delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN, 2162 fieldStart, result.length(), result); 2163 } 2164 digitList.set(negativeExponent, exponent); 2165 2166 int eFieldStart = result.length(); 2167 2168 for (int i=digitList.decimalAt; i<minExponentDigits; ++i) { 2169 result.append(zero); 2170 } 2171 for (int i=0; i<digitList.decimalAt; ++i) { 2172 result.append((i < digitList.count) ? 2173 (char)(digitList.digits[i] + zeroDelta) : zero); 2174 } 2175 delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart, 2176 result.length(), result); 2177 } else { 2178 int iFieldStart = result.length(); 2179 2180 // Output the integer portion. Here 'count' is the total 2181 // number of integer digits we will display, including both 2182 // leading zeros required to satisfy getMinimumIntegerDigits, 2183 // and actual digits present in the number. 2184 int count = minIntDigits; 2185 int digitIndex = 0; // Index into digitList.fDigits[] 2186 if (digitList.decimalAt > 0 && count < digitList.decimalAt) { 2187 count = digitList.decimalAt; 2188 } 2189 2190 // Handle the case where getMaximumIntegerDigits() is smaller 2191 // than the real number of integer digits. If this is so, we 2192 // output the least significant max integer digits. For example, 2193 // the value 1997 printed with 2 max integer digits is just "97". 2194 if (count > maxIntDigits) { 2195 count = maxIntDigits; 2196 digitIndex = digitList.decimalAt - count; 2197 } 2198 2199 int sizeBeforeIntegerPart = result.length(); 2200 for (int i=count-1; i>=0; --i) { 2201 if (i < digitList.decimalAt && digitIndex < digitList.count) { 2202 // Output a real digit 2203 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 2204 } else { 2205 // Output a leading zero 2206 result.append(zero); 2207 } 2208 2209 // Output grouping separator if necessary. Don't output a 2210 // grouping separator if i==0 though; that's at the end of 2211 // the integer part. 2212 if (isGroupingUsed() && i>0 && (groupingSize != 0) && 2213 (i % groupingSize == 0)) { 2214 int gStart = result.length(); 2215 result.append(grouping); 2216 delegate.formatted(Field.GROUPING_SEPARATOR, 2217 Field.GROUPING_SEPARATOR, gStart, 2218 result.length(), result); 2219 } 2220 } 2221 2222 // Determine whether or not there are any printable fractional 2223 // digits. If we've used up the digits we know there aren't. 2224 boolean fractionPresent = (minFraDigits > 0) || 2225 (!isInteger && digitIndex < digitList.count); 2226 2227 // If there is no fraction present, and we haven't printed any 2228 // integer digits, then print a zero. Otherwise we won't print 2229 // _any_ digits, and we won't be able to parse this string. 2230 if (!fractionPresent && result.length() == sizeBeforeIntegerPart) { 2231 result.append(zero); 2232 } 2233 2234 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 2235 iFieldStart, result.length(), result); 2236 2237 // Output the decimal separator if we always do so. 2238 int sStart = result.length(); 2239 if (decimalSeparatorAlwaysShown || fractionPresent) { 2240 result.append(decimal); 2241 } 2242 2243 if (sStart != result.length()) { 2244 delegate.formatted(Field.DECIMAL_SEPARATOR, 2245 Field.DECIMAL_SEPARATOR, 2246 sStart, result.length(), result); 2247 } 2248 int fFieldStart = result.length(); 2249 2250 for (int i=0; i < maxFraDigits; ++i) { 2251 // Here is where we escape from the loop. We escape if we've 2252 // output the maximum fraction digits (specified in the for 2253 // expression above). 2254 // We also stop when we've output the minimum digits and either: 2255 // we have an integer, so there is no fractional stuff to 2256 // display, or we're out of significant digits. 2257 if (i >= minFraDigits && 2258 (isInteger || digitIndex >= digitList.count)) { 2259 break; 2260 } 2261 2262 // Output leading fractional zeros. These are zeros that come 2263 // after the decimal but before any significant digits. These 2264 // are only output if abs(number being formatted) < 1.0. 2265 if (-1-i > (digitList.decimalAt-1)) { 2266 result.append(zero); 2267 continue; 2268 } 2269 2270 // Output a digit, if we have any precision left, or a 2271 // zero if we don't. We don't want to output noise digits. 2272 if (!isInteger && digitIndex < digitList.count) { 2273 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 2274 } else { 2275 result.append(zero); 2276 } 2277 } 2278 2279 // Record field information for caller. 2280 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 2281 fFieldStart, result.length(), result); 2282 } 2283 } 2284 2285 /** 2286 * Appends the String {@code string} to {@code result}. 2287 * {@code delegate} is notified of all the 2288 * {@code FieldPosition}s in {@code positions}. 2289 * <p> 2290 * If one of the {@code FieldPosition}s in {@code positions} 2291 * identifies a {@code SIGN} attribute, it is mapped to 2292 * {@code signAttribute}. This is used 2293 * to map the {@code SIGN} attribute to the {@code EXPONENT} 2294 * attribute as necessary. 2295 * <p> 2296 * This is used by {@code subformat} to add the prefix/suffix. 2297 * 2298 private void append(StringBuffer result, String string, 2299 FieldDelegate delegate, 2300 FieldPosition[] positions, 2301 Format.Field signAttribute) { 2302 int start = result.length(); 2303 2304 if (!string.isEmpty()) { 2305 result.append(string); 2306 for (int counter = 0, max = positions.length; counter < max; 2307 counter++) { 2308 FieldPosition fp = positions[counter]; 2309 Format.Field attribute = fp.getFieldAttribute(); 2310 2311 if (attribute == Field.SIGN) { 2312 attribute = signAttribute; 2313 } 2314 delegate.formatted(attribute, attribute, 2315 start + fp.getBeginIndex(), 2316 start + fp.getEndIndex(), result); 2317 } 2318 } 2319 } 2320 */ 2321 // END Android-removed: "fast-path formatting logic for double", subformat(), append(). 2322 2323 /** 2324 * Parses text from a string to produce a {@code Number}. 2325 * <p> 2326 * The method attempts to parse text starting at the index given by 2327 * {@code pos}. 2328 * If parsing succeeds, then the index of {@code pos} is updated 2329 * to the index after the last character used (parsing does not necessarily 2330 * use all characters up to the end of the string), and the parsed 2331 * number is returned. The updated {@code pos} can be used to 2332 * indicate the starting point for the next call to this method. 2333 * If an error occurs, then the index of {@code pos} is not 2334 * changed, the error index of {@code pos} is set to the index of 2335 * the character where the error occurred, and null is returned. 2336 * <p> 2337 * The subclass returned depends on the value of {@link #isParseBigDecimal} 2338 * as well as on the string being parsed. 2339 * <ul> 2340 * <li>If {@code isParseBigDecimal()} is false (the default), 2341 * most integer values are returned as {@code Long} 2342 * objects, no matter how they are written: {@code "17"} and 2343 * {@code "17.000"} both parse to {@code Long(17)}. 2344 * Values that cannot fit into a {@code Long} are returned as 2345 * {@code Double}s. This includes values with a fractional part, 2346 * infinite values, {@code NaN}, and the value -0.0. 2347 * {@code DecimalFormat} does <em>not</em> decide whether to 2348 * return a {@code Double} or a {@code Long} based on the 2349 * presence of a decimal separator in the source string. Doing so 2350 * would prevent integers that overflow the mantissa of a double, 2351 * such as {@code "-9,223,372,036,854,775,808.00"}, from being 2352 * parsed accurately. 2353 * <p> 2354 * Callers may use the {@code Number} methods 2355 * {@code doubleValue}, {@code longValue}, etc., to obtain 2356 * the type they want. 2357 * <li>If {@code isParseBigDecimal()} is true, values are returned 2358 * as {@code BigDecimal} objects. The values are the ones 2359 * constructed by {@link java.math.BigDecimal#BigDecimal(String)} 2360 * for corresponding strings in locale-independent format. The 2361 * special cases negative and positive infinity and NaN are returned 2362 * as {@code Double} instances holding the values of the 2363 * corresponding {@code Double} constants. 2364 * </ul> 2365 * <p> 2366 * {@code DecimalFormat} parses all Unicode characters that represent 2367 * decimal digits, as defined by {@code Character.digit()}. In 2368 * addition, {@code DecimalFormat} also recognizes as digits the ten 2369 * consecutive characters starting with the localized zero digit defined in 2370 * the {@code DecimalFormatSymbols} object. 2371 * 2372 * @param text the string to be parsed 2373 * @param pos A {@code ParsePosition} object with index and error 2374 * index information as described above. 2375 * @return the parsed value, or {@code null} if the parse fails 2376 * @throws NullPointerException if {@code text} or 2377 * {@code pos} is null. 2378 */ 2379 @Override parse(String text, ParsePosition pos)2380 public Number parse(String text, ParsePosition pos) { 2381 // BEGIN Android-changed: Use ICU. 2382 // Return early if the parse position is bogus. 2383 /* 2384 // special case NaN 2385 if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { 2386 pos.index = pos.index + symbols.getNaN().length(); 2387 return Double.valueOf(Double.NaN); 2388 } 2389 2390 boolean[] status = new boolean[STATUS_LENGTH]; 2391 if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) { 2392 return null; 2393 } 2394 2395 // special case INFINITY 2396 if (status[STATUS_INFINITE]) { 2397 if (status[STATUS_POSITIVE] == (multiplier >= 0)) { 2398 return Double.valueOf(Double.POSITIVE_INFINITY); 2399 } else { 2400 return Double.valueOf(Double.NEGATIVE_INFINITY); 2401 } 2402 } 2403 2404 if (multiplier == 0) { 2405 if (digitList.isZero()) { 2406 return Double.valueOf(Double.NaN); 2407 } else if (status[STATUS_POSITIVE]) { 2408 return Double.valueOf(Double.POSITIVE_INFINITY); 2409 } else { 2410 return Double.valueOf(Double.NEGATIVE_INFINITY); 2411 } 2412 } 2413 2414 if (isParseBigDecimal()) { 2415 BigDecimal bigDecimalResult = digitList.getBigDecimal(); 2416 2417 if (multiplier != 1) { 2418 try { 2419 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier()); 2420 } 2421 catch (ArithmeticException e) { // non-terminating decimal expansion 2422 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode); 2423 } 2424 } 2425 2426 if (!status[STATUS_POSITIVE]) { 2427 bigDecimalResult = bigDecimalResult.negate(); 2428 } 2429 return bigDecimalResult; 2430 } else { 2431 boolean gotDouble = true; 2432 boolean gotLongMinimum = false; 2433 double doubleResult = 0.0; 2434 long longResult = 0; 2435 2436 // Finally, have DigitList parse the digits into a value. 2437 if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) { 2438 gotDouble = false; 2439 longResult = digitList.getLong(); 2440 if (longResult < 0) { // got Long.MIN_VALUE 2441 gotLongMinimum = true; 2442 } 2443 } else { 2444 doubleResult = digitList.getDouble(); 2445 } 2446 2447 // Divide by multiplier. We have to be careful here not to do 2448 // unneeded conversions between double and long. 2449 if (multiplier != 1) { 2450 if (gotDouble) { 2451 doubleResult /= multiplier; 2452 } else { 2453 // Avoid converting to double if we can 2454 if (longResult % multiplier == 0) { 2455 longResult /= multiplier; 2456 } else { 2457 doubleResult = ((double)longResult) / multiplier; 2458 gotDouble = true; 2459 } 2460 } 2461 } 2462 2463 if (!status[STATUS_POSITIVE] && !gotLongMinimum) { 2464 doubleResult = -doubleResult; 2465 longResult = -longResult; 2466 } 2467 2468 // At this point, if we divided the result by the multiplier, the 2469 // result may fit into a long. We check for this case and return 2470 // a long if possible. 2471 // We must do this AFTER applying the negative (if appropriate) 2472 // in order to handle the case of LONG_MIN; otherwise, if we do 2473 // this with a positive value -LONG_MIN, the double is > 0, but 2474 // the long is < 0. We also must retain a double in the case of 2475 // -0.0, which will compare as == to a long 0 cast to a double 2476 // (bug 4162852). 2477 if (multiplier != 1 && gotDouble) { 2478 longResult = (long)doubleResult; 2479 gotDouble = ((doubleResult != (double)longResult) || 2480 (doubleResult == 0.0 && 1/doubleResult < 0.0)) && 2481 !isParseIntegerOnly(); 2482 } 2483 2484 // cast inside of ?: because of binary numeric promotion, JLS 15.25 2485 return gotDouble ? (Number)doubleResult : (Number)longResult; 2486 } 2487 */ 2488 if (pos.index < 0 || pos.index >= text.length()) { 2489 return null; 2490 } 2491 2492 // This might return android.icu.math.BigDecimal, java.math.BigInteger or a primitive type. 2493 Number number = icuDecimalFormat.parse(text, pos); 2494 if (number == null) { 2495 return null; 2496 } 2497 if (isParseBigDecimal()) { 2498 if (number instanceof Long) { 2499 return new BigDecimal(number.longValue()); 2500 } 2501 if ((number instanceof Double) && !((Double) number).isInfinite() 2502 && !((Double) number).isNaN()) { 2503 return new BigDecimal(number.toString()); 2504 } 2505 if ((number instanceof Double) && 2506 (((Double) number).isNaN() || ((Double) number).isInfinite())) { 2507 return number; 2508 } 2509 if (number instanceof android.icu.math.BigDecimal) { 2510 return ((android.icu.math.BigDecimal) number).toBigDecimal(); 2511 } 2512 } 2513 if ((number instanceof android.icu.math.BigDecimal) || (number instanceof BigInteger)) { 2514 return number.doubleValue(); 2515 } 2516 if (isParseIntegerOnly() && number.equals(new Double(-0.0))) { 2517 return 0L; 2518 } 2519 return number; 2520 // END Android-changed: Use ICU. 2521 } 2522 2523 // BEGIN Android-removed: Unused private helpers. 2524 /* 2525 /** 2526 * Return a BigInteger multiplier. 2527 * 2528 private BigInteger getBigIntegerMultiplier() { 2529 if (bigIntegerMultiplier == null) { 2530 bigIntegerMultiplier = BigInteger.valueOf(multiplier); 2531 } 2532 return bigIntegerMultiplier; 2533 } 2534 private transient BigInteger bigIntegerMultiplier; 2535 2536 /** 2537 * Return a BigDecimal multiplier. 2538 * 2539 private BigDecimal getBigDecimalMultiplier() { 2540 if (bigDecimalMultiplier == null) { 2541 bigDecimalMultiplier = new BigDecimal(multiplier); 2542 } 2543 return bigDecimalMultiplier; 2544 } 2545 private transient BigDecimal bigDecimalMultiplier; 2546 2547 private static final int STATUS_INFINITE = 0; 2548 private static final int STATUS_POSITIVE = 1; 2549 private static final int STATUS_LENGTH = 2; 2550 2551 /** 2552 * Parse the given text into a number. The text is parsed beginning at 2553 * parsePosition, until an unparseable character is seen. 2554 * @param text The string to parse. 2555 * @param parsePosition The position at which to being parsing. Upon 2556 * return, the first unparseable character. 2557 * @param digits The DigitList to set to the parsed value. 2558 * @param isExponent If true, parse an exponent. This means no 2559 * infinite values and integer only. 2560 * @param status Upon return contains boolean status flags indicating 2561 * whether the value was infinite and whether it was positive. 2562 * 2563 private final boolean subparse(String text, ParsePosition parsePosition, 2564 String positivePrefix, String negativePrefix, 2565 DigitList digits, boolean isExponent, 2566 boolean status[]) { 2567 int position = parsePosition.index; 2568 int oldStart = parsePosition.index; 2569 boolean gotPositive, gotNegative; 2570 2571 // check for positivePrefix; take longest 2572 gotPositive = text.regionMatches(position, positivePrefix, 0, 2573 positivePrefix.length()); 2574 gotNegative = text.regionMatches(position, negativePrefix, 0, 2575 negativePrefix.length()); 2576 2577 if (gotPositive && gotNegative) { 2578 if (positivePrefix.length() > negativePrefix.length()) { 2579 gotNegative = false; 2580 } else if (positivePrefix.length() < negativePrefix.length()) { 2581 gotPositive = false; 2582 } 2583 } 2584 2585 if (gotPositive) { 2586 position += positivePrefix.length(); 2587 } else if (gotNegative) { 2588 position += negativePrefix.length(); 2589 } else { 2590 parsePosition.errorIndex = position; 2591 return false; 2592 } 2593 2594 position = subparseNumber(text, position, digits, true, isExponent, status); 2595 if (position == -1) { 2596 parsePosition.index = oldStart; 2597 parsePosition.errorIndex = oldStart; 2598 return false; 2599 } 2600 2601 // Check for suffix 2602 if (!isExponent) { 2603 if (gotPositive) { 2604 gotPositive = text.regionMatches(position,positiveSuffix,0, 2605 positiveSuffix.length()); 2606 } 2607 if (gotNegative) { 2608 gotNegative = text.regionMatches(position,negativeSuffix,0, 2609 negativeSuffix.length()); 2610 } 2611 2612 // If both match, take longest 2613 if (gotPositive && gotNegative) { 2614 if (positiveSuffix.length() > negativeSuffix.length()) { 2615 gotNegative = false; 2616 } else if (positiveSuffix.length() < negativeSuffix.length()) { 2617 gotPositive = false; 2618 } 2619 } 2620 2621 // Fail if neither or both 2622 if (gotPositive == gotNegative) { 2623 parsePosition.errorIndex = position; 2624 return false; 2625 } 2626 2627 parsePosition.index = position + 2628 (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success! 2629 } else { 2630 parsePosition.index = position; 2631 } 2632 2633 status[STATUS_POSITIVE] = gotPositive; 2634 if (parsePosition.index == oldStart) { 2635 parsePosition.errorIndex = position; 2636 return false; 2637 } 2638 return true; 2639 } 2640 2641 /** 2642 * Parses a number from the given {@code text}. The text is parsed 2643 * beginning at position, until an unparseable character is seen. 2644 * 2645 * @param text the string to parse 2646 * @param position the position at which parsing begins 2647 * @param digits the DigitList to set to the parsed value 2648 * @param checkExponent whether to check for exponential number 2649 * @param isExponent if the exponential part is encountered 2650 * @param status upon return contains boolean status flags indicating 2651 * whether the value is infinite and whether it is 2652 * positive 2653 * @return returns the position of the first unparseable character or 2654 * -1 in case of no valid number parsed 2655 * 2656 int subparseNumber(String text, int position, 2657 DigitList digits, boolean checkExponent, 2658 boolean isExponent, boolean status[]) { 2659 // process digits or Inf, find decimal position 2660 status[STATUS_INFINITE] = false; 2661 if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0, 2662 symbols.getInfinity().length())) { 2663 position += symbols.getInfinity().length(); 2664 status[STATUS_INFINITE] = true; 2665 } else { 2666 // We now have a string of digits, possibly with grouping symbols, 2667 // and decimal points. We want to process these into a DigitList. 2668 // We don't want to put a bunch of leading zeros into the DigitList 2669 // though, so we keep track of the location of the decimal point, 2670 // put only significant digits into the DigitList, and adjust the 2671 // exponent as needed. 2672 2673 digits.decimalAt = digits.count = 0; 2674 char zero = symbols.getZeroDigit(); 2675 char decimal = isCurrencyFormat ? 2676 symbols.getMonetaryDecimalSeparator() : 2677 symbols.getDecimalSeparator(); 2678 char grouping = isCurrencyFormat ? 2679 symbols.getMonetaryGroupingSeparator() : 2680 symbols.getGroupingSeparator(); 2681 String exponentString = symbols.getExponentSeparator(); 2682 boolean sawDecimal = false; 2683 boolean sawExponent = false; 2684 boolean sawDigit = false; 2685 int exponent = 0; // Set to the exponent value, if any 2686 2687 // We have to track digitCount ourselves, because digits.count will 2688 // pin when the maximum allowable digits is reached. 2689 int digitCount = 0; 2690 2691 int backup = -1; 2692 for (; position < text.length(); ++position) { 2693 char ch = text.charAt(position); 2694 2695 /* We recognize all digit ranges, not only the Latin digit range 2696 * '0'..'9'. We do so by using the Character.digit() method, 2697 * which converts a valid Unicode digit to the range 0..9. 2698 * 2699 * The character 'ch' may be a digit. If so, place its value 2700 * from 0 to 9 in 'digit'. First try using the locale digit, 2701 * which may or MAY NOT be a standard Unicode digit range. If 2702 * this fails, try using the standard Unicode digit ranges by 2703 * calling Character.digit(). If this also fails, digit will 2704 * have a value outside the range 0..9. 2705 * 2706 int digit = ch - zero; 2707 if (digit < 0 || digit > 9) { 2708 digit = Character.digit(ch, 10); 2709 } 2710 2711 if (digit == 0) { 2712 // Cancel out backup setting (see grouping handler below) 2713 backup = -1; // Do this BEFORE continue statement below!!! 2714 sawDigit = true; 2715 2716 // Handle leading zeros 2717 if (digits.count == 0) { 2718 // Ignore leading zeros in integer part of number. 2719 if (!sawDecimal) { 2720 continue; 2721 } 2722 2723 // If we have seen the decimal, but no significant 2724 // digits yet, then we account for leading zeros by 2725 // decrementing the digits.decimalAt into negative 2726 // values. 2727 --digits.decimalAt; 2728 } else { 2729 ++digitCount; 2730 digits.append((char)(digit + '0')); 2731 } 2732 } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above 2733 sawDigit = true; 2734 ++digitCount; 2735 digits.append((char)(digit + '0')); 2736 2737 // Cancel out backup setting (see grouping handler below) 2738 backup = -1; 2739 } else if (!isExponent && ch == decimal) { 2740 // If we're only parsing integers, or if we ALREADY saw the 2741 // decimal, then don't parse this one. 2742 if (isParseIntegerOnly() || sawDecimal) { 2743 break; 2744 } 2745 digits.decimalAt = digitCount; // Not digits.count! 2746 sawDecimal = true; 2747 } else if (!isExponent && ch == grouping && isGroupingUsed()) { 2748 if (sawDecimal) { 2749 break; 2750 } 2751 // Ignore grouping characters, if we are using them, but 2752 // require that they be followed by a digit. Otherwise 2753 // we backup and reprocess them. 2754 backup = position; 2755 } else if (checkExponent && !isExponent && text.regionMatches(position, exponentString, 0, exponentString.length()) 2756 && !sawExponent) { 2757 // Process the exponent by recursively calling this method. 2758 ParsePosition pos = new ParsePosition(position + exponentString.length()); 2759 boolean[] stat = new boolean[STATUS_LENGTH]; 2760 DigitList exponentDigits = new DigitList(); 2761 2762 if (subparse(text, pos, "", symbols.getMinusSignText(), exponentDigits, true, stat) && 2763 exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) { 2764 position = pos.index; // Advance past the exponent 2765 exponent = (int)exponentDigits.getLong(); 2766 if (!stat[STATUS_POSITIVE]) { 2767 exponent = -exponent; 2768 } 2769 sawExponent = true; 2770 } 2771 break; // Whether we fail or succeed, we exit this loop 2772 } else { 2773 break; 2774 } 2775 } 2776 2777 if (backup != -1) { 2778 position = backup; 2779 } 2780 2781 // If there was no decimal point we have an integer 2782 if (!sawDecimal) { 2783 digits.decimalAt = digitCount; // Not digits.count! 2784 } 2785 2786 // Adjust for exponent, if any 2787 digits.decimalAt += exponent; 2788 2789 // If none of the text string was recognized. For example, parse 2790 // "x" with pattern "#0.00" (return index and error index both 0) 2791 // parse "$" with pattern "$#0.00". (return index 0 and error 2792 // index 1). 2793 if (!sawDigit && digitCount == 0) { 2794 return -1; 2795 } 2796 } 2797 return position; 2798 2799 } 2800 */ 2801 // END Android-removed: Unused private helpers. 2802 2803 /** 2804 * Returns a copy of the decimal format symbols, which is generally not 2805 * changed by the programmer or user. 2806 * @return a copy of the desired DecimalFormatSymbols 2807 * @see java.text.DecimalFormatSymbols 2808 */ getDecimalFormatSymbols()2809 public DecimalFormatSymbols getDecimalFormatSymbols() { 2810 // BEGIN Android-changed: Use ICU. 2811 /* 2812 try { 2813 // don't allow multiple references 2814 return (DecimalFormatSymbols) symbols.clone(); 2815 } catch (Exception foo) { 2816 return null; // should never happen 2817 } 2818 */ 2819 return DecimalFormatSymbols.fromIcuInstance(icuDecimalFormat.getDecimalFormatSymbols()); 2820 // END Android-changed: Use ICU. 2821 } 2822 2823 2824 /** 2825 * Sets the decimal format symbols, which is generally not changed 2826 * by the programmer or user. 2827 * @param newSymbols desired DecimalFormatSymbols 2828 * @see java.text.DecimalFormatSymbols 2829 */ setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)2830 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { 2831 try { 2832 // don't allow multiple references 2833 symbols = (DecimalFormatSymbols) newSymbols.clone(); 2834 // BEGIN Android-changed: Use ICU. 2835 /* 2836 expandAffixes(); 2837 fastPathCheckNeeded = true; 2838 */ 2839 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 2840 // END Android-changed: Use ICU. 2841 } catch (Exception foo) { 2842 // should never happen 2843 } 2844 } 2845 2846 /** 2847 * Get the positive prefix. 2848 * <P>Examples: +123, $123, sFr123 2849 * 2850 * @return the positive prefix 2851 */ getPositivePrefix()2852 public String getPositivePrefix () { 2853 // Android-changed: Use ICU. 2854 // return positivePrefix; 2855 return icuDecimalFormat.getPositivePrefix(); 2856 } 2857 2858 /** 2859 * Set the positive prefix. 2860 * <P>Examples: +123, $123, sFr123 2861 * 2862 * @param newValue the new positive prefix 2863 */ setPositivePrefix(String newValue)2864 public void setPositivePrefix (String newValue) { 2865 // BEGIN Android-changed: Use ICU. 2866 /* 2867 positivePrefix = newValue; 2868 posPrefixPattern = null; 2869 positivePrefixFieldPositions = null; 2870 fastPathCheckNeeded = true; 2871 */ 2872 icuDecimalFormat.setPositivePrefix(newValue); 2873 // END Android-changed: Use ICU. 2874 } 2875 2876 // BEGIN Android-removed: private helper getPositivePrefixFieldPositions(). 2877 /* 2878 /** 2879 * Returns the FieldPositions of the fields in the prefix used for 2880 * positive numbers. This is not used if the user has explicitly set 2881 * a positive prefix via {@code setPositivePrefix}. This is 2882 * lazily created. 2883 * 2884 * @return FieldPositions in positive prefix 2885 * 2886 private FieldPosition[] getPositivePrefixFieldPositions() { 2887 if (positivePrefixFieldPositions == null) { 2888 if (posPrefixPattern != null) { 2889 positivePrefixFieldPositions = expandAffix(posPrefixPattern); 2890 } else { 2891 positivePrefixFieldPositions = EmptyFieldPositionArray; 2892 } 2893 } 2894 return positivePrefixFieldPositions; 2895 } 2896 */ 2897 // END Android-removed: private helper getPositivePrefixFieldPositions(). 2898 2899 /** 2900 * Get the negative prefix. 2901 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2902 * 2903 * @return the negative prefix 2904 */ getNegativePrefix()2905 public String getNegativePrefix () { 2906 // Android-changed: Use ICU. 2907 // return negativePrefix; 2908 return icuDecimalFormat.getNegativePrefix(); 2909 } 2910 2911 /** 2912 * Set the negative prefix. 2913 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2914 * 2915 * @param newValue the new negative prefix 2916 */ setNegativePrefix(String newValue)2917 public void setNegativePrefix (String newValue) { 2918 // BEGIN Android-changed: Use ICU. 2919 /* 2920 negativePrefix = newValue; 2921 negPrefixPattern = null; 2922 fastPathCheckNeeded = true; 2923 */ 2924 icuDecimalFormat.setNegativePrefix(newValue); 2925 // END Android-changed: Use ICU. 2926 } 2927 2928 // BEGIN Android-removed: private helper getNegativePrefixFieldPositions(). 2929 /* 2930 /** 2931 * Returns the FieldPositions of the fields in the prefix used for 2932 * negative numbers. This is not used if the user has explicitly set 2933 * a negative prefix via {@code setNegativePrefix}. This is 2934 * lazily created. 2935 * 2936 * @return FieldPositions in positive prefix 2937 * 2938 private FieldPosition[] getNegativePrefixFieldPositions() { 2939 if (negativePrefixFieldPositions == null) { 2940 if (negPrefixPattern != null) { 2941 negativePrefixFieldPositions = expandAffix(negPrefixPattern); 2942 } else { 2943 negativePrefixFieldPositions = EmptyFieldPositionArray; 2944 } 2945 } 2946 return negativePrefixFieldPositions; 2947 } 2948 */ 2949 // END Android-removed: private helper getNegativePrefixFieldPositions(). 2950 2951 /** 2952 * Get the positive suffix. 2953 * <P>Example: 123% 2954 * 2955 * @return the positive suffix 2956 */ getPositiveSuffix()2957 public String getPositiveSuffix () { 2958 // Android-changed: Use ICU. 2959 // return positiveSuffix; 2960 return icuDecimalFormat.getPositiveSuffix(); 2961 } 2962 2963 /** 2964 * Set the positive suffix. 2965 * <P>Example: 123% 2966 * 2967 * @param newValue the new positive suffix 2968 */ setPositiveSuffix(String newValue)2969 public void setPositiveSuffix (String newValue) { 2970 // BEGIN Android-changed: Use ICU. 2971 /* 2972 positiveSuffix = newValue; 2973 posSuffixPattern = null; 2974 fastPathCheckNeeded = true; 2975 */ 2976 icuDecimalFormat.setPositiveSuffix(newValue); 2977 // END Android-changed: Use ICU. 2978 } 2979 2980 // BEGIN Android-removed: private helper getPositiveSuffixFieldPositions(). 2981 /* 2982 /** 2983 * Returns the FieldPositions of the fields in the suffix used for 2984 * positive numbers. This is not used if the user has explicitly set 2985 * a positive suffix via {@code setPositiveSuffix}. This is 2986 * lazily created. 2987 * 2988 * @return FieldPositions in positive prefix 2989 * 2990 private FieldPosition[] getPositiveSuffixFieldPositions() { 2991 if (positiveSuffixFieldPositions == null) { 2992 if (posSuffixPattern != null) { 2993 positiveSuffixFieldPositions = expandAffix(posSuffixPattern); 2994 } else { 2995 positiveSuffixFieldPositions = EmptyFieldPositionArray; 2996 } 2997 } 2998 return positiveSuffixFieldPositions; 2999 } 3000 */ 3001 // END Android-removed: private helper getPositiveSuffixFieldPositions(). 3002 3003 /** 3004 * Get the negative suffix. 3005 * <P>Examples: -123%, ($123) (with positive suffixes) 3006 * 3007 * @return the negative suffix 3008 */ getNegativeSuffix()3009 public String getNegativeSuffix () { 3010 // Android-changed: Use ICU. 3011 // return negativeSuffix; 3012 return icuDecimalFormat.getNegativeSuffix(); 3013 } 3014 3015 /** 3016 * Set the negative suffix. 3017 * <P>Examples: 123% 3018 * 3019 * @param newValue the new negative suffix 3020 */ setNegativeSuffix(String newValue)3021 public void setNegativeSuffix (String newValue) { 3022 // BEGIN Android-changed: Use ICU. 3023 /* 3024 negativeSuffix = newValue; 3025 negSuffixPattern = null; 3026 fastPathCheckNeeded = true; 3027 */ 3028 icuDecimalFormat.setNegativeSuffix(newValue); 3029 // END Android-changed: Use ICU. 3030 } 3031 3032 // BEGIN Android-removed: private helper getNegativeSuffixFieldPositions(). 3033 /* 3034 /** 3035 * Returns the FieldPositions of the fields in the suffix used for 3036 * negative numbers. This is not used if the user has explicitly set 3037 * a negative suffix via {@code setNegativeSuffix}. This is 3038 * lazily created. 3039 * 3040 * @return FieldPositions in positive prefix 3041 * 3042 private FieldPosition[] getNegativeSuffixFieldPositions() { 3043 if (negativeSuffixFieldPositions == null) { 3044 if (negSuffixPattern != null) { 3045 negativeSuffixFieldPositions = expandAffix(negSuffixPattern); 3046 } else { 3047 negativeSuffixFieldPositions = EmptyFieldPositionArray; 3048 } 3049 } 3050 return negativeSuffixFieldPositions; 3051 } 3052 */ 3053 // END Android-removed: private helper getNegativeSuffixFieldPositions(). 3054 3055 /** 3056 * Gets the multiplier for use in percent, per mille, and similar 3057 * formats. 3058 * 3059 * @return the multiplier 3060 * @see #setMultiplier(int) 3061 */ getMultiplier()3062 public int getMultiplier () { 3063 // Android-changed: Use ICU. 3064 // return multiplier; 3065 return icuDecimalFormat.getMultiplier(); 3066 } 3067 3068 /** 3069 * Sets the multiplier for use in percent, per mille, and similar 3070 * formats. 3071 * For a percent format, set the multiplier to 100 and the suffixes to 3072 * have '%' (for Arabic, use the Arabic percent sign). 3073 * For a per mille format, set the multiplier to 1000 and the suffixes to 3074 * have '\u2030'. 3075 * 3076 * <P>Example: with multiplier 100, 1.23 is formatted as "123", and 3077 * "123" is parsed into 1.23. 3078 * 3079 * @param newValue the new multiplier 3080 * @see #getMultiplier 3081 */ setMultiplier(int newValue)3082 public void setMultiplier (int newValue) { 3083 // BEGIN Android-changed: Use ICU. 3084 /* 3085 multiplier = newValue; 3086 bigDecimalMultiplier = null; 3087 bigIntegerMultiplier = null; 3088 fastPathCheckNeeded = true; 3089 */ 3090 icuDecimalFormat.setMultiplier(newValue); 3091 // END Android-changed: Use ICU. 3092 } 3093 3094 /** 3095 * {@inheritDoc} 3096 */ 3097 @Override setGroupingUsed(boolean newValue)3098 public void setGroupingUsed(boolean newValue) { 3099 // BEGIN Android-changed: Use ICU. 3100 /* 3101 super.setGroupingUsed(newValue); 3102 fastPathCheckNeeded = true; 3103 */ 3104 icuDecimalFormat.setGroupingUsed(newValue); 3105 // END Android-changed: Use ICU. 3106 } 3107 3108 // BEGIN Android-added: isGroupingUsed() override delegating to ICU. 3109 /** 3110 * {@inheritDoc} 3111 */ 3112 @Override isGroupingUsed()3113 public boolean isGroupingUsed() { 3114 return icuDecimalFormat.isGroupingUsed(); 3115 } 3116 // END Android-added: isGroupingUsed() override delegating to ICU. 3117 3118 /** 3119 * Return the grouping size. Grouping size is the number of digits between 3120 * grouping separators in the integer portion of a number. For example, 3121 * in the number "123,456.78", the grouping size is 3. Grouping size of 3122 * zero designates that grouping is not used, which provides the same 3123 * formatting as if calling {@link #setGroupingUsed(boolean) 3124 * setGroupingUsed(false)}. 3125 * 3126 * @return the grouping size 3127 * @see #setGroupingSize 3128 * @see java.text.NumberFormat#isGroupingUsed 3129 * @see java.text.DecimalFormatSymbols#getGroupingSeparator 3130 */ getGroupingSize()3131 public int getGroupingSize () { 3132 // Android-changed: Use ICU. 3133 // return groupingSize; 3134 return icuDecimalFormat.getGroupingSize(); 3135 } 3136 3137 /** 3138 * Set the grouping size. Grouping size is the number of digits between 3139 * grouping separators in the integer portion of a number. For example, 3140 * in the number "123,456.78", the grouping size is 3. Grouping size of 3141 * zero designates that grouping is not used, which provides the same 3142 * formatting as if calling {@link #setGroupingUsed(boolean) 3143 * setGroupingUsed(false)}. 3144 * <p> 3145 * The value passed in is converted to a byte, which may lose information. 3146 * Values that are negative or greater than 3147 * {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE}, will throw an 3148 * {@code IllegalArgumentException}. 3149 * 3150 * @param newValue the new grouping size 3151 * @see #getGroupingSize 3152 * @see java.text.NumberFormat#setGroupingUsed 3153 * @see java.text.DecimalFormatSymbols#setGroupingSeparator 3154 * @throws IllegalArgumentException if {@code newValue} is negative or 3155 * greater than {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE} 3156 */ setGroupingSize(int newValue)3157 public void setGroupingSize (int newValue) { 3158 if (newValue < 0 || newValue > Byte.MAX_VALUE) { 3159 throw new IllegalArgumentException( 3160 "newValue is out of valid range. value: " + newValue); 3161 } 3162 // BEGIN Android-changed: Use ICU. 3163 /* 3164 groupingSize = (byte)newValue; 3165 fastPathCheckNeeded = true; 3166 */ 3167 icuDecimalFormat.setGroupingSize(newValue); 3168 // END Android-changed: Use ICU. 3169 } 3170 3171 /** 3172 * Allows you to get the behavior of the decimal separator with integers. 3173 * (The decimal separator will always appear with decimals.) 3174 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 3175 * 3176 * @return {@code true} if the decimal separator is always shown; 3177 * {@code false} otherwise 3178 */ isDecimalSeparatorAlwaysShown()3179 public boolean isDecimalSeparatorAlwaysShown() { 3180 // Android-changed: Use ICU. 3181 // return decimalSeparatorAlwaysShown; 3182 return icuDecimalFormat.isDecimalSeparatorAlwaysShown(); 3183 } 3184 3185 /** 3186 * Allows you to set the behavior of the decimal separator with integers. 3187 * (The decimal separator will always appear with decimals.) 3188 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 3189 * 3190 * @param newValue {@code true} if the decimal separator is always shown; 3191 * {@code false} otherwise 3192 */ setDecimalSeparatorAlwaysShown(boolean newValue)3193 public void setDecimalSeparatorAlwaysShown(boolean newValue) { 3194 // BEGIN Android-changed: Use ICU. 3195 /* 3196 decimalSeparatorAlwaysShown = newValue; 3197 fastPathCheckNeeded = true; 3198 */ 3199 icuDecimalFormat.setDecimalSeparatorAlwaysShown(newValue); 3200 // END Android-changed: Use ICU. 3201 } 3202 3203 /** 3204 * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 3205 * method returns {@code BigDecimal}. The default value is false. 3206 * 3207 * @return {@code true} if the parse method returns BigDecimal; 3208 * {@code false} otherwise 3209 * @see #setParseBigDecimal 3210 * @since 1.5 3211 */ isParseBigDecimal()3212 public boolean isParseBigDecimal() { 3213 // Android-changed: Use ICU. 3214 // return parseBigDecimal; 3215 return icuDecimalFormat.isParseBigDecimal(); 3216 } 3217 3218 /** 3219 * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 3220 * method returns {@code BigDecimal}. 3221 * 3222 * @param newValue {@code true} if the parse method returns BigDecimal; 3223 * {@code false} otherwise 3224 * @see #isParseBigDecimal 3225 * @since 1.5 3226 */ setParseBigDecimal(boolean newValue)3227 public void setParseBigDecimal(boolean newValue) { 3228 // Android-changed: Use ICU. 3229 // parseBigDecimal = newValue; 3230 icuDecimalFormat.setParseBigDecimal(newValue); 3231 } 3232 3233 // BEGIN Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 3234 /** 3235 * {@inheritDoc} 3236 */ 3237 @Override isParseIntegerOnly()3238 public boolean isParseIntegerOnly() { 3239 return icuDecimalFormat.isParseIntegerOnly(); 3240 } 3241 3242 /** 3243 * {@inheritDoc} 3244 */ 3245 @Override setParseIntegerOnly(boolean value)3246 public void setParseIntegerOnly(boolean value) { 3247 super.setParseIntegerOnly(value); 3248 icuDecimalFormat.setParseIntegerOnly(value); 3249 } 3250 // END Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 3251 3252 /** 3253 * Standard override; no change in semantics. 3254 */ 3255 @Override clone()3256 public Object clone() { 3257 // BEGIN Android-changed: Use ICU, remove fast path related code. 3258 /* 3259 DecimalFormat other = (DecimalFormat) super.clone(); 3260 other.symbols = (DecimalFormatSymbols) symbols.clone(); 3261 other.digitList = (DigitList) digitList.clone(); 3262 3263 // Fast-path is almost stateless algorithm. The only logical state is the 3264 // isFastPath flag. In addition fastPathCheckNeeded is a sentinel flag 3265 // that forces recalculation of all fast-path fields when set to true. 3266 // 3267 // There is thus no need to clone all the fast-path fields. 3268 // We just only need to set fastPathCheckNeeded to true when cloning, 3269 // and init fastPathData to null as if it were a truly new instance. 3270 // Every fast-path field will be recalculated (only once) at next usage of 3271 // fast-path algorithm. 3272 other.fastPathCheckNeeded = true; 3273 other.isFastPath = false; 3274 other.fastPathData = null; 3275 3276 return other; 3277 */ 3278 try { 3279 DecimalFormat other = (DecimalFormat) super.clone(); 3280 other.icuDecimalFormat = (android.icu.text.DecimalFormat) icuDecimalFormat.clone(); 3281 other.symbols = (DecimalFormatSymbols) symbols.clone(); 3282 return other; 3283 } catch (Exception e) { 3284 throw new InternalError(); 3285 } 3286 // END Android-changed: Use ICU, remove fast path related code. 3287 } 3288 3289 /** 3290 * Overrides equals 3291 */ 3292 @Override equals(Object obj)3293 public boolean equals(Object obj) 3294 { 3295 // BEGIN Android-changed: re-implement equals() using ICU fields. 3296 /* 3297 if (obj == null) 3298 return false; 3299 if (!super.equals(obj)) 3300 return false; // super does class check 3301 DecimalFormat other = (DecimalFormat) obj; 3302 return ((posPrefixPattern == other.posPrefixPattern && 3303 positivePrefix.equals(other.positivePrefix)) 3304 || (posPrefixPattern != null && 3305 posPrefixPattern.equals(other.posPrefixPattern))) 3306 && ((posSuffixPattern == other.posSuffixPattern && 3307 positiveSuffix.equals(other.positiveSuffix)) 3308 || (posSuffixPattern != null && 3309 posSuffixPattern.equals(other.posSuffixPattern))) 3310 && ((negPrefixPattern == other.negPrefixPattern && 3311 negativePrefix.equals(other.negativePrefix)) 3312 || (negPrefixPattern != null && 3313 negPrefixPattern.equals(other.negPrefixPattern))) 3314 && ((negSuffixPattern == other.negSuffixPattern && 3315 negativeSuffix.equals(other.negativeSuffix)) 3316 || (negSuffixPattern != null && 3317 negSuffixPattern.equals(other.negSuffixPattern))) 3318 && multiplier == other.multiplier 3319 && groupingSize == other.groupingSize 3320 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown 3321 && parseBigDecimal == other.parseBigDecimal 3322 && useExponentialNotation == other.useExponentialNotation 3323 && (!useExponentialNotation || 3324 minExponentDigits == other.minExponentDigits) 3325 && maximumIntegerDigits == other.maximumIntegerDigits 3326 && minimumIntegerDigits == other.minimumIntegerDigits 3327 && maximumFractionDigits == other.maximumFractionDigits 3328 && minimumFractionDigits == other.minimumFractionDigits 3329 && roundingMode == other.roundingMode 3330 && symbols.equals(other.symbols); 3331 */ 3332 if (obj == null) { 3333 return false; 3334 } 3335 if (this == obj) { 3336 return true; 3337 } 3338 if (!(obj instanceof DecimalFormat)) { 3339 return false; 3340 } 3341 DecimalFormat other = (DecimalFormat) obj; 3342 return icuDecimalFormat.equals(other.icuDecimalFormat) 3343 && compareIcuRoundingIncrement(other.icuDecimalFormat); 3344 } 3345 compareIcuRoundingIncrement(android.icu.text.DecimalFormat other)3346 private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat other) { 3347 BigDecimal increment = this.icuDecimalFormat.getRoundingIncrement(); 3348 if (increment != null) { 3349 return (other.getRoundingIncrement() != null) 3350 && increment.equals(other.getRoundingIncrement()); 3351 } 3352 return other.getRoundingIncrement() == null; 3353 } 3354 // END Android-changed: re-implement equals() using ICU fields. 3355 3356 /** 3357 * Overrides hashCode 3358 */ 3359 @Override hashCode()3360 public int hashCode() { 3361 // Android-changed: use getPositivePrefix() instead of positivePrefix field. 3362 // return super.hashCode() * 37 + positivePrefix.hashCode(); 3363 return super.hashCode() * 37 + getPositivePrefix().hashCode(); 3364 // just enough fields for a reasonable distribution 3365 } 3366 3367 /** 3368 * Synthesizes a pattern string that represents the current state 3369 * of this Format object. 3370 * 3371 * @return a pattern string 3372 * @see #applyPattern 3373 */ toPattern()3374 public String toPattern() { 3375 // Android-changed: use ICU. 3376 // return toPattern( false ); 3377 return icuDecimalFormat.toPattern(); 3378 } 3379 3380 /** 3381 * Synthesizes a localized pattern string that represents the current 3382 * state of this Format object. 3383 * 3384 * @return a localized pattern string 3385 * @see #applyPattern 3386 */ toLocalizedPattern()3387 public String toLocalizedPattern() { 3388 // Android-changed: use ICU. 3389 // return toPattern( true ); 3390 return icuDecimalFormat.toLocalizedPattern(); 3391 } 3392 3393 // BEGIN Android-removed: Unused private helpers. 3394 /* 3395 /** 3396 * Expand the affix pattern strings into the expanded affix strings. If any 3397 * affix pattern string is null, do not expand it. This method should be 3398 * called any time the symbols or the affix patterns change in order to keep 3399 * the expanded affix strings up to date. 3400 * 3401 private void expandAffixes() { 3402 // Reuse one StringBuffer for better performance 3403 StringBuffer buffer = new StringBuffer(); 3404 if (posPrefixPattern != null) { 3405 positivePrefix = expandAffix(posPrefixPattern, buffer); 3406 positivePrefixFieldPositions = null; 3407 } 3408 if (posSuffixPattern != null) { 3409 positiveSuffix = expandAffix(posSuffixPattern, buffer); 3410 positiveSuffixFieldPositions = null; 3411 } 3412 if (negPrefixPattern != null) { 3413 negativePrefix = expandAffix(negPrefixPattern, buffer); 3414 negativePrefixFieldPositions = null; 3415 } 3416 if (negSuffixPattern != null) { 3417 negativeSuffix = expandAffix(negSuffixPattern, buffer); 3418 negativeSuffixFieldPositions = null; 3419 } 3420 } 3421 3422 /** 3423 * Expand an affix pattern into an affix string. All characters in the 3424 * pattern are literal unless prefixed by QUOTE. The following characters 3425 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 3426 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 3427 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 3428 * currency code. Any other character after a QUOTE represents itself. 3429 * QUOTE must be followed by another character; QUOTE may not occur by 3430 * itself at the end of the pattern. 3431 * 3432 * @param pattern the non-null, possibly empty pattern 3433 * @param buffer a scratch StringBuffer; its contents will be lost 3434 * @return the expanded equivalent of pattern 3435 * 3436 private String expandAffix(String pattern, StringBuffer buffer) { 3437 buffer.setLength(0); 3438 for (int i=0; i<pattern.length(); ) { 3439 char c = pattern.charAt(i++); 3440 if (c == QUOTE) { 3441 c = pattern.charAt(i++); 3442 switch (c) { 3443 case CURRENCY_SIGN: 3444 if (i<pattern.length() && 3445 pattern.charAt(i) == CURRENCY_SIGN) { 3446 ++i; 3447 buffer.append(symbols.getInternationalCurrencySymbol()); 3448 } else { 3449 buffer.append(symbols.getCurrencySymbol()); 3450 } 3451 continue; 3452 case PATTERN_PERCENT: 3453 buffer.append(symbols.getPercentText()); 3454 continue; 3455 case PATTERN_PER_MILLE: 3456 buffer.append(symbols.getPerMillText()); 3457 continue; 3458 case PATTERN_MINUS: 3459 buffer.append(symbols.getMinusSignText()); 3460 continue; 3461 } 3462 } 3463 buffer.append(c); 3464 } 3465 return buffer.toString(); 3466 } 3467 3468 /** 3469 * Expand an affix pattern into an array of FieldPositions describing 3470 * how the pattern would be expanded. 3471 * All characters in the 3472 * pattern are literal unless prefixed by QUOTE. The following characters 3473 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 3474 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 3475 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 3476 * currency code. Any other character after a QUOTE represents itself. 3477 * QUOTE must be followed by another character; QUOTE may not occur by 3478 * itself at the end of the pattern. 3479 * 3480 * @param pattern the non-null, possibly empty pattern 3481 * @return FieldPosition array of the resulting fields. 3482 * 3483 private FieldPosition[] expandAffix(String pattern) { 3484 ArrayList<FieldPosition> positions = null; 3485 int stringIndex = 0; 3486 for (int i=0; i<pattern.length(); ) { 3487 char c = pattern.charAt(i++); 3488 if (c == QUOTE) { 3489 Format.Field fieldID = null; 3490 String string = null; 3491 c = pattern.charAt(i++); 3492 switch (c) { 3493 case CURRENCY_SIGN: 3494 if (i<pattern.length() && 3495 pattern.charAt(i) == CURRENCY_SIGN) { 3496 ++i; 3497 string = symbols.getInternationalCurrencySymbol(); 3498 } else { 3499 string = symbols.getCurrencySymbol(); 3500 } 3501 fieldID = Field.CURRENCY; 3502 break; 3503 case PATTERN_PERCENT: 3504 string = symbols.getPercentText(); 3505 fieldID = Field.PERCENT; 3506 break; 3507 case PATTERN_PER_MILLE: 3508 string = symbols.getPerMillText(); 3509 fieldID = Field.PERMILLE; 3510 break; 3511 case PATTERN_MINUS: 3512 string = symbols.getMinusSignText(); 3513 fieldID = Field.SIGN; 3514 break; 3515 } 3516 3517 if (fieldID != null && !string.isEmpty()) { 3518 if (positions == null) { 3519 positions = new ArrayList<>(2); 3520 } 3521 FieldPosition fp = new FieldPosition(fieldID); 3522 fp.setBeginIndex(stringIndex); 3523 fp.setEndIndex(stringIndex + string.length()); 3524 positions.add(fp); 3525 stringIndex += string.length(); 3526 continue; 3527 } 3528 } 3529 stringIndex++; 3530 } 3531 if (positions != null) { 3532 return positions.toArray(EmptyFieldPositionArray); 3533 } 3534 return EmptyFieldPositionArray; 3535 } 3536 3537 /** 3538 * Appends an affix pattern to the given StringBuffer, quoting special 3539 * characters as needed. Uses the internal affix pattern, if that exists, 3540 * or the literal affix, if the internal affix pattern is null. The 3541 * appended string will generate the same affix pattern (or literal affix) 3542 * when passed to toPattern(). 3543 * 3544 * @param buffer the affix string is appended to this 3545 * @param affixPattern a pattern such as posPrefixPattern; may be null 3546 * @param expAffix a corresponding expanded affix, such as positivePrefix. 3547 * Ignored unless affixPattern is null. If affixPattern is null, then 3548 * expAffix is appended as a literal affix. 3549 * @param localized true if the appended pattern should contain localized 3550 * pattern characters; otherwise, non-localized pattern chars are appended 3551 * 3552 private void appendAffix(StringBuffer buffer, String affixPattern, 3553 String expAffix, boolean localized) { 3554 if (affixPattern == null) { 3555 appendAffix(buffer, expAffix, localized); 3556 } else { 3557 int i; 3558 for (int pos=0; pos<affixPattern.length(); pos=i) { 3559 i = affixPattern.indexOf(QUOTE, pos); 3560 if (i < 0) { 3561 appendAffix(buffer, affixPattern.substring(pos), localized); 3562 break; 3563 } 3564 if (i > pos) { 3565 appendAffix(buffer, affixPattern.substring(pos, i), localized); 3566 } 3567 char c = affixPattern.charAt(++i); 3568 ++i; 3569 if (c == QUOTE) { 3570 buffer.append(c); 3571 // Fall through and append another QUOTE below 3572 } else if (c == CURRENCY_SIGN && 3573 i<affixPattern.length() && 3574 affixPattern.charAt(i) == CURRENCY_SIGN) { 3575 ++i; 3576 buffer.append(c); 3577 // Fall through and append another CURRENCY_SIGN below 3578 } else if (localized) { 3579 switch (c) { 3580 case PATTERN_PERCENT: 3581 buffer.append(symbols.getPercentText()); 3582 continue; 3583 case PATTERN_PER_MILLE: 3584 buffer.append(symbols.getPerMillText()); 3585 continue; 3586 case PATTERN_MINUS: 3587 buffer.append(symbols.getMinusSignText()); 3588 continue; 3589 } 3590 } 3591 buffer.append(c); 3592 } 3593 } 3594 } 3595 3596 /** 3597 * Append an affix to the given StringBuffer, using quotes if 3598 * there are special characters. Single quotes themselves must be 3599 * escaped in either case. 3600 * 3601 private void appendAffix(StringBuffer buffer, String affix, boolean localized) { 3602 boolean needQuote; 3603 if (localized) { 3604 needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0 3605 || affix.indexOf(symbols.getGroupingSeparator()) >= 0 3606 || affix.indexOf(symbols.getDecimalSeparator()) >= 0 3607 || affix.indexOf(symbols.getPercentText()) >= 0 3608 || affix.indexOf(symbols.getPerMillText()) >= 0 3609 || affix.indexOf(symbols.getDigit()) >= 0 3610 || affix.indexOf(symbols.getPatternSeparator()) >= 0 3611 || affix.indexOf(symbols.getMinusSignText()) >= 0 3612 || affix.indexOf(CURRENCY_SIGN) >= 0; 3613 } else { 3614 needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0 3615 || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0 3616 || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0 3617 || affix.indexOf(PATTERN_PERCENT) >= 0 3618 || affix.indexOf(PATTERN_PER_MILLE) >= 0 3619 || affix.indexOf(PATTERN_DIGIT) >= 0 3620 || affix.indexOf(PATTERN_SEPARATOR) >= 0 3621 || affix.indexOf(PATTERN_MINUS) >= 0 3622 || affix.indexOf(CURRENCY_SIGN) >= 0; 3623 } 3624 if (needQuote) buffer.append('\''); 3625 if (affix.indexOf('\'') < 0) buffer.append(affix); 3626 else { 3627 for (int j=0; j<affix.length(); ++j) { 3628 char c = affix.charAt(j); 3629 buffer.append(c); 3630 if (c == '\'') buffer.append(c); 3631 } 3632 } 3633 if (needQuote) buffer.append('\''); 3634 } 3635 3636 /** 3637 * Does the real work of generating a pattern. * 3638 private String toPattern(boolean localized) { 3639 StringBuffer result = new StringBuffer(); 3640 for (int j = 1; j >= 0; --j) { 3641 if (j == 1) 3642 appendAffix(result, posPrefixPattern, positivePrefix, localized); 3643 else appendAffix(result, negPrefixPattern, negativePrefix, localized); 3644 int i; 3645 int digitCount = useExponentialNotation 3646 ? getMaximumIntegerDigits() 3647 : Math.max(groupingSize, getMinimumIntegerDigits())+1; 3648 for (i = digitCount; i > 0; --i) { 3649 if (i != digitCount && isGroupingUsed() && groupingSize != 0 && 3650 i % groupingSize == 0) { 3651 result.append(localized ? 3652 (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) : 3653 PATTERN_GROUPING_SEPARATOR); 3654 } 3655 result.append(i <= getMinimumIntegerDigits() 3656 ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) 3657 : (localized ? symbols.getDigit() : PATTERN_DIGIT)); 3658 } 3659 if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) 3660 result.append(localized ? 3661 (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) : 3662 PATTERN_DECIMAL_SEPARATOR); 3663 for (i = 0; i < getMaximumFractionDigits(); ++i) { 3664 if (i < getMinimumFractionDigits()) { 3665 result.append(localized ? symbols.getZeroDigit() : 3666 PATTERN_ZERO_DIGIT); 3667 } else { 3668 result.append(localized ? symbols.getDigit() : 3669 PATTERN_DIGIT); 3670 } 3671 } 3672 if (useExponentialNotation) 3673 { 3674 result.append(localized ? symbols.getExponentSeparator() : 3675 PATTERN_EXPONENT); 3676 for (i=0; i<minExponentDigits; ++i) 3677 result.append(localized ? symbols.getZeroDigit() : 3678 PATTERN_ZERO_DIGIT); 3679 } 3680 if (j == 1) { 3681 appendAffix(result, posSuffixPattern, positiveSuffix, localized); 3682 if ((negSuffixPattern == posSuffixPattern && // n == p == null 3683 negativeSuffix.equals(positiveSuffix)) 3684 || (negSuffixPattern != null && 3685 negSuffixPattern.equals(posSuffixPattern))) { 3686 if ((negPrefixPattern != null && posPrefixPattern != null && 3687 negPrefixPattern.equals("'-" + posPrefixPattern)) || 3688 (negPrefixPattern == posPrefixPattern && // n == p == null 3689 negativePrefix.equals(symbols.getMinusSignText() + positivePrefix))) 3690 break; 3691 } 3692 result.append(localized ? symbols.getPatternSeparator() : 3693 PATTERN_SEPARATOR); 3694 } else appendAffix(result, negSuffixPattern, negativeSuffix, localized); 3695 } 3696 return result.toString(); 3697 } 3698 */ 3699 // END Android-removed: Unused private helpers. 3700 3701 /** 3702 * Apply the given pattern to this Format object. A pattern is a 3703 * short-hand specification for the various formatting properties. 3704 * These properties can also be changed individually through the 3705 * various setter methods. 3706 * <p> 3707 * There is no limit to integer digits set 3708 * by this routine, since that is the typical end-user desire; 3709 * use setMaximumInteger if you want to set a real value. 3710 * For negative numbers, use a second pattern, separated by a semicolon 3711 * <P>Example {@code "#,#00.0#"} → 1,234.56 3712 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3713 * a maximum of 2 fraction digits. 3714 * <p>Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in 3715 * parentheses. 3716 * <p>In negative patterns, the minimum and maximum counts are ignored; 3717 * these are presumed to be set in the positive pattern. 3718 * 3719 * @param pattern a new pattern 3720 * @throws NullPointerException if {@code pattern} is null 3721 * @throws IllegalArgumentException if the given pattern is invalid. 3722 */ applyPattern(String pattern)3723 public void applyPattern(String pattern) { 3724 // Android-changed: use ICU. 3725 // applyPattern(pattern, false); 3726 icuDecimalFormat.applyPattern(pattern); 3727 updateFieldsFromIcu(); 3728 } 3729 3730 /** 3731 * Apply the given pattern to this Format object. The pattern 3732 * is assumed to be in a localized notation. A pattern is a 3733 * short-hand specification for the various formatting properties. 3734 * These properties can also be changed individually through the 3735 * various setter methods. 3736 * <p> 3737 * There is no limit to integer digits set 3738 * by this routine, since that is the typical end-user desire; 3739 * use setMaximumInteger if you want to set a real value. 3740 * For negative numbers, use a second pattern, separated by a semicolon 3741 * <P>Example {@code "#,#00.0#"} → 1,234.56 3742 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3743 * a maximum of 2 fraction digits. 3744 * <p>Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in 3745 * parentheses. 3746 * <p>In negative patterns, the minimum and maximum counts are ignored; 3747 * these are presumed to be set in the positive pattern. 3748 * 3749 * @param pattern a new pattern 3750 * @throws NullPointerException if {@code pattern} is null 3751 * @throws IllegalArgumentException if the given pattern is invalid. 3752 */ applyLocalizedPattern(String pattern)3753 public void applyLocalizedPattern(String pattern) { 3754 // Android-changed: use ICU. 3755 // applyPattern(pattern, true); 3756 icuDecimalFormat.applyLocalizedPattern(pattern); 3757 updateFieldsFromIcu(); 3758 } 3759 3760 // BEGIN Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly. 3761 /* 3762 /** 3763 * Does the real work of applying a pattern. 3764 * 3765 private void applyPattern(String pattern, boolean localized) { 3766 char zeroDigit = PATTERN_ZERO_DIGIT; 3767 char groupingSeparator = PATTERN_GROUPING_SEPARATOR; 3768 char decimalSeparator = PATTERN_DECIMAL_SEPARATOR; 3769 char percent = PATTERN_PERCENT; 3770 char perMill = PATTERN_PER_MILLE; 3771 char digit = PATTERN_DIGIT; 3772 char separator = PATTERN_SEPARATOR; 3773 String exponent = PATTERN_EXPONENT; 3774 char minus = PATTERN_MINUS; 3775 if (localized) { 3776 zeroDigit = symbols.getZeroDigit(); 3777 groupingSeparator = symbols.getGroupingSeparator(); 3778 decimalSeparator = symbols.getDecimalSeparator(); 3779 percent = symbols.getPercent(); 3780 perMill = symbols.getPerMill(); 3781 digit = symbols.getDigit(); 3782 separator = symbols.getPatternSeparator(); 3783 exponent = symbols.getExponentSeparator(); 3784 minus = symbols.getMinusSign(); 3785 } 3786 boolean gotNegative = false; 3787 decimalSeparatorAlwaysShown = false; 3788 isCurrencyFormat = false; 3789 useExponentialNotation = false; 3790 3791 int start = 0; 3792 for (int j = 1; j >= 0 && start < pattern.length(); --j) { 3793 boolean inQuote = false; 3794 StringBuffer prefix = new StringBuffer(); 3795 StringBuffer suffix = new StringBuffer(); 3796 int decimalPos = -1; 3797 int multiplier = 1; 3798 int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0; 3799 byte groupingCount = -1; 3800 3801 // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is 3802 // the section of the pattern with digits, decimal separator, 3803 // grouping characters. Phase 2 is the suffix. In phases 0 and 2, 3804 // percent, per mille, and currency symbols are recognized and 3805 // translated. The separation of the characters into phases is 3806 // strictly enforced; if phase 1 characters are to appear in the 3807 // suffix, for example, they must be quoted. 3808 int phase = 0; 3809 3810 // The affix is either the prefix or the suffix. 3811 StringBuffer affix = prefix; 3812 3813 for (int pos = start; pos < pattern.length(); ++pos) { 3814 char ch = pattern.charAt(pos); 3815 switch (phase) { 3816 case 0: 3817 case 2: 3818 // Process the prefix / suffix characters 3819 if (inQuote) { 3820 // A quote within quotes indicates either the closing 3821 // quote or two quotes, which is a quote literal. That 3822 // is, we have the second quote in 'do' or 'don''t'. 3823 if (ch == QUOTE) { 3824 if ((pos+1) < pattern.length() && 3825 pattern.charAt(pos+1) == QUOTE) { 3826 ++pos; 3827 affix.append("''"); // 'don''t' 3828 } else { 3829 inQuote = false; // 'do' 3830 } 3831 continue; 3832 } 3833 } else { 3834 // Process unquoted characters seen in prefix or suffix 3835 // phase. 3836 if (ch == digit || 3837 ch == zeroDigit || 3838 ch == groupingSeparator || 3839 ch == decimalSeparator) { 3840 phase = 1; 3841 --pos; // Reprocess this character 3842 continue; 3843 } else if (ch == CURRENCY_SIGN) { 3844 // Use lookahead to determine if the currency sign 3845 // is doubled or not. 3846 boolean doubled = (pos + 1) < pattern.length() && 3847 pattern.charAt(pos + 1) == CURRENCY_SIGN; 3848 if (doubled) { // Skip over the doubled character 3849 ++pos; 3850 } 3851 isCurrencyFormat = true; 3852 affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4"); 3853 continue; 3854 } else if (ch == QUOTE) { 3855 // A quote outside quotes indicates either the 3856 // opening quote or two quotes, which is a quote 3857 // literal. That is, we have the first quote in 'do' 3858 // or o''clock. 3859 if (ch == QUOTE) { 3860 if ((pos+1) < pattern.length() && 3861 pattern.charAt(pos+1) == QUOTE) { 3862 ++pos; 3863 affix.append("''"); // o''clock 3864 } else { 3865 inQuote = true; // 'do' 3866 } 3867 continue; 3868 } 3869 } else if (ch == separator) { 3870 // Don't allow separators before we see digit 3871 // characters of phase 1, and don't allow separators 3872 // in the second pattern (j == 0). 3873 if (phase == 0 || j == 0) { 3874 throw new IllegalArgumentException("Unquoted special character '" + 3875 ch + "' in pattern \"" + pattern + '"'); 3876 } 3877 start = pos + 1; 3878 pos = pattern.length(); 3879 continue; 3880 } 3881 3882 // Next handle characters which are appended directly. 3883 else if (ch == percent) { 3884 if (multiplier != 1) { 3885 throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + 3886 pattern + '"'); 3887 } 3888 multiplier = 100; 3889 affix.append("'%"); 3890 continue; 3891 } else if (ch == perMill) { 3892 if (multiplier != 1) { 3893 throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + 3894 pattern + '"'); 3895 } 3896 multiplier = 1000; 3897 affix.append("'\u2030"); 3898 continue; 3899 } else if (ch == minus) { 3900 affix.append("'-"); 3901 continue; 3902 } 3903 } 3904 // Note that if we are within quotes, or if this is an 3905 // unquoted, non-special character, then we usually fall 3906 // through to here. 3907 affix.append(ch); 3908 break; 3909 3910 case 1: 3911 // The negative subpattern (j = 0) serves only to specify the 3912 // negative prefix and suffix, so all the phase 1 characters 3913 // e.g. digits, zeroDigit, groupingSeparator, 3914 // decimalSeparator, exponent are ignored 3915 if (j == 0) { 3916 while (pos < pattern.length()) { 3917 char negPatternChar = pattern.charAt(pos); 3918 if (negPatternChar == digit 3919 || negPatternChar == zeroDigit 3920 || negPatternChar == groupingSeparator 3921 || negPatternChar == decimalSeparator) { 3922 ++pos; 3923 } else if (pattern.regionMatches(pos, exponent, 3924 0, exponent.length())) { 3925 pos = pos + exponent.length(); 3926 } else { 3927 // Not a phase 1 character, consider it as 3928 // suffix and parse it in phase 2 3929 --pos; //process it again in outer loop 3930 phase = 2; 3931 affix = suffix; 3932 break; 3933 } 3934 } 3935 continue; 3936 } 3937 3938 // Process the digits, decimal, and grouping characters. We 3939 // record five pieces of information. We expect the digits 3940 // to occur in the pattern ####0000.####, and we record the 3941 // number of left digits, zero (central) digits, and right 3942 // digits. The position of the last grouping character is 3943 // recorded (should be somewhere within the first two blocks 3944 // of characters), as is the position of the decimal point, 3945 // if any (should be in the zero digits). If there is no 3946 // decimal point, then there should be no right digits. 3947 if (ch == digit) { 3948 if (zeroDigitCount > 0) { 3949 ++digitRightCount; 3950 } else { 3951 ++digitLeftCount; 3952 } 3953 if (groupingCount >= 0 && decimalPos < 0) { 3954 ++groupingCount; 3955 } 3956 } else if (ch == zeroDigit) { 3957 if (digitRightCount > 0) { 3958 throw new IllegalArgumentException("Unexpected '0' in pattern \"" + 3959 pattern + '"'); 3960 } 3961 ++zeroDigitCount; 3962 if (groupingCount >= 0 && decimalPos < 0) { 3963 ++groupingCount; 3964 } 3965 } else if (ch == groupingSeparator) { 3966 groupingCount = 0; 3967 } else if (ch == decimalSeparator) { 3968 if (decimalPos >= 0) { 3969 throw new IllegalArgumentException("Multiple decimal separators in pattern \"" + 3970 pattern + '"'); 3971 } 3972 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; 3973 } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){ 3974 if (useExponentialNotation) { 3975 throw new IllegalArgumentException("Multiple exponential " + 3976 "symbols in pattern \"" + pattern + '"'); 3977 } 3978 useExponentialNotation = true; 3979 minExponentDigits = 0; 3980 3981 // Use lookahead to parse out the exponential part 3982 // of the pattern, then jump into phase 2. 3983 pos = pos+exponent.length(); 3984 while (pos < pattern.length() && 3985 pattern.charAt(pos) == zeroDigit) { 3986 ++minExponentDigits; 3987 ++pos; 3988 } 3989 3990 if ((digitLeftCount + zeroDigitCount) < 1 || 3991 minExponentDigits < 1) { 3992 throw new IllegalArgumentException("Malformed exponential " + 3993 "pattern \"" + pattern + '"'); 3994 } 3995 3996 // Transition to phase 2 3997 phase = 2; 3998 affix = suffix; 3999 --pos; 4000 continue; 4001 } else { 4002 phase = 2; 4003 affix = suffix; 4004 --pos; 4005 continue; 4006 } 4007 break; 4008 } 4009 } 4010 4011 // Handle patterns with no '0' pattern character. These patterns 4012 // are legal, but must be interpreted. "##.###" -> "#0.###". 4013 // ".###" -> ".0##". 4014 /* We allow patterns of the form "####" to produce a zeroDigitCount 4015 * of zero (got that?); although this seems like it might make it 4016 * possible for format() to produce empty strings, format() checks 4017 * for this condition and outputs a zero digit in this situation. 4018 * Having a zeroDigitCount of zero yields a minimum integer digits 4019 * of zero, which allows proper round-trip patterns. That is, we 4020 * don't want "#" to become "#0" when toPattern() is called (even 4021 * though that's what it really is, semantically). 4022 * 4023 if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { 4024 // Handle "###.###" and "###." and ".###" 4025 int n = decimalPos; 4026 if (n == 0) { // Handle ".###" 4027 ++n; 4028 } 4029 digitRightCount = digitLeftCount - n; 4030 digitLeftCount = n - 1; 4031 zeroDigitCount = 1; 4032 } 4033 4034 // Do syntax checking on the digits. 4035 if ((decimalPos < 0 && digitRightCount > 0) || 4036 (decimalPos >= 0 && (decimalPos < digitLeftCount || 4037 decimalPos > (digitLeftCount + zeroDigitCount))) || 4038 groupingCount == 0 || inQuote) { 4039 throw new IllegalArgumentException("Malformed pattern \"" + 4040 pattern + '"'); 4041 } 4042 4043 if (j == 1) { 4044 posPrefixPattern = prefix.toString(); 4045 posSuffixPattern = suffix.toString(); 4046 negPrefixPattern = posPrefixPattern; // assume these for now 4047 negSuffixPattern = posSuffixPattern; 4048 int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; 4049 /* The effectiveDecimalPos is the position the decimal is at or 4050 * would be at if there is no decimal. Note that if decimalPos<0, 4051 * then digitTotalCount == digitLeftCount + zeroDigitCount. 4052 * 4053 int effectiveDecimalPos = decimalPos >= 0 ? 4054 decimalPos : digitTotalCount; 4055 setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount); 4056 setMaximumIntegerDigits(useExponentialNotation ? 4057 digitLeftCount + getMinimumIntegerDigits() : 4058 MAXIMUM_INTEGER_DIGITS); 4059 setMaximumFractionDigits(decimalPos >= 0 ? 4060 (digitTotalCount - decimalPos) : 0); 4061 setMinimumFractionDigits(decimalPos >= 0 ? 4062 (digitLeftCount + zeroDigitCount - decimalPos) : 0); 4063 setGroupingUsed(groupingCount > 0); 4064 this.groupingSize = (groupingCount > 0) ? groupingCount : 0; 4065 this.multiplier = multiplier; 4066 setDecimalSeparatorAlwaysShown(decimalPos == 0 || 4067 decimalPos == digitTotalCount); 4068 } else { 4069 negPrefixPattern = prefix.toString(); 4070 negSuffixPattern = suffix.toString(); 4071 gotNegative = true; 4072 } 4073 } 4074 4075 if (pattern.isEmpty()) { 4076 posPrefixPattern = posSuffixPattern = ""; 4077 setMinimumIntegerDigits(0); 4078 setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS); 4079 setMinimumFractionDigits(0); 4080 setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS); 4081 } 4082 4083 // If there was no negative pattern, or if the negative pattern is 4084 // identical to the positive pattern, then prepend the minus sign to 4085 // the positive pattern to form the negative pattern. 4086 if (!gotNegative || 4087 (negPrefixPattern.equals(posPrefixPattern) 4088 && negSuffixPattern.equals(posSuffixPattern))) { 4089 negSuffixPattern = posSuffixPattern; 4090 negPrefixPattern = "'-" + posPrefixPattern; 4091 } 4092 4093 expandAffixes(); 4094 } 4095 */ 4096 // END Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly. 4097 4098 /** 4099 * Sets the maximum number of digits allowed in the integer portion of a 4100 * number. 4101 * For formatting numbers other than {@code BigInteger} and 4102 * {@code BigDecimal} objects, the lower of {@code newValue} and 4103 * 309 is used. Negative input values are replaced with 0. 4104 * @see NumberFormat#setMaximumIntegerDigits 4105 */ 4106 @Override setMaximumIntegerDigits(int newValue)4107 public void setMaximumIntegerDigits(int newValue) { 4108 maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 4109 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 4110 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 4111 if (minimumIntegerDigits > maximumIntegerDigits) { 4112 minimumIntegerDigits = maximumIntegerDigits; 4113 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 4114 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 4115 } 4116 // Android-added: use ICU. 4117 icuDecimalFormat.setMaximumIntegerDigits(getMaximumIntegerDigits()); 4118 // Android-removed: fast path related code. 4119 // fastPathCheckNeeded = true; 4120 } 4121 4122 /** 4123 * Sets the minimum number of digits allowed in the integer portion of a 4124 * number. 4125 * For formatting numbers other than {@code BigInteger} and 4126 * {@code BigDecimal} objects, the lower of {@code newValue} and 4127 * 309 is used. Negative input values are replaced with 0. 4128 * @see NumberFormat#setMinimumIntegerDigits 4129 */ 4130 @Override setMinimumIntegerDigits(int newValue)4131 public void setMinimumIntegerDigits(int newValue) { 4132 minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 4133 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 4134 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 4135 if (minimumIntegerDigits > maximumIntegerDigits) { 4136 maximumIntegerDigits = minimumIntegerDigits; 4137 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 4138 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 4139 } 4140 // Android-added: use ICU. 4141 icuDecimalFormat.setMinimumIntegerDigits(getMinimumIntegerDigits()); 4142 // Android-removed: fast path related code. 4143 // fastPathCheckNeeded = true; 4144 } 4145 4146 /** 4147 * Sets the maximum number of digits allowed in the fraction portion of a 4148 * number. 4149 * For formatting numbers other than {@code BigInteger} and 4150 * {@code BigDecimal} objects, the lower of {@code newValue} and 4151 * 340 is used. Negative input values are replaced with 0. 4152 * @see NumberFormat#setMaximumFractionDigits 4153 */ 4154 @Override setMaximumFractionDigits(int newValue)4155 public void setMaximumFractionDigits(int newValue) { 4156 maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 4157 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 4158 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 4159 if (minimumFractionDigits > maximumFractionDigits) { 4160 minimumFractionDigits = maximumFractionDigits; 4161 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 4162 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 4163 } 4164 // Android-added: use ICU. 4165 icuDecimalFormat.setMaximumFractionDigits(getMaximumFractionDigits()); 4166 // Android-removed: fast path related code. 4167 // fastPathCheckNeeded = true; 4168 } 4169 4170 /** 4171 * Sets the minimum number of digits allowed in the fraction portion of a 4172 * number. 4173 * For formatting numbers other than {@code BigInteger} and 4174 * {@code BigDecimal} objects, the lower of {@code newValue} and 4175 * 340 is used. Negative input values are replaced with 0. 4176 * @see NumberFormat#setMinimumFractionDigits 4177 */ 4178 @Override setMinimumFractionDigits(int newValue)4179 public void setMinimumFractionDigits(int newValue) { 4180 minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 4181 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 4182 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 4183 if (minimumFractionDigits > maximumFractionDigits) { 4184 maximumFractionDigits = minimumFractionDigits; 4185 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 4186 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 4187 } 4188 // Android-added: use ICU. 4189 icuDecimalFormat.setMinimumFractionDigits(getMinimumFractionDigits()); 4190 // Android-removed: fast path related code. 4191 // fastPathCheckNeeded = true; 4192 } 4193 4194 /** 4195 * Gets the maximum number of digits allowed in the integer portion of a 4196 * number. 4197 * For formatting numbers other than {@code BigInteger} and 4198 * {@code BigDecimal} objects, the lower of the return value and 4199 * 309 is used. 4200 * @see #setMaximumIntegerDigits 4201 */ 4202 @Override getMaximumIntegerDigits()4203 public int getMaximumIntegerDigits() { 4204 return maximumIntegerDigits; 4205 } 4206 4207 /** 4208 * Gets the minimum number of digits allowed in the integer portion of a 4209 * number. 4210 * For formatting numbers other than {@code BigInteger} and 4211 * {@code BigDecimal} objects, the lower of the return value and 4212 * 309 is used. 4213 * @see #setMinimumIntegerDigits 4214 */ 4215 @Override getMinimumIntegerDigits()4216 public int getMinimumIntegerDigits() { 4217 return minimumIntegerDigits; 4218 } 4219 4220 /** 4221 * Gets the maximum number of digits allowed in the fraction portion of a 4222 * number. 4223 * For formatting numbers other than {@code BigInteger} and 4224 * {@code BigDecimal} objects, the lower of the return value and 4225 * 340 is used. 4226 * @see #setMaximumFractionDigits 4227 */ 4228 @Override getMaximumFractionDigits()4229 public int getMaximumFractionDigits() { 4230 return maximumFractionDigits; 4231 } 4232 4233 /** 4234 * Gets the minimum number of digits allowed in the fraction portion of a 4235 * number. 4236 * For formatting numbers other than {@code BigInteger} and 4237 * {@code BigDecimal} objects, the lower of the return value and 4238 * 340 is used. 4239 * @see #setMinimumFractionDigits 4240 */ 4241 @Override getMinimumFractionDigits()4242 public int getMinimumFractionDigits() { 4243 return minimumFractionDigits; 4244 } 4245 4246 /** 4247 * Gets the currency used by this decimal format when formatting 4248 * currency values. 4249 * The currency is obtained by calling 4250 * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency} 4251 * on this number format's symbols. 4252 * 4253 * @return the currency used by this decimal format, or {@code null} 4254 * @since 1.4 4255 */ 4256 @Override getCurrency()4257 public Currency getCurrency() { 4258 return symbols.getCurrency(); 4259 } 4260 4261 /** 4262 * Sets the currency used by this number format when formatting 4263 * currency values. This does not update the minimum or maximum 4264 * number of fraction digits used by the number format. 4265 * The currency is set by calling 4266 * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency} 4267 * on this number format's symbols. 4268 * 4269 * @param currency the new currency to be used by this decimal format 4270 * @throws NullPointerException if {@code currency} is null 4271 * @since 1.4 4272 */ 4273 @Override setCurrency(Currency currency)4274 public void setCurrency(Currency currency) { 4275 // BEGIN Android-changed: use ICU. 4276 // Set the international currency symbol, and currency symbol on the DecimalFormatSymbols 4277 // object and tell ICU to use that. 4278 /* 4279 if (currency != symbols.getCurrency()) { 4280 symbols.setCurrency(currency); 4281 if (isCurrencyFormat) { 4282 expandAffixes(); 4283 } 4284 } 4285 */ 4286 if (currency != symbols.getCurrency() 4287 || !currency.getSymbol().equals(symbols.getCurrencySymbol())) { 4288 symbols.setCurrency(currency); 4289 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 4290 // Giving the icuDecimalFormat a new currency will cause the fractional digits to be 4291 // updated. This class is specified to not touch the fraction digits, so we re-set them. 4292 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 4293 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 4294 } 4295 // END Android-changed: use ICU. 4296 // Android-removed: fast path related code. 4297 // fastPathCheckNeeded = true; 4298 } 4299 4300 /** 4301 * Gets the {@link java.math.RoundingMode} used in this DecimalFormat. 4302 * 4303 * @return The {@code RoundingMode} used for this DecimalFormat. 4304 * @see #setRoundingMode(RoundingMode) 4305 * @since 1.6 4306 */ 4307 @Override getRoundingMode()4308 public RoundingMode getRoundingMode() { 4309 return roundingMode; 4310 } 4311 4312 // BEGIN Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums. convertRoundingMode(RoundingMode rm)4313 private static int convertRoundingMode(RoundingMode rm) { 4314 switch (rm) { 4315 case UP: 4316 return MathContext.ROUND_UP; 4317 case DOWN: 4318 return MathContext.ROUND_DOWN; 4319 case CEILING: 4320 return MathContext.ROUND_CEILING; 4321 case FLOOR: 4322 return MathContext.ROUND_FLOOR; 4323 case HALF_UP: 4324 return MathContext.ROUND_HALF_UP; 4325 case HALF_DOWN: 4326 return MathContext.ROUND_HALF_DOWN; 4327 case HALF_EVEN: 4328 return MathContext.ROUND_HALF_EVEN; 4329 case UNNECESSARY: 4330 return MathContext.ROUND_UNNECESSARY; 4331 } 4332 throw new IllegalArgumentException("Invalid rounding mode specified"); 4333 } 4334 // END Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums. 4335 4336 /** 4337 * Sets the {@link java.math.RoundingMode} used in this DecimalFormat. 4338 * 4339 * @param roundingMode The {@code RoundingMode} to be used 4340 * @see #getRoundingMode() 4341 * @throws NullPointerException if {@code roundingMode} is null. 4342 * @since 1.6 4343 */ 4344 @Override setRoundingMode(RoundingMode roundingMode)4345 public void setRoundingMode(RoundingMode roundingMode) { 4346 if (roundingMode == null) { 4347 throw new NullPointerException(); 4348 } 4349 4350 this.roundingMode = roundingMode; 4351 // Android-changed: use ICU. 4352 // digitList.setRoundingMode(roundingMode); 4353 icuDecimalFormat.setRoundingMode(convertRoundingMode(roundingMode)); 4354 // Android-removed: fast path related code. 4355 // fastPathCheckNeeded = true; 4356 } 4357 4358 // BEGIN Android-added: Upstream code from OpenJDK 7u40 release. 4359 // This method was removed in OpenJDK 8 in favor of doing equivalent work in the provider. Since 4360 // Android removed support for providers for NumberFormat we keep this method around as an 4361 // "Android addition". 4362 /** 4363 * Adjusts the minimum and maximum fraction digits to values that 4364 * are reasonable for the currency's default fraction digits. 4365 */ adjustForCurrencyDefaultFractionDigits()4366 void adjustForCurrencyDefaultFractionDigits() { 4367 Currency currency = symbols.getCurrency(); 4368 if (currency == null) { 4369 try { 4370 currency = Currency.getInstance(symbols.getInternationalCurrencySymbol()); 4371 } catch (IllegalArgumentException e) { 4372 } 4373 } 4374 if (currency != null) { 4375 int digits = currency.getDefaultFractionDigits(); 4376 if (digits != -1) { 4377 int oldMinDigits = getMinimumFractionDigits(); 4378 // Common patterns are "#.##", "#.00", "#". 4379 // Try to adjust all of them in a reasonable way. 4380 if (oldMinDigits == getMaximumFractionDigits()) { 4381 setMinimumFractionDigits(digits); 4382 setMaximumFractionDigits(digits); 4383 } else { 4384 setMinimumFractionDigits(Math.min(digits, oldMinDigits)); 4385 setMaximumFractionDigits(digits); 4386 } 4387 } 4388 } 4389 } 4390 // END Android-added: Upstream code from OpenJDK 7u40 release. 4391 4392 // BEGIN Android-added: Custom serialization code for compatibility with RI serialization. 4393 // the fields list to be serialized 4394 private static final ObjectStreamField[] serialPersistentFields = { 4395 new ObjectStreamField("positivePrefix", String.class), 4396 new ObjectStreamField("positiveSuffix", String.class), 4397 new ObjectStreamField("negativePrefix", String.class), 4398 new ObjectStreamField("negativeSuffix", String.class), 4399 new ObjectStreamField("posPrefixPattern", String.class), 4400 new ObjectStreamField("posSuffixPattern", String.class), 4401 new ObjectStreamField("negPrefixPattern", String.class), 4402 new ObjectStreamField("negSuffixPattern", String.class), 4403 new ObjectStreamField("multiplier", int.class), 4404 new ObjectStreamField("groupingSize", byte.class), 4405 new ObjectStreamField("groupingUsed", boolean.class), 4406 new ObjectStreamField("decimalSeparatorAlwaysShown", boolean.class), 4407 new ObjectStreamField("parseBigDecimal", boolean.class), 4408 new ObjectStreamField("roundingMode", RoundingMode.class), 4409 new ObjectStreamField("symbols", DecimalFormatSymbols.class), 4410 new ObjectStreamField("useExponentialNotation", boolean.class), 4411 new ObjectStreamField("minExponentDigits", byte.class), 4412 new ObjectStreamField("maximumIntegerDigits", int.class), 4413 new ObjectStreamField("minimumIntegerDigits", int.class), 4414 new ObjectStreamField("maximumFractionDigits", int.class), 4415 new ObjectStreamField("minimumFractionDigits", int.class), 4416 new ObjectStreamField("serialVersionOnStream", int.class), 4417 }; 4418 writeObject(ObjectOutputStream stream)4419 private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException { 4420 ObjectOutputStream.PutField fields = stream.putFields(); 4421 fields.put("positivePrefix", icuDecimalFormat.getPositivePrefix()); 4422 fields.put("positiveSuffix", icuDecimalFormat.getPositiveSuffix()); 4423 fields.put("negativePrefix", icuDecimalFormat.getNegativePrefix()); 4424 fields.put("negativeSuffix", icuDecimalFormat.getNegativeSuffix()); 4425 fields.put("posPrefixPattern", (String) null); 4426 fields.put("posSuffixPattern", (String) null); 4427 fields.put("negPrefixPattern", (String) null); 4428 fields.put("negSuffixPattern", (String) null); 4429 fields.put("multiplier", icuDecimalFormat.getMultiplier()); 4430 fields.put("groupingSize", (byte) icuDecimalFormat.getGroupingSize()); 4431 fields.put("groupingUsed", icuDecimalFormat.isGroupingUsed()); 4432 fields.put("decimalSeparatorAlwaysShown", icuDecimalFormat.isDecimalSeparatorAlwaysShown()); 4433 fields.put("parseBigDecimal", icuDecimalFormat.isParseBigDecimal()); 4434 fields.put("roundingMode", roundingMode); 4435 fields.put("symbols", symbols); 4436 fields.put("useExponentialNotation", false); 4437 fields.put("minExponentDigits", (byte) 0); 4438 fields.put("maximumIntegerDigits", icuDecimalFormat.getMaximumIntegerDigits()); 4439 fields.put("minimumIntegerDigits", icuDecimalFormat.getMinimumIntegerDigits()); 4440 fields.put("maximumFractionDigits", icuDecimalFormat.getMaximumFractionDigits()); 4441 fields.put("minimumFractionDigits", icuDecimalFormat.getMinimumFractionDigits()); 4442 fields.put("serialVersionOnStream", currentSerialVersion); 4443 stream.writeFields(); 4444 } 4445 // END Android-added: Custom serialization code for compatibility with RI serialization. 4446 4447 /** 4448 * Reads the default serializable fields from the stream and performs 4449 * validations and adjustments for older serialized versions. The 4450 * validations and adjustments are: 4451 * <ol> 4452 * <li> 4453 * Verify that the superclass's digit count fields correctly reflect 4454 * the limits imposed on formatting numbers other than 4455 * {@code BigInteger} and {@code BigDecimal} objects. These 4456 * limits are stored in the superclass for serialization compatibility 4457 * with older versions, while the limits for {@code BigInteger} and 4458 * {@code BigDecimal} objects are kept in this class. 4459 * If, in the superclass, the minimum or maximum integer digit count is 4460 * larger than {@code DOUBLE_INTEGER_DIGITS} or if the minimum or 4461 * maximum fraction digit count is larger than 4462 * {@code DOUBLE_FRACTION_DIGITS}, then the stream data is invalid 4463 * and this method throws an {@code InvalidObjectException}. 4464 * <li> 4465 * If {@code serialVersionOnStream} is less than 4, initialize 4466 * {@code roundingMode} to {@link java.math.RoundingMode#HALF_EVEN 4467 * RoundingMode.HALF_EVEN}. This field is new with version 4. 4468 * <li> 4469 * If {@code serialVersionOnStream} is less than 3, then call 4470 * the setters for the minimum and maximum integer and fraction digits with 4471 * the values of the corresponding superclass getters to initialize the 4472 * fields in this class. The fields in this class are new with version 3. 4473 * <li> 4474 * If {@code serialVersionOnStream} is less than 1, indicating that 4475 * the stream was written by JDK 1.1, initialize 4476 * {@code useExponentialNotation} 4477 * to false, since it was not present in JDK 1.1. 4478 * <li> 4479 * Set {@code serialVersionOnStream} to the maximum allowed value so 4480 * that default serialization will work properly if this object is streamed 4481 * out again. 4482 * </ol> 4483 * 4484 * <p>Stream versions older than 2 will not have the affix pattern variables 4485 * {@code posPrefixPattern} etc. As a result, they will be initialized 4486 * to {@code null}, which means the affix strings will be taken as 4487 * literal values. This is exactly what we want, since that corresponds to 4488 * the pre-version-2 behavior. 4489 */ 4490 @java.io.Serial readObject(ObjectInputStream stream)4491 private void readObject(ObjectInputStream stream) 4492 throws IOException, ClassNotFoundException { 4493 // BEGIN Android-changed: Custom serialization code for compatibility with RI serialization. 4494 /* 4495 stream.defaultReadObject(); 4496 digitList = new DigitList(); 4497 4498 // We force complete fast-path reinitialization when the instance is 4499 // deserialized. See clone() comment on fastPathCheckNeeded. 4500 fastPathCheckNeeded = true; 4501 isFastPath = false; 4502 fastPathData = null; 4503 4504 if (serialVersionOnStream < 4) { 4505 setRoundingMode(RoundingMode.HALF_EVEN); 4506 } else { 4507 setRoundingMode(getRoundingMode()); 4508 } 4509 4510 // We only need to check the maximum counts because NumberFormat 4511 // .readObject has already ensured that the maximum is greater than the 4512 // minimum count. 4513 if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS || 4514 super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { 4515 throw new InvalidObjectException("Digit count out of range"); 4516 } 4517 if (serialVersionOnStream < 3) { 4518 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 4519 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 4520 setMaximumFractionDigits(super.getMaximumFractionDigits()); 4521 setMinimumFractionDigits(super.getMinimumFractionDigits()); 4522 } 4523 if (serialVersionOnStream < 1) { 4524 // Didn't have exponential fields 4525 useExponentialNotation = false; 4526 } 4527 4528 // Restore the invariant value if groupingSize is invalid. 4529 if (groupingSize < 0) { 4530 groupingSize = 3; 4531 } 4532 4533 serialVersionOnStream = currentSerialVersion; 4534 */ 4535 ObjectInputStream.GetField fields = stream.readFields(); 4536 this.symbols = (DecimalFormatSymbols) fields.get("symbols", null); 4537 4538 initPattern("#"); 4539 4540 // Calling a setter method on an ICU DecimalFormat object will change the object's internal 4541 // state, even if the value set is the same as the default value (ICU Ticket #13266). 4542 // 4543 // In an attempt to create objects that are equals() to the ones that were serialized, it's 4544 // therefore assumed here that any values that are the same as the default values were the 4545 // default values (ie. no setter was called to explicitly set that value). 4546 4547 String positivePrefix = (String) fields.get("positivePrefix", ""); 4548 if (!Objects.equals(positivePrefix, icuDecimalFormat.getPositivePrefix())) { 4549 icuDecimalFormat.setPositivePrefix(positivePrefix); 4550 } 4551 4552 String positiveSuffix = (String) fields.get("positiveSuffix", ""); 4553 if (!Objects.equals(positiveSuffix, icuDecimalFormat.getPositiveSuffix())) { 4554 icuDecimalFormat.setPositiveSuffix(positiveSuffix); 4555 } 4556 4557 String negativePrefix = (String) fields.get("negativePrefix", "-"); 4558 if (!Objects.equals(negativePrefix, icuDecimalFormat.getNegativePrefix())) { 4559 icuDecimalFormat.setNegativePrefix(negativePrefix); 4560 } 4561 4562 String negativeSuffix = (String) fields.get("negativeSuffix", ""); 4563 if (!Objects.equals(negativeSuffix, icuDecimalFormat.getNegativeSuffix())) { 4564 icuDecimalFormat.setNegativeSuffix(negativeSuffix); 4565 } 4566 4567 int multiplier = fields.get("multiplier", 1); 4568 if (multiplier != icuDecimalFormat.getMultiplier()) { 4569 icuDecimalFormat.setMultiplier(multiplier); 4570 } 4571 4572 boolean groupingUsed = fields.get("groupingUsed", true); 4573 if (groupingUsed != icuDecimalFormat.isGroupingUsed()) { 4574 icuDecimalFormat.setGroupingUsed(groupingUsed); 4575 } 4576 4577 int groupingSize = fields.get("groupingSize", (byte) 3); 4578 if (groupingSize != icuDecimalFormat.getGroupingSize()) { 4579 icuDecimalFormat.setGroupingSize(groupingSize); 4580 } 4581 4582 boolean decimalSeparatorAlwaysShown = fields.get("decimalSeparatorAlwaysShown", false); 4583 if (decimalSeparatorAlwaysShown != icuDecimalFormat.isDecimalSeparatorAlwaysShown()) { 4584 icuDecimalFormat.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown); 4585 } 4586 4587 RoundingMode roundingMode = 4588 (RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN); 4589 if (convertRoundingMode(roundingMode) != icuDecimalFormat.getRoundingMode()) { 4590 setRoundingMode(roundingMode); 4591 } 4592 4593 int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309); 4594 if (maximumIntegerDigits != icuDecimalFormat.getMaximumIntegerDigits()) { 4595 icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits); 4596 } 4597 4598 int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309); 4599 if (minimumIntegerDigits != icuDecimalFormat.getMinimumIntegerDigits()) { 4600 icuDecimalFormat.setMinimumIntegerDigits(minimumIntegerDigits); 4601 } 4602 4603 int maximumFractionDigits = fields.get("maximumFractionDigits", 340); 4604 if (maximumFractionDigits != icuDecimalFormat.getMaximumFractionDigits()) { 4605 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 4606 } 4607 4608 int minimumFractionDigits = fields.get("minimumFractionDigits", 340); 4609 if (minimumFractionDigits != icuDecimalFormat.getMinimumFractionDigits()) { 4610 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 4611 } 4612 4613 boolean parseBigDecimal = fields.get("parseBigDecimal", true); 4614 if (parseBigDecimal != icuDecimalFormat.isParseBigDecimal()) { 4615 icuDecimalFormat.setParseBigDecimal(parseBigDecimal); 4616 } 4617 4618 updateFieldsFromIcu(); 4619 4620 if (fields.get("serialVersionOnStream", 0) < 3) { 4621 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 4622 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 4623 setMaximumFractionDigits(super.getMaximumFractionDigits()); 4624 setMinimumFractionDigits(super.getMinimumFractionDigits()); 4625 } 4626 // END Android-changed: Custom serialization code for compatibility with RI serialization. 4627 } 4628 4629 //---------------------------------------------------------------------- 4630 // INSTANCE VARIABLES 4631 //---------------------------------------------------------------------- 4632 4633 // BEGIN Android-removed: various fields now stored in icuDecimalFormat. 4634 /* 4635 private transient DigitList digitList = new DigitList(); 4636 4637 /** 4638 * The symbol used as a prefix when formatting positive numbers, e.g. "+". 4639 * 4640 * @serial 4641 * @see #getPositivePrefix 4642 * 4643 private String positivePrefix = ""; 4644 4645 /** 4646 * The symbol used as a suffix when formatting positive numbers. 4647 * This is often an empty string. 4648 * 4649 * @serial 4650 * @see #getPositiveSuffix 4651 * 4652 private String positiveSuffix = ""; 4653 4654 /** 4655 * The symbol used as a prefix when formatting negative numbers, e.g. "-". 4656 * 4657 * @serial 4658 * @see #getNegativePrefix 4659 * 4660 private String negativePrefix = "-"; 4661 4662 /** 4663 * The symbol used as a suffix when formatting negative numbers. 4664 * This is often an empty string. 4665 * 4666 * @serial 4667 * @see #getNegativeSuffix 4668 * 4669 private String negativeSuffix = ""; 4670 4671 /** 4672 * The prefix pattern for non-negative numbers. This variable corresponds 4673 * to {@code positivePrefix}. 4674 * 4675 * <p>This pattern is expanded by the method {@code expandAffix()} to 4676 * {@code positivePrefix} to update the latter to reflect changes in 4677 * {@code symbols}. If this variable is {@code null} then 4678 * {@code positivePrefix} is taken as a literal value that does not 4679 * change when {@code symbols} changes. This variable is always 4680 * {@code null} for {@code DecimalFormat} objects older than 4681 * stream version 2 restored from stream. 4682 * 4683 * @serial 4684 * @since 1.3 4685 * 4686 private String posPrefixPattern; 4687 4688 /** 4689 * The suffix pattern for non-negative numbers. This variable corresponds 4690 * to {@code positiveSuffix}. This variable is analogous to 4691 * {@code posPrefixPattern}; see that variable for further 4692 * documentation. 4693 * 4694 * @serial 4695 * @since 1.3 4696 * 4697 private String posSuffixPattern; 4698 4699 /** 4700 * The prefix pattern for negative numbers. This variable corresponds 4701 * to {@code negativePrefix}. This variable is analogous to 4702 * {@code posPrefixPattern}; see that variable for further 4703 * documentation. 4704 * 4705 * @serial 4706 * @since 1.3 4707 * 4708 private String negPrefixPattern; 4709 4710 /** 4711 * The suffix pattern for negative numbers. This variable corresponds 4712 * to {@code negativeSuffix}. This variable is analogous to 4713 * {@code posPrefixPattern}; see that variable for further 4714 * documentation. 4715 * 4716 * @serial 4717 * @since 1.3 4718 * 4719 private String negSuffixPattern; 4720 4721 /** 4722 * The multiplier for use in percent, per mille, etc. 4723 * 4724 * @serial 4725 * @see #getMultiplier 4726 * 4727 private int multiplier = 1; 4728 4729 /** 4730 * The number of digits between grouping separators in the integer 4731 * portion of a number. Must be non-negative and less than or equal to 4732 * {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE} if 4733 * {@code NumberFormat.groupingUsed} is true. 4734 * 4735 * @serial 4736 * @see #getGroupingSize 4737 * @see java.text.NumberFormat#isGroupingUsed 4738 * 4739 private byte groupingSize = 3; // invariant, 0 - 127, if groupingUsed 4740 4741 /** 4742 * If true, forces the decimal separator to always appear in a formatted 4743 * number, even if the fractional part of the number is zero. 4744 * 4745 * @serial 4746 * @see #isDecimalSeparatorAlwaysShown 4747 * 4748 private boolean decimalSeparatorAlwaysShown = false; 4749 4750 /** 4751 * If true, parse returns BigDecimal wherever possible. 4752 * 4753 * @serial 4754 * @see #isParseBigDecimal 4755 * @since 1.5 4756 * 4757 private boolean parseBigDecimal = false; 4758 4759 4760 /** 4761 * True if this object represents a currency format. This determines 4762 * whether the monetary decimal/grouping separators are used instead of the normal ones. 4763 * 4764 private transient boolean isCurrencyFormat = false; 4765 */ 4766 // END Android-removed: various fields now stored in icuDecimalFormat. 4767 4768 /** 4769 * The {@code DecimalFormatSymbols} object used by this format. 4770 * It contains the symbols used to format numbers, e.g. the grouping separator, 4771 * decimal separator, and so on. 4772 * 4773 * @serial 4774 * @see #setDecimalFormatSymbols 4775 * @see java.text.DecimalFormatSymbols 4776 */ 4777 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); 4778 4779 // BEGIN Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits. 4780 /* 4781 /** 4782 * True to force the use of exponential (i.e. scientific) notation when formatting 4783 * numbers. 4784 * 4785 * @serial 4786 * @since 1.2 4787 * 4788 private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2 4789 4790 /** 4791 * FieldPositions describing the positive prefix String. This is 4792 * lazily created. Use {@code getPositivePrefixFieldPositions} 4793 * when needed. 4794 * 4795 private transient FieldPosition[] positivePrefixFieldPositions; 4796 4797 /** 4798 * FieldPositions describing the positive suffix String. This is 4799 * lazily created. Use {@code getPositiveSuffixFieldPositions} 4800 * when needed. 4801 * 4802 private transient FieldPosition[] positiveSuffixFieldPositions; 4803 4804 /** 4805 * FieldPositions describing the negative prefix String. This is 4806 * lazily created. Use {@code getNegativePrefixFieldPositions} 4807 * when needed. 4808 * 4809 private transient FieldPosition[] negativePrefixFieldPositions; 4810 4811 /** 4812 * FieldPositions describing the negative suffix String. This is 4813 * lazily created. Use {@code getNegativeSuffixFieldPositions} 4814 * when needed. 4815 * 4816 private transient FieldPosition[] negativeSuffixFieldPositions; 4817 4818 /** 4819 * The minimum number of digits used to display the exponent when a number is 4820 * formatted in exponential notation. This field is ignored if 4821 * {@code useExponentialNotation} is not true. 4822 * 4823 * @serial 4824 * @since 1.2 4825 * 4826 private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2 4827 4828 4829 */ 4830 // END Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits. 4831 4832 /** 4833 * The maximum number of digits allowed in the integer portion of a 4834 * {@code BigInteger} or {@code BigDecimal} number. 4835 * {@code maximumIntegerDigits} must be greater than or equal to 4836 * {@code minimumIntegerDigits}. 4837 * 4838 * @serial 4839 * @see #getMaximumIntegerDigits 4840 * @since 1.5 4841 */ 4842 // Android-changed: removed initialization. 4843 private int maximumIntegerDigits /* = super.getMaximumIntegerDigits() */; 4844 4845 /** 4846 * The minimum number of digits allowed in the integer portion of a 4847 * {@code BigInteger} or {@code BigDecimal} number. 4848 * {@code minimumIntegerDigits} must be less than or equal to 4849 * {@code maximumIntegerDigits}. 4850 * 4851 * @serial 4852 * @see #getMinimumIntegerDigits 4853 * @since 1.5 4854 */ 4855 // Android-changed: removed initialization. 4856 private int minimumIntegerDigits /* = super.getMinimumIntegerDigits() */; 4857 4858 /** 4859 * The maximum number of digits allowed in the fractional portion of a 4860 * {@code BigInteger} or {@code BigDecimal} number. 4861 * {@code maximumFractionDigits} must be greater than or equal to 4862 * {@code minimumFractionDigits}. 4863 * 4864 * @serial 4865 * @see #getMaximumFractionDigits 4866 * @since 1.5 4867 */ 4868 // Android-changed: removed initialization. 4869 private int maximumFractionDigits /* = super.getMaximumFractionDigits() */; 4870 4871 /** 4872 * The minimum number of digits allowed in the fractional portion of a 4873 * {@code BigInteger} or {@code BigDecimal} number. 4874 * {@code minimumFractionDigits} must be less than or equal to 4875 * {@code maximumFractionDigits}. 4876 * 4877 * @serial 4878 * @see #getMinimumFractionDigits 4879 * @since 1.5 4880 */ 4881 // Android-changed: removed initialization. 4882 private int minimumFractionDigits /* = super.getMinimumFractionDigits() */; 4883 4884 /** 4885 * The {@link java.math.RoundingMode} used in this DecimalFormat. 4886 * 4887 * @serial 4888 * @since 1.6 4889 */ 4890 private RoundingMode roundingMode = RoundingMode.HALF_EVEN; 4891 4892 // BEGIN Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData. 4893 /* 4894 // ------ DecimalFormat fields for fast-path for double algorithm ------ 4895 4896 /** 4897 * Helper inner utility class for storing the data used in the fast-path 4898 * algorithm. Almost all fields related to fast-path are encapsulated in 4899 * this class. 4900 * 4901 * Any {@code DecimalFormat} instance has a {@code fastPathData} 4902 * reference field that is null unless both the properties of the instance 4903 * are such that the instance is in the "fast-path" state, and a format call 4904 * has been done at least once while in this state. 4905 * 4906 * Almost all fields are related to the "fast-path" state only and don't 4907 * change until one of the instance properties is changed. 4908 * 4909 * {@code firstUsedIndex} and {@code lastFreeIndex} are the only 4910 * two fields that are used and modified while inside a call to 4911 * {@code fastDoubleFormat}. 4912 * 4913 * 4914 private static class FastPathData { 4915 // --- Temporary fields used in fast-path, shared by several methods. 4916 4917 /** The first unused index at the end of the formatted result. * 4918 int lastFreeIndex; 4919 4920 /** The first used index at the beginning of the formatted result * 4921 int firstUsedIndex; 4922 4923 // --- State fields related to fast-path status. Changes due to a 4924 // property change only. Set by checkAndSetFastPathStatus() only. 4925 4926 /** Difference between locale zero and default zero representation. * 4927 int zeroDelta; 4928 4929 /** Locale char for grouping separator. * 4930 char groupingChar; 4931 4932 /** Fixed index position of last integral digit of formatted result * 4933 int integralLastIndex; 4934 4935 /** Fixed index position of first fractional digit of formatted result * 4936 int fractionalFirstIndex; 4937 4938 /** Fractional constants depending on decimal|currency state * 4939 double fractionalScaleFactor; 4940 int fractionalMaxIntBound; 4941 4942 4943 /** The char array buffer that will contain the formatted result * 4944 char[] fastPathContainer; 4945 4946 /** Suffixes recorded as char array for efficiency. * 4947 char[] charsPositivePrefix; 4948 char[] charsNegativePrefix; 4949 char[] charsPositiveSuffix; 4950 char[] charsNegativeSuffix; 4951 boolean positiveAffixesRequired = true; 4952 boolean negativeAffixesRequired = true; 4953 } 4954 4955 /** The format fast-path status of the instance. Logical state. * 4956 private transient boolean isFastPath = false; 4957 4958 /** Flag stating need of check and reinit fast-path status on next format call. * 4959 private transient boolean fastPathCheckNeeded = true; 4960 4961 /** DecimalFormat reference to its FastPathData * 4962 private transient FastPathData fastPathData; 4963 */ 4964 // END Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData. 4965 4966 //---------------------------------------------------------------------- 4967 4968 static final int currentSerialVersion = 4; 4969 4970 // BEGIN Android-removed: serialVersionOnStream. 4971 4972 /** 4973 * The internal serial version which says which version was written. 4974 * Possible values are: 4975 * <ul> 4976 * <li><b>0</b> (default): versions before the Java 2 platform v1.2 4977 * <li><b>1</b>: version for 1.2, which includes the two new fields 4978 * {@code useExponentialNotation} and 4979 * {@code minExponentDigits}. 4980 * <li><b>2</b>: version for 1.3 and later, which adds four new fields: 4981 * {@code posPrefixPattern}, {@code posSuffixPattern}, 4982 * {@code negPrefixPattern}, and {@code negSuffixPattern}. 4983 * <li><b>3</b>: version for 1.5 and later, which adds five new fields: 4984 * {@code maximumIntegerDigits}, 4985 * {@code minimumIntegerDigits}, 4986 * {@code maximumFractionDigits}, 4987 * {@code minimumFractionDigits}, and 4988 * {@code parseBigDecimal}. 4989 * <li><b>4</b>: version for 1.6 and later, which adds one new field: 4990 * {@code roundingMode}. 4991 * </ul> 4992 * @since 1.2 4993 * @serial 4994 * 4995 private int serialVersionOnStream = currentSerialVersion; 4996 */ 4997 // END Android-removed: serialVersionOnStream. 4998 4999 //---------------------------------------------------------------------- 5000 // CONSTANTS 5001 //---------------------------------------------------------------------- 5002 5003 // BEGIN Android-removed: Fast-Path for double Constants, various constants. 5004 /* 5005 // ------ Fast-Path for double Constants ------ 5006 5007 /** Maximum valid integer value for applying fast-path algorithm * 5008 private static final double MAX_INT_AS_DOUBLE = (double) Integer.MAX_VALUE; 5009 5010 /** 5011 * The digit arrays used in the fast-path methods for collecting digits. 5012 * Using 3 constants arrays of chars ensures a very fast collection of digits 5013 * 5014 private static class DigitArrays { 5015 static final char[] DigitOnes1000 = new char[1000]; 5016 static final char[] DigitTens1000 = new char[1000]; 5017 static final char[] DigitHundreds1000 = new char[1000]; 5018 5019 // initialize on demand holder class idiom for arrays of digits 5020 static { 5021 int tenIndex = 0; 5022 int hundredIndex = 0; 5023 char digitOne = '0'; 5024 char digitTen = '0'; 5025 char digitHundred = '0'; 5026 for (int i = 0; i < 1000; i++ ) { 5027 5028 DigitOnes1000[i] = digitOne; 5029 if (digitOne == '9') 5030 digitOne = '0'; 5031 else 5032 digitOne++; 5033 5034 DigitTens1000[i] = digitTen; 5035 if (i == (tenIndex + 9)) { 5036 tenIndex += 10; 5037 if (digitTen == '9') 5038 digitTen = '0'; 5039 else 5040 digitTen++; 5041 } 5042 5043 DigitHundreds1000[i] = digitHundred; 5044 if (i == (hundredIndex + 99)) { 5045 digitHundred++; 5046 hundredIndex += 100; 5047 } 5048 } 5049 } 5050 } 5051 // ------ Fast-Path for double Constants end ------ 5052 5053 // Constants for characters used in programmatic (unlocalized) patterns. 5054 private static final char PATTERN_ZERO_DIGIT = '0'; 5055 private static final char PATTERN_GROUPING_SEPARATOR = ','; 5056 private static final char PATTERN_DECIMAL_SEPARATOR = '.'; 5057 private static final char PATTERN_PER_MILLE = '\u2030'; 5058 private static final char PATTERN_PERCENT = '%'; 5059 private static final char PATTERN_DIGIT = '#'; 5060 private static final char PATTERN_SEPARATOR = ';'; 5061 private static final String PATTERN_EXPONENT = "E"; 5062 private static final char PATTERN_MINUS = '-'; 5063 5064 /** 5065 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It 5066 * is used in patterns and substituted with either the currency symbol, 5067 * or if it is doubled, with the international currency symbol. If the 5068 * CURRENCY_SIGN is seen in a pattern, then the decimal/grouping separators 5069 * are replaced with the monetary decimal/grouping separators. 5070 * 5071 * The CURRENCY_SIGN is not localized. 5072 * 5073 private static final char CURRENCY_SIGN = '\u00A4'; 5074 5075 private static final char QUOTE = '\''; 5076 5077 private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0]; 5078 */ 5079 // END Android-removed: Fast-Path for double Constants, various constants. 5080 5081 // Upper limit on integer and fraction digits for a Java double 5082 static final int DOUBLE_INTEGER_DIGITS = 309; 5083 static final int DOUBLE_FRACTION_DIGITS = 340; 5084 5085 // Upper limit on integer and fraction digits for BigDecimal and BigInteger 5086 static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE; 5087 static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE; 5088 5089 // Proclaim JDK 1.1 serial compatibility. 5090 @java.io.Serial 5091 static final long serialVersionUID = 864413376551465018L; 5092 } 5093