rt/emul/compact/src/main/java/java/text/DecimalFormat.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 15:40:35 +0200
branchjdk7-b147
changeset 1334 588d5bf7a560
child 1339 8cc04f85a683
permissions -rw-r--r--
Set of JDK classes needed to run javac
jtulach@1334
     1
/*
jtulach@1334
     2
 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
jtulach@1334
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jtulach@1334
     4
 *
jtulach@1334
     5
 * This code is free software; you can redistribute it and/or modify it
jtulach@1334
     6
 * under the terms of the GNU General Public License version 2 only, as
jtulach@1334
     7
 * published by the Free Software Foundation.  Oracle designates this
jtulach@1334
     8
 * particular file as subject to the "Classpath" exception as provided
jtulach@1334
     9
 * by Oracle in the LICENSE file that accompanied this code.
jtulach@1334
    10
 *
jtulach@1334
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jtulach@1334
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jtulach@1334
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jtulach@1334
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jtulach@1334
    15
 * accompanied this code).
jtulach@1334
    16
 *
jtulach@1334
    17
 * You should have received a copy of the GNU General Public License version
jtulach@1334
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jtulach@1334
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jtulach@1334
    20
 *
jtulach@1334
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jtulach@1334
    22
 * or visit www.oracle.com if you need additional information or have any
jtulach@1334
    23
 * questions.
jtulach@1334
    24
 */
jtulach@1334
    25
jtulach@1334
    26
/*
jtulach@1334
    27
 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
jtulach@1334
    28
 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
jtulach@1334
    29
 *
jtulach@1334
    30
 *   The original version of this source code and documentation is copyrighted
jtulach@1334
    31
 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
jtulach@1334
    32
 * materials are provided under terms of a License Agreement between Taligent
jtulach@1334
    33
 * and Sun. This technology is protected by multiple US and International
jtulach@1334
    34
 * patents. This notice and attribution to Taligent may not be removed.
jtulach@1334
    35
 *   Taligent is a registered trademark of Taligent, Inc.
jtulach@1334
    36
 *
jtulach@1334
    37
 */
jtulach@1334
    38
jtulach@1334
    39
package java.text;
jtulach@1334
    40
jtulach@1334
    41
import java.io.InvalidObjectException;
jtulach@1334
    42
import java.io.IOException;
jtulach@1334
    43
import java.io.ObjectInputStream;
jtulach@1334
    44
import java.math.BigDecimal;
jtulach@1334
    45
import java.math.BigInteger;
jtulach@1334
    46
import java.math.RoundingMode;
jtulach@1334
    47
import java.util.ArrayList;
jtulach@1334
    48
import java.util.Currency;
jtulach@1334
    49
import java.util.Locale;
jtulach@1334
    50
import java.util.ResourceBundle;
jtulach@1334
    51
import java.util.concurrent.ConcurrentHashMap;
jtulach@1334
    52
import java.util.concurrent.ConcurrentMap;
jtulach@1334
    53
import java.util.concurrent.atomic.AtomicInteger;
jtulach@1334
    54
import java.util.concurrent.atomic.AtomicLong;
jtulach@1334
    55
import sun.util.resources.LocaleData;
jtulach@1334
    56
jtulach@1334
    57
/**
jtulach@1334
    58
 * <code>DecimalFormat</code> is a concrete subclass of
jtulach@1334
    59
 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
jtulach@1334
    60
 * features designed to make it possible to parse and format numbers in any
jtulach@1334
    61
 * locale, including support for Western, Arabic, and Indic digits.  It also
jtulach@1334
    62
 * supports different kinds of numbers, including integers (123), fixed-point
jtulach@1334
    63
 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
jtulach@1334
    64
 * currency amounts ($123).  All of these can be localized.
jtulach@1334
    65
 *
jtulach@1334
    66
 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
jtulach@1334
    67
 * default locale, call one of <code>NumberFormat</code>'s factory methods, such
jtulach@1334
    68
 * as <code>getInstance()</code>.  In general, do not call the
jtulach@1334
    69
 * <code>DecimalFormat</code> constructors directly, since the
jtulach@1334
    70
 * <code>NumberFormat</code> factory methods may return subclasses other than
jtulach@1334
    71
 * <code>DecimalFormat</code>. If you need to customize the format object, do
jtulach@1334
    72
 * something like this:
jtulach@1334
    73
 *
jtulach@1334
    74
 * <blockquote><pre>
jtulach@1334
    75
 * NumberFormat f = NumberFormat.getInstance(loc);
jtulach@1334
    76
 * if (f instanceof DecimalFormat) {
jtulach@1334
    77
 *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
jtulach@1334
    78
 * }
jtulach@1334
    79
 * </pre></blockquote>
jtulach@1334
    80
 *
jtulach@1334
    81
 * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
jtulach@1334
    82
 * <em>symbols</em>.  The pattern may be set directly using
jtulach@1334
    83
 * <code>applyPattern()</code>, or indirectly using the API methods.  The
jtulach@1334
    84
 * symbols are stored in a <code>DecimalFormatSymbols</code> object.  When using
jtulach@1334
    85
 * the <code>NumberFormat</code> factory methods, the pattern and symbols are
jtulach@1334
    86
 * read from localized <code>ResourceBundle</code>s.
jtulach@1334
    87
 *
jtulach@1334
    88
 * <h4>Patterns</h4>
jtulach@1334
    89
 *
jtulach@1334
    90
 * <code>DecimalFormat</code> patterns have the following syntax:
jtulach@1334
    91
 * <blockquote><pre>
jtulach@1334
    92
 * <i>Pattern:</i>
jtulach@1334
    93
 *         <i>PositivePattern</i>
jtulach@1334
    94
 *         <i>PositivePattern</i> ; <i>NegativePattern</i>
jtulach@1334
    95
 * <i>PositivePattern:</i>
jtulach@1334
    96
 *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
jtulach@1334
    97
 * <i>NegativePattern:</i>
jtulach@1334
    98
 *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
jtulach@1334
    99
 * <i>Prefix:</i>
jtulach@1334
   100
 *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
jtulach@1334
   101
 * <i>Suffix:</i>
jtulach@1334
   102
 *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
jtulach@1334
   103
 * <i>Number:</i>
jtulach@1334
   104
 *         <i>Integer</i> <i>Exponent<sub>opt</sub></i>
jtulach@1334
   105
 *         <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
jtulach@1334
   106
 * <i>Integer:</i>
jtulach@1334
   107
 *         <i>MinimumInteger</i>
jtulach@1334
   108
 *         #
jtulach@1334
   109
 *         # <i>Integer</i>
jtulach@1334
   110
 *         # , <i>Integer</i>
jtulach@1334
   111
 * <i>MinimumInteger:</i>
jtulach@1334
   112
 *         0
jtulach@1334
   113
 *         0 <i>MinimumInteger</i>
jtulach@1334
   114
 *         0 , <i>MinimumInteger</i>
jtulach@1334
   115
 * <i>Fraction:</i>
jtulach@1334
   116
 *         <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
jtulach@1334
   117
 * <i>MinimumFraction:</i>
jtulach@1334
   118
 *         0 <i>MinimumFraction<sub>opt</sub></i>
jtulach@1334
   119
 * <i>OptionalFraction:</i>
jtulach@1334
   120
 *         # <i>OptionalFraction<sub>opt</sub></i>
jtulach@1334
   121
 * <i>Exponent:</i>
jtulach@1334
   122
 *         E <i>MinimumExponent</i>
jtulach@1334
   123
 * <i>MinimumExponent:</i>
jtulach@1334
   124
 *         0 <i>MinimumExponent<sub>opt</sub></i>
jtulach@1334
   125
 * </pre></blockquote>
jtulach@1334
   126
 *
jtulach@1334
   127
 * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
jtulach@1334
   128
 * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>.  Each
jtulach@1334
   129
 * subpattern has a prefix, numeric part, and suffix. The negative subpattern
jtulach@1334
   130
 * is optional; if absent, then the positive subpattern prefixed with the
jtulach@1334
   131
 * localized minus sign (<code>'-'</code> in most locales) is used as the
jtulach@1334
   132
 * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
jtulach@1334
   133
 * <code>"0.00;-0.00"</code>.  If there is an explicit negative subpattern, it
jtulach@1334
   134
 * serves only to specify the negative prefix and suffix; the number of digits,
jtulach@1334
   135
 * minimal digits, and other characteristics are all the same as the positive
jtulach@1334
   136
 * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
jtulach@1334
   137
 * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
jtulach@1334
   138
 *
jtulach@1334
   139
 * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
jtulach@1334
   140
 * thousands separators, decimal separators, etc. may be set to arbitrary
jtulach@1334
   141
 * values, and they will appear properly during formatting.  However, care must
jtulach@1334
   142
 * be taken that the symbols and strings do not conflict, or parsing will be
jtulach@1334
   143
 * unreliable.  For example, either the positive and negative prefixes or the
jtulach@1334
   144
 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
jtulach@1334
   145
 * to distinguish positive from negative values.  (If they are identical, then
jtulach@1334
   146
 * <code>DecimalFormat</code> will behave as if no negative subpattern was
jtulach@1334
   147
 * specified.)  Another example is that the decimal separator and thousands
jtulach@1334
   148
 * separator should be distinct characters, or parsing will be impossible.
jtulach@1334
   149
 *
jtulach@1334
   150
 * <p>The grouping separator is commonly used for thousands, but in some
jtulach@1334
   151
 * countries it separates ten-thousands. The grouping size is a constant number
jtulach@1334
   152
 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
jtulach@1334
   153
 * 1,0000,0000.  If you supply a pattern with multiple grouping characters, the
jtulach@1334
   154
 * interval between the last one and the end of the integer is the one that is
jtulach@1334
   155
 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
jtulach@1334
   156
 * <code>"##,####,####"</code>.
jtulach@1334
   157
 *
jtulach@1334
   158
 * <h4>Special Pattern Characters</h4>
jtulach@1334
   159
 *
jtulach@1334
   160
 * <p>Many characters in a pattern are taken literally; they are matched during
jtulach@1334
   161
 * parsing and output unchanged during formatting.  Special characters, on the
jtulach@1334
   162
 * other hand, stand for other characters, strings, or classes of characters.
jtulach@1334
   163
 * They must be quoted, unless noted otherwise, if they are to appear in the
jtulach@1334
   164
 * prefix or suffix as literals.
jtulach@1334
   165
 *
jtulach@1334
   166
 * <p>The characters listed here are used in non-localized patterns.  Localized
jtulach@1334
   167
 * patterns use the corresponding characters taken from this formatter's
jtulach@1334
   168
 * <code>DecimalFormatSymbols</code> object instead, and these characters lose
jtulach@1334
   169
 * their special status.  Two exceptions are the currency sign and quote, which
jtulach@1334
   170
 * are not localized.
jtulach@1334
   171
 *
jtulach@1334
   172
 * <blockquote>
jtulach@1334
   173
 * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
jtulach@1334
   174
 *  location, localized, and meaning.">
jtulach@1334
   175
 *     <tr bgcolor="#ccccff">
jtulach@1334
   176
 *          <th align=left>Symbol
jtulach@1334
   177
 *          <th align=left>Location
jtulach@1334
   178
 *          <th align=left>Localized?
jtulach@1334
   179
 *          <th align=left>Meaning
jtulach@1334
   180
 *     <tr valign=top>
jtulach@1334
   181
 *          <td><code>0</code>
jtulach@1334
   182
 *          <td>Number
jtulach@1334
   183
 *          <td>Yes
jtulach@1334
   184
 *          <td>Digit
jtulach@1334
   185
 *     <tr valign=top bgcolor="#eeeeff">
jtulach@1334
   186
 *          <td><code>#</code>
jtulach@1334
   187
 *          <td>Number
jtulach@1334
   188
 *          <td>Yes
jtulach@1334
   189
 *          <td>Digit, zero shows as absent
jtulach@1334
   190
 *     <tr valign=top>
jtulach@1334
   191
 *          <td><code>.</code>
jtulach@1334
   192
 *          <td>Number
jtulach@1334
   193
 *          <td>Yes
jtulach@1334
   194
 *          <td>Decimal separator or monetary decimal separator
jtulach@1334
   195
 *     <tr valign=top bgcolor="#eeeeff">
jtulach@1334
   196
 *          <td><code>-</code>
jtulach@1334
   197
 *          <td>Number
jtulach@1334
   198
 *          <td>Yes
jtulach@1334
   199
 *          <td>Minus sign
jtulach@1334
   200
 *     <tr valign=top>
jtulach@1334
   201
 *          <td><code>,</code>
jtulach@1334
   202
 *          <td>Number
jtulach@1334
   203
 *          <td>Yes
jtulach@1334
   204
 *          <td>Grouping separator
jtulach@1334
   205
 *     <tr valign=top bgcolor="#eeeeff">
jtulach@1334
   206
 *          <td><code>E</code>
jtulach@1334
   207
 *          <td>Number
jtulach@1334
   208
 *          <td>Yes
jtulach@1334
   209
 *          <td>Separates mantissa and exponent in scientific notation.
jtulach@1334
   210
 *              <em>Need not be quoted in prefix or suffix.</em>
jtulach@1334
   211
 *     <tr valign=top>
jtulach@1334
   212
 *          <td><code>;</code>
jtulach@1334
   213
 *          <td>Subpattern boundary
jtulach@1334
   214
 *          <td>Yes
jtulach@1334
   215
 *          <td>Separates positive and negative subpatterns
jtulach@1334
   216
 *     <tr valign=top bgcolor="#eeeeff">
jtulach@1334
   217
 *          <td><code>%</code>
jtulach@1334
   218
 *          <td>Prefix or suffix
jtulach@1334
   219
 *          <td>Yes
jtulach@1334
   220
 *          <td>Multiply by 100 and show as percentage
jtulach@1334
   221
 *     <tr valign=top>
jtulach@1334
   222
 *          <td><code>&#92;u2030</code>
jtulach@1334
   223
 *          <td>Prefix or suffix
jtulach@1334
   224
 *          <td>Yes
jtulach@1334
   225
 *          <td>Multiply by 1000 and show as per mille value
jtulach@1334
   226
 *     <tr valign=top bgcolor="#eeeeff">
jtulach@1334
   227
 *          <td><code>&#164;</code> (<code>&#92;u00A4</code>)
jtulach@1334
   228
 *          <td>Prefix or suffix
jtulach@1334
   229
 *          <td>No
jtulach@1334
   230
 *          <td>Currency sign, replaced by currency symbol.  If
jtulach@1334
   231
 *              doubled, replaced by international currency symbol.
jtulach@1334
   232
 *              If present in a pattern, the monetary decimal separator
jtulach@1334
   233
 *              is used instead of the decimal separator.
jtulach@1334
   234
 *     <tr valign=top>
jtulach@1334
   235
 *          <td><code>'</code>
jtulach@1334
   236
 *          <td>Prefix or suffix
jtulach@1334
   237
 *          <td>No
jtulach@1334
   238
 *          <td>Used to quote special characters in a prefix or suffix,
jtulach@1334
   239
 *              for example, <code>"'#'#"</code> formats 123 to
jtulach@1334
   240
 *              <code>"#123"</code>.  To create a single quote
jtulach@1334
   241
 *              itself, use two in a row: <code>"# o''clock"</code>.
jtulach@1334
   242
 * </table>
jtulach@1334
   243
 * </blockquote>
jtulach@1334
   244
 *
jtulach@1334
   245
 * <h4>Scientific Notation</h4>
jtulach@1334
   246
 *
jtulach@1334
   247
 * <p>Numbers in scientific notation are expressed as the product of a mantissa
jtulach@1334
   248
 * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3.  The
jtulach@1334
   249
 * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
jtulach@1334
   250
 * <code>DecimalFormat</code> can be instructed to format and parse scientific
jtulach@1334
   251
 * notation <em>only via a pattern</em>; there is currently no factory method
jtulach@1334
   252
 * that creates a scientific notation format.  In a pattern, the exponent
jtulach@1334
   253
 * character immediately followed by one or more digit characters indicates
jtulach@1334
   254
 * scientific notation.  Example: <code>"0.###E0"</code> formats the number
jtulach@1334
   255
 * 1234 as <code>"1.234E3"</code>.
jtulach@1334
   256
 *
jtulach@1334
   257
 * <ul>
jtulach@1334
   258
 * <li>The number of digit characters after the exponent character gives the
jtulach@1334
   259
 * minimum exponent digit count.  There is no maximum.  Negative exponents are
jtulach@1334
   260
 * formatted using the localized minus sign, <em>not</em> the prefix and suffix
jtulach@1334
   261
 * from the pattern.  This allows patterns such as <code>"0.###E0 m/s"</code>.
jtulach@1334
   262
 *
jtulach@1334
   263
 * <li>The minimum and maximum number of integer digits are interpreted
jtulach@1334
   264
 * together:
jtulach@1334
   265
 *
jtulach@1334
   266
 * <ul>
jtulach@1334
   267
 * <li>If the maximum number of integer digits is greater than their minimum number
jtulach@1334
   268
 * and greater than 1, it forces the exponent to be a multiple of the maximum
jtulach@1334
   269
 * number of integer digits, and the minimum number of integer digits to be
jtulach@1334
   270
 * interpreted as 1.  The most common use of this is to generate
jtulach@1334
   271
 * <em>engineering notation</em>, in which the exponent is a multiple of three,
jtulach@1334
   272
 * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
jtulach@1334
   273
 * formats to <code>"12.345E3"</code>, and 123456 formats to
jtulach@1334
   274
 * <code>"123.456E3"</code>.
jtulach@1334
   275
 *
jtulach@1334
   276
 * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
jtulach@1334
   277
 * exponent.  Example: 0.00123 formatted with <code>"00.###E0"</code> yields
jtulach@1334
   278
 * <code>"12.3E-4"</code>.
jtulach@1334
   279
 * </ul>
jtulach@1334
   280
 *
jtulach@1334
   281
 * <li>The number of significant digits in the mantissa is the sum of the
jtulach@1334
   282
 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
jtulach@1334
   283
 * unaffected by the maximum integer digits.  For example, 12345 formatted with
jtulach@1334
   284
 * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
jtulach@1334
   285
 * the significant digits count to zero.  The number of significant digits
jtulach@1334
   286
 * does not affect parsing.
jtulach@1334
   287
 *
jtulach@1334
   288
 * <li>Exponential patterns may not contain grouping separators.
jtulach@1334
   289
 * </ul>
jtulach@1334
   290
 *
jtulach@1334
   291
 * <h4>Rounding</h4>
jtulach@1334
   292
 *
jtulach@1334
   293
 * <code>DecimalFormat</code> provides rounding modes defined in
jtulach@1334
   294
 * {@link java.math.RoundingMode} for formatting.  By default, it uses
jtulach@1334
   295
 * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
jtulach@1334
   296
 *
jtulach@1334
   297
 * <h4>Digits</h4>
jtulach@1334
   298
 *
jtulach@1334
   299
 * For formatting, <code>DecimalFormat</code> uses the ten consecutive
jtulach@1334
   300
 * characters starting with the localized zero digit defined in the
jtulach@1334
   301
 * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
jtulach@1334
   302
 * digits as well as all Unicode decimal digits, as defined by
jtulach@1334
   303
 * {@link Character#digit Character.digit}, are recognized.
jtulach@1334
   304
 *
jtulach@1334
   305
 * <h4>Special Values</h4>
jtulach@1334
   306
 *
jtulach@1334
   307
 * <p><code>NaN</code> is formatted as a string, which typically has a single character
jtulach@1334
   308
 * <code>&#92;uFFFD</code>.  This string is determined by the
jtulach@1334
   309
 * <code>DecimalFormatSymbols</code> object.  This is the only value for which
jtulach@1334
   310
 * the prefixes and suffixes are not used.
jtulach@1334
   311
 *
jtulach@1334
   312
 * <p>Infinity is formatted as a string, which typically has a single character
jtulach@1334
   313
 * <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
jtulach@1334
   314
 * applied.  The infinity string is determined by the
jtulach@1334
   315
 * <code>DecimalFormatSymbols</code> object.
jtulach@1334
   316
 *
jtulach@1334
   317
 * <p>Negative zero (<code>"-0"</code>) parses to
jtulach@1334
   318
 * <ul>
jtulach@1334
   319
 * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
jtulach@1334
   320
 * true,
jtulach@1334
   321
 * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
jtulach@1334
   322
 *     and <code>isParseIntegerOnly()</code> is true,
jtulach@1334
   323
 * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
jtulach@1334
   324
 * and <code>isParseIntegerOnly()</code> are false.
jtulach@1334
   325
 * </ul>
jtulach@1334
   326
 *
jtulach@1334
   327
 * <h4><a name="synchronization">Synchronization</a></h4>
jtulach@1334
   328
 *
jtulach@1334
   329
 * <p>
jtulach@1334
   330
 * Decimal formats are generally not synchronized.
jtulach@1334
   331
 * It is recommended to create separate format instances for each thread.
jtulach@1334
   332
 * If multiple threads access a format concurrently, it must be synchronized
jtulach@1334
   333
 * externally.
jtulach@1334
   334
 *
jtulach@1334
   335
 * <h4>Example</h4>
jtulach@1334
   336
 *
jtulach@1334
   337
 * <blockquote><pre>
jtulach@1334
   338
 * <strong>// Print out a number using the localized number, integer, currency,
jtulach@1334
   339
 * // and percent format for each locale</strong>
jtulach@1334
   340
 * Locale[] locales = NumberFormat.getAvailableLocales();
jtulach@1334
   341
 * double myNumber = -1234.56;
jtulach@1334
   342
 * NumberFormat form;
jtulach@1334
   343
 * for (int j=0; j<4; ++j) {
jtulach@1334
   344
 *     System.out.println("FORMAT");
jtulach@1334
   345
 *     for (int i = 0; i < locales.length; ++i) {
jtulach@1334
   346
 *         if (locales[i].getCountry().length() == 0) {
jtulach@1334
   347
 *            continue; // Skip language-only locales
jtulach@1334
   348
 *         }
jtulach@1334
   349
 *         System.out.print(locales[i].getDisplayName());
jtulach@1334
   350
 *         switch (j) {
jtulach@1334
   351
 *         case 0:
jtulach@1334
   352
 *             form = NumberFormat.getInstance(locales[i]); break;
jtulach@1334
   353
 *         case 1:
jtulach@1334
   354
 *             form = NumberFormat.getIntegerInstance(locales[i]); break;
jtulach@1334
   355
 *         case 2:
jtulach@1334
   356
 *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
jtulach@1334
   357
 *         default:
jtulach@1334
   358
 *             form = NumberFormat.getPercentInstance(locales[i]); break;
jtulach@1334
   359
 *         }
jtulach@1334
   360
 *         if (form instanceof DecimalFormat) {
jtulach@1334
   361
 *             System.out.print(": " + ((DecimalFormat) form).toPattern());
jtulach@1334
   362
 *         }
jtulach@1334
   363
 *         System.out.print(" -> " + form.format(myNumber));
jtulach@1334
   364
 *         try {
jtulach@1334
   365
 *             System.out.println(" -> " + form.parse(form.format(myNumber)));
jtulach@1334
   366
 *         } catch (ParseException e) {}
jtulach@1334
   367
 *     }
jtulach@1334
   368
 * }
jtulach@1334
   369
 * </pre></blockquote>
jtulach@1334
   370
 *
jtulach@1334
   371
 * @see          <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
jtulach@1334
   372
 * @see          NumberFormat
jtulach@1334
   373
 * @see          DecimalFormatSymbols
jtulach@1334
   374
 * @see          ParsePosition
jtulach@1334
   375
 * @author       Mark Davis
jtulach@1334
   376
 * @author       Alan Liu
jtulach@1334
   377
 */
jtulach@1334
   378
public class DecimalFormat extends NumberFormat {
jtulach@1334
   379
jtulach@1334
   380
    /**
jtulach@1334
   381
     * Creates a DecimalFormat using the default pattern and symbols
jtulach@1334
   382
     * for the default locale. This is a convenient way to obtain a
jtulach@1334
   383
     * DecimalFormat when internationalization is not the main concern.
jtulach@1334
   384
     * <p>
jtulach@1334
   385
     * To obtain standard formats for a given locale, use the factory methods
jtulach@1334
   386
     * on NumberFormat such as getNumberInstance. These factories will
jtulach@1334
   387
     * return the most appropriate sub-class of NumberFormat for a given
jtulach@1334
   388
     * locale.
jtulach@1334
   389
     *
jtulach@1334
   390
     * @see java.text.NumberFormat#getInstance
jtulach@1334
   391
     * @see java.text.NumberFormat#getNumberInstance
jtulach@1334
   392
     * @see java.text.NumberFormat#getCurrencyInstance
jtulach@1334
   393
     * @see java.text.NumberFormat#getPercentInstance
jtulach@1334
   394
     */
jtulach@1334
   395
    public DecimalFormat() {
jtulach@1334
   396
        Locale def = Locale.getDefault(Locale.Category.FORMAT);
jtulach@1334
   397
        // try to get the pattern from the cache
jtulach@1334
   398
        String pattern = cachedLocaleData.get(def);
jtulach@1334
   399
        if (pattern == null) {  /* cache miss */
jtulach@1334
   400
            // Get the pattern for the default locale.
jtulach@1334
   401
            ResourceBundle rb = LocaleData.getNumberFormatData(def);
jtulach@1334
   402
            String[] all = rb.getStringArray("NumberPatterns");
jtulach@1334
   403
            pattern = all[0];
jtulach@1334
   404
            /* update cache */
jtulach@1334
   405
            cachedLocaleData.putIfAbsent(def, pattern);
jtulach@1334
   406
        }
jtulach@1334
   407
jtulach@1334
   408
        // Always applyPattern after the symbols are set
jtulach@1334
   409
        this.symbols = new DecimalFormatSymbols(def);
jtulach@1334
   410
        applyPattern(pattern, false);
jtulach@1334
   411
    }
jtulach@1334
   412
jtulach@1334
   413
jtulach@1334
   414
    /**
jtulach@1334
   415
     * Creates a DecimalFormat using the given pattern and the symbols
jtulach@1334
   416
     * for the default locale. This is a convenient way to obtain a
jtulach@1334
   417
     * DecimalFormat when internationalization is not the main concern.
jtulach@1334
   418
     * <p>
jtulach@1334
   419
     * To obtain standard formats for a given locale, use the factory methods
jtulach@1334
   420
     * on NumberFormat such as getNumberInstance. These factories will
jtulach@1334
   421
     * return the most appropriate sub-class of NumberFormat for a given
jtulach@1334
   422
     * locale.
jtulach@1334
   423
     *
jtulach@1334
   424
     * @param pattern A non-localized pattern string.
jtulach@1334
   425
     * @exception NullPointerException if <code>pattern</code> is null
jtulach@1334
   426
     * @exception IllegalArgumentException if the given pattern is invalid.
jtulach@1334
   427
     * @see java.text.NumberFormat#getInstance
jtulach@1334
   428
     * @see java.text.NumberFormat#getNumberInstance
jtulach@1334
   429
     * @see java.text.NumberFormat#getCurrencyInstance
jtulach@1334
   430
     * @see java.text.NumberFormat#getPercentInstance
jtulach@1334
   431
     */
jtulach@1334
   432
    public DecimalFormat(String pattern) {
jtulach@1334
   433
        // Always applyPattern after the symbols are set
jtulach@1334
   434
        this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
jtulach@1334
   435
        applyPattern(pattern, false);
jtulach@1334
   436
    }
jtulach@1334
   437
jtulach@1334
   438
jtulach@1334
   439
    /**
jtulach@1334
   440
     * Creates a DecimalFormat using the given pattern and symbols.
jtulach@1334
   441
     * Use this constructor when you need to completely customize the
jtulach@1334
   442
     * behavior of the format.
jtulach@1334
   443
     * <p>
jtulach@1334
   444
     * To obtain standard formats for a given
jtulach@1334
   445
     * locale, use the factory methods on NumberFormat such as
jtulach@1334
   446
     * getInstance or getCurrencyInstance. If you need only minor adjustments
jtulach@1334
   447
     * to a standard format, you can modify the format returned by
jtulach@1334
   448
     * a NumberFormat factory method.
jtulach@1334
   449
     *
jtulach@1334
   450
     * @param pattern a non-localized pattern string
jtulach@1334
   451
     * @param symbols the set of symbols to be used
jtulach@1334
   452
     * @exception NullPointerException if any of the given arguments is null
jtulach@1334
   453
     * @exception IllegalArgumentException if the given pattern is invalid
jtulach@1334
   454
     * @see java.text.NumberFormat#getInstance
jtulach@1334
   455
     * @see java.text.NumberFormat#getNumberInstance
jtulach@1334
   456
     * @see java.text.NumberFormat#getCurrencyInstance
jtulach@1334
   457
     * @see java.text.NumberFormat#getPercentInstance
jtulach@1334
   458
     * @see java.text.DecimalFormatSymbols
jtulach@1334
   459
     */
jtulach@1334
   460
    public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
jtulach@1334
   461
        // Always applyPattern after the symbols are set
jtulach@1334
   462
        this.symbols = (DecimalFormatSymbols)symbols.clone();
jtulach@1334
   463
        applyPattern(pattern, false);
jtulach@1334
   464
    }
jtulach@1334
   465
jtulach@1334
   466
jtulach@1334
   467
    // Overrides
jtulach@1334
   468
    /**
jtulach@1334
   469
     * Formats a number and appends the resulting text to the given string
jtulach@1334
   470
     * buffer.
jtulach@1334
   471
     * The number can be of any subclass of {@link java.lang.Number}.
jtulach@1334
   472
     * <p>
jtulach@1334
   473
     * This implementation uses the maximum precision permitted.
jtulach@1334
   474
     * @param number     the number to format
jtulach@1334
   475
     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
jtulach@1334
   476
     *                   text is to be appended
jtulach@1334
   477
     * @param pos        On input: an alignment field, if desired.
jtulach@1334
   478
     *                   On output: the offsets of the alignment field.
jtulach@1334
   479
     * @return           the value passed in as <code>toAppendTo</code>
jtulach@1334
   480
     * @exception        IllegalArgumentException if <code>number</code> is
jtulach@1334
   481
     *                   null or not an instance of <code>Number</code>.
jtulach@1334
   482
     * @exception        NullPointerException if <code>toAppendTo</code> or
jtulach@1334
   483
     *                   <code>pos</code> is null
jtulach@1334
   484
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   485
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   486
     * @see              java.text.FieldPosition
jtulach@1334
   487
     */
jtulach@1334
   488
    public final StringBuffer format(Object number,
jtulach@1334
   489
                                     StringBuffer toAppendTo,
jtulach@1334
   490
                                     FieldPosition pos) {
jtulach@1334
   491
        if (number instanceof Long || number instanceof Integer ||
jtulach@1334
   492
                   number instanceof Short || number instanceof Byte ||
jtulach@1334
   493
                   number instanceof AtomicInteger ||
jtulach@1334
   494
                   number instanceof AtomicLong ||
jtulach@1334
   495
                   (number instanceof BigInteger &&
jtulach@1334
   496
                    ((BigInteger)number).bitLength () < 64)) {
jtulach@1334
   497
            return format(((Number)number).longValue(), toAppendTo, pos);
jtulach@1334
   498
        } else if (number instanceof BigDecimal) {
jtulach@1334
   499
            return format((BigDecimal)number, toAppendTo, pos);
jtulach@1334
   500
        } else if (number instanceof BigInteger) {
jtulach@1334
   501
            return format((BigInteger)number, toAppendTo, pos);
jtulach@1334
   502
        } else if (number instanceof Number) {
jtulach@1334
   503
            return format(((Number)number).doubleValue(), toAppendTo, pos);
jtulach@1334
   504
        } else {
jtulach@1334
   505
            throw new IllegalArgumentException("Cannot format given Object as a Number");
jtulach@1334
   506
        }
jtulach@1334
   507
    }
jtulach@1334
   508
jtulach@1334
   509
    /**
jtulach@1334
   510
     * Formats a double to produce a string.
jtulach@1334
   511
     * @param number    The double to format
jtulach@1334
   512
     * @param result    where the text is to be appended
jtulach@1334
   513
     * @param fieldPosition    On input: an alignment field, if desired.
jtulach@1334
   514
     * On output: the offsets of the alignment field.
jtulach@1334
   515
     * @exception ArithmeticException if rounding is needed with rounding
jtulach@1334
   516
     *            mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   517
     * @return The formatted number string
jtulach@1334
   518
     * @see java.text.FieldPosition
jtulach@1334
   519
     */
jtulach@1334
   520
    public StringBuffer format(double number, StringBuffer result,
jtulach@1334
   521
                               FieldPosition fieldPosition) {
jtulach@1334
   522
        fieldPosition.setBeginIndex(0);
jtulach@1334
   523
        fieldPosition.setEndIndex(0);
jtulach@1334
   524
jtulach@1334
   525
        return format(number, result, fieldPosition.getFieldDelegate());
jtulach@1334
   526
    }
jtulach@1334
   527
jtulach@1334
   528
    /**
jtulach@1334
   529
     * Formats a double to produce a string.
jtulach@1334
   530
     * @param number    The double to format
jtulach@1334
   531
     * @param result    where the text is to be appended
jtulach@1334
   532
     * @param delegate notified of locations of sub fields
jtulach@1334
   533
     * @exception       ArithmeticException if rounding is needed with rounding
jtulach@1334
   534
     *                  mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   535
     * @return The formatted number string
jtulach@1334
   536
     */
jtulach@1334
   537
    private StringBuffer format(double number, StringBuffer result,
jtulach@1334
   538
                                FieldDelegate delegate) {
jtulach@1334
   539
        if (Double.isNaN(number) ||
jtulach@1334
   540
           (Double.isInfinite(number) && multiplier == 0)) {
jtulach@1334
   541
            int iFieldStart = result.length();
jtulach@1334
   542
            result.append(symbols.getNaN());
jtulach@1334
   543
            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
jtulach@1334
   544
                               iFieldStart, result.length(), result);
jtulach@1334
   545
            return result;
jtulach@1334
   546
        }
jtulach@1334
   547
jtulach@1334
   548
        /* Detecting whether a double is negative is easy with the exception of
jtulach@1334
   549
         * the value -0.0.  This is a double which has a zero mantissa (and
jtulach@1334
   550
         * exponent), but a negative sign bit.  It is semantically distinct from
jtulach@1334
   551
         * a zero with a positive sign bit, and this distinction is important
jtulach@1334
   552
         * to certain kinds of computations.  However, it's a little tricky to
jtulach@1334
   553
         * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0).  How then, you may
jtulach@1334
   554
         * ask, does it behave distinctly from +0.0?  Well, 1/(-0.0) ==
jtulach@1334
   555
         * -Infinity.  Proper detection of -0.0 is needed to deal with the
jtulach@1334
   556
         * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
jtulach@1334
   557
         */
jtulach@1334
   558
        boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
jtulach@1334
   559
jtulach@1334
   560
        if (multiplier != 1) {
jtulach@1334
   561
            number *= multiplier;
jtulach@1334
   562
        }
jtulach@1334
   563
jtulach@1334
   564
        if (Double.isInfinite(number)) {
jtulach@1334
   565
            if (isNegative) {
jtulach@1334
   566
                append(result, negativePrefix, delegate,
jtulach@1334
   567
                       getNegativePrefixFieldPositions(), Field.SIGN);
jtulach@1334
   568
            } else {
jtulach@1334
   569
                append(result, positivePrefix, delegate,
jtulach@1334
   570
                       getPositivePrefixFieldPositions(), Field.SIGN);
jtulach@1334
   571
            }
jtulach@1334
   572
jtulach@1334
   573
            int iFieldStart = result.length();
jtulach@1334
   574
            result.append(symbols.getInfinity());
jtulach@1334
   575
            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
jtulach@1334
   576
                               iFieldStart, result.length(), result);
jtulach@1334
   577
jtulach@1334
   578
            if (isNegative) {
jtulach@1334
   579
                append(result, negativeSuffix, delegate,
jtulach@1334
   580
                       getNegativeSuffixFieldPositions(), Field.SIGN);
jtulach@1334
   581
            } else {
jtulach@1334
   582
                append(result, positiveSuffix, delegate,
jtulach@1334
   583
                       getPositiveSuffixFieldPositions(), Field.SIGN);
jtulach@1334
   584
            }
jtulach@1334
   585
jtulach@1334
   586
            return result;
jtulach@1334
   587
        }
jtulach@1334
   588
jtulach@1334
   589
        if (isNegative) {
jtulach@1334
   590
            number = -number;
jtulach@1334
   591
        }
jtulach@1334
   592
jtulach@1334
   593
        // at this point we are guaranteed a nonnegative finite number.
jtulach@1334
   594
        assert(number >= 0 && !Double.isInfinite(number));
jtulach@1334
   595
jtulach@1334
   596
        synchronized(digitList) {
jtulach@1334
   597
            int maxIntDigits = super.getMaximumIntegerDigits();
jtulach@1334
   598
            int minIntDigits = super.getMinimumIntegerDigits();
jtulach@1334
   599
            int maxFraDigits = super.getMaximumFractionDigits();
jtulach@1334
   600
            int minFraDigits = super.getMinimumFractionDigits();
jtulach@1334
   601
jtulach@1334
   602
            digitList.set(isNegative, number, useExponentialNotation ?
jtulach@1334
   603
                          maxIntDigits + maxFraDigits : maxFraDigits,
jtulach@1334
   604
                          !useExponentialNotation);
jtulach@1334
   605
            return subformat(result, delegate, isNegative, false,
jtulach@1334
   606
                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
jtulach@1334
   607
        }
jtulach@1334
   608
    }
jtulach@1334
   609
jtulach@1334
   610
    /**
jtulach@1334
   611
     * Format a long to produce a string.
jtulach@1334
   612
     * @param number    The long to format
jtulach@1334
   613
     * @param result    where the text is to be appended
jtulach@1334
   614
     * @param fieldPosition    On input: an alignment field, if desired.
jtulach@1334
   615
     * On output: the offsets of the alignment field.
jtulach@1334
   616
     * @exception       ArithmeticException if rounding is needed with rounding
jtulach@1334
   617
     *                  mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   618
     * @return The formatted number string
jtulach@1334
   619
     * @see java.text.FieldPosition
jtulach@1334
   620
     */
jtulach@1334
   621
    public StringBuffer format(long number, StringBuffer result,
jtulach@1334
   622
                               FieldPosition fieldPosition) {
jtulach@1334
   623
        fieldPosition.setBeginIndex(0);
jtulach@1334
   624
        fieldPosition.setEndIndex(0);
jtulach@1334
   625
jtulach@1334
   626
        return format(number, result, fieldPosition.getFieldDelegate());
jtulach@1334
   627
    }
jtulach@1334
   628
jtulach@1334
   629
    /**
jtulach@1334
   630
     * Format a long to produce a string.
jtulach@1334
   631
     * @param number    The long to format
jtulach@1334
   632
     * @param result    where the text is to be appended
jtulach@1334
   633
     * @param delegate notified of locations of sub fields
jtulach@1334
   634
     * @return The formatted number string
jtulach@1334
   635
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   636
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   637
     * @see java.text.FieldPosition
jtulach@1334
   638
     */
jtulach@1334
   639
    private StringBuffer format(long number, StringBuffer result,
jtulach@1334
   640
                               FieldDelegate delegate) {
jtulach@1334
   641
        boolean isNegative = (number < 0);
jtulach@1334
   642
        if (isNegative) {
jtulach@1334
   643
            number = -number;
jtulach@1334
   644
        }
jtulach@1334
   645
jtulach@1334
   646
        // In general, long values always represent real finite numbers, so
jtulach@1334
   647
        // we don't have to check for +/- Infinity or NaN.  However, there
jtulach@1334
   648
        // is one case we have to be careful of:  The multiplier can push
jtulach@1334
   649
        // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
jtulach@1334
   650
        // check for this before multiplying, and if it happens we use
jtulach@1334
   651
        // BigInteger instead.
jtulach@1334
   652
        boolean useBigInteger = false;
jtulach@1334
   653
        if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
jtulach@1334
   654
            if (multiplier != 0) {
jtulach@1334
   655
                useBigInteger = true;
jtulach@1334
   656
            }
jtulach@1334
   657
        } else if (multiplier != 1 && multiplier != 0) {
jtulach@1334
   658
            long cutoff = Long.MAX_VALUE / multiplier;
jtulach@1334
   659
            if (cutoff < 0) {
jtulach@1334
   660
                cutoff = -cutoff;
jtulach@1334
   661
            }
jtulach@1334
   662
            useBigInteger = (number > cutoff);
jtulach@1334
   663
        }
jtulach@1334
   664
jtulach@1334
   665
        if (useBigInteger) {
jtulach@1334
   666
            if (isNegative) {
jtulach@1334
   667
                number = -number;
jtulach@1334
   668
            }
jtulach@1334
   669
            BigInteger bigIntegerValue = BigInteger.valueOf(number);
jtulach@1334
   670
            return format(bigIntegerValue, result, delegate, true);
jtulach@1334
   671
        }
jtulach@1334
   672
jtulach@1334
   673
        number *= multiplier;
jtulach@1334
   674
        if (number == 0) {
jtulach@1334
   675
            isNegative = false;
jtulach@1334
   676
        } else {
jtulach@1334
   677
            if (multiplier < 0) {
jtulach@1334
   678
                number = -number;
jtulach@1334
   679
                isNegative = !isNegative;
jtulach@1334
   680
            }
jtulach@1334
   681
        }
jtulach@1334
   682
jtulach@1334
   683
        synchronized(digitList) {
jtulach@1334
   684
            int maxIntDigits = super.getMaximumIntegerDigits();
jtulach@1334
   685
            int minIntDigits = super.getMinimumIntegerDigits();
jtulach@1334
   686
            int maxFraDigits = super.getMaximumFractionDigits();
jtulach@1334
   687
            int minFraDigits = super.getMinimumFractionDigits();
jtulach@1334
   688
jtulach@1334
   689
            digitList.set(isNegative, number,
jtulach@1334
   690
                     useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
jtulach@1334
   691
jtulach@1334
   692
            return subformat(result, delegate, isNegative, true,
jtulach@1334
   693
                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
jtulach@1334
   694
        }
jtulach@1334
   695
    }
jtulach@1334
   696
jtulach@1334
   697
    /**
jtulach@1334
   698
     * Formats a BigDecimal to produce a string.
jtulach@1334
   699
     * @param number    The BigDecimal to format
jtulach@1334
   700
     * @param result    where the text is to be appended
jtulach@1334
   701
     * @param fieldPosition    On input: an alignment field, if desired.
jtulach@1334
   702
     * On output: the offsets of the alignment field.
jtulach@1334
   703
     * @return The formatted number string
jtulach@1334
   704
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   705
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   706
     * @see java.text.FieldPosition
jtulach@1334
   707
     */
jtulach@1334
   708
    private StringBuffer format(BigDecimal number, StringBuffer result,
jtulach@1334
   709
                                FieldPosition fieldPosition) {
jtulach@1334
   710
        fieldPosition.setBeginIndex(0);
jtulach@1334
   711
        fieldPosition.setEndIndex(0);
jtulach@1334
   712
        return format(number, result, fieldPosition.getFieldDelegate());
jtulach@1334
   713
    }
jtulach@1334
   714
jtulach@1334
   715
    /**
jtulach@1334
   716
     * Formats a BigDecimal to produce a string.
jtulach@1334
   717
     * @param number    The BigDecimal to format
jtulach@1334
   718
     * @param result    where the text is to be appended
jtulach@1334
   719
     * @param delegate notified of locations of sub fields
jtulach@1334
   720
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   721
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   722
     * @return The formatted number string
jtulach@1334
   723
     */
jtulach@1334
   724
    private StringBuffer format(BigDecimal number, StringBuffer result,
jtulach@1334
   725
                                FieldDelegate delegate) {
jtulach@1334
   726
        if (multiplier != 1) {
jtulach@1334
   727
            number = number.multiply(getBigDecimalMultiplier());
jtulach@1334
   728
        }
jtulach@1334
   729
        boolean isNegative = number.signum() == -1;
jtulach@1334
   730
        if (isNegative) {
jtulach@1334
   731
            number = number.negate();
jtulach@1334
   732
        }
jtulach@1334
   733
jtulach@1334
   734
        synchronized(digitList) {
jtulach@1334
   735
            int maxIntDigits = getMaximumIntegerDigits();
jtulach@1334
   736
            int minIntDigits = getMinimumIntegerDigits();
jtulach@1334
   737
            int maxFraDigits = getMaximumFractionDigits();
jtulach@1334
   738
            int minFraDigits = getMinimumFractionDigits();
jtulach@1334
   739
            int maximumDigits = maxIntDigits + maxFraDigits;
jtulach@1334
   740
jtulach@1334
   741
            digitList.set(isNegative, number, useExponentialNotation ?
jtulach@1334
   742
                ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
jtulach@1334
   743
                maxFraDigits, !useExponentialNotation);
jtulach@1334
   744
jtulach@1334
   745
            return subformat(result, delegate, isNegative, false,
jtulach@1334
   746
                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
jtulach@1334
   747
        }
jtulach@1334
   748
    }
jtulach@1334
   749
jtulach@1334
   750
    /**
jtulach@1334
   751
     * Format a BigInteger to produce a string.
jtulach@1334
   752
     * @param number    The BigInteger to format
jtulach@1334
   753
     * @param result    where the text is to be appended
jtulach@1334
   754
     * @param fieldPosition    On input: an alignment field, if desired.
jtulach@1334
   755
     * On output: the offsets of the alignment field.
jtulach@1334
   756
     * @return The formatted number string
jtulach@1334
   757
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   758
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   759
     * @see java.text.FieldPosition
jtulach@1334
   760
     */
jtulach@1334
   761
    private StringBuffer format(BigInteger number, StringBuffer result,
jtulach@1334
   762
                               FieldPosition fieldPosition) {
jtulach@1334
   763
        fieldPosition.setBeginIndex(0);
jtulach@1334
   764
        fieldPosition.setEndIndex(0);
jtulach@1334
   765
jtulach@1334
   766
        return format(number, result, fieldPosition.getFieldDelegate(), false);
jtulach@1334
   767
    }
jtulach@1334
   768
jtulach@1334
   769
    /**
jtulach@1334
   770
     * Format a BigInteger to produce a string.
jtulach@1334
   771
     * @param number    The BigInteger to format
jtulach@1334
   772
     * @param result    where the text is to be appended
jtulach@1334
   773
     * @param delegate notified of locations of sub fields
jtulach@1334
   774
     * @return The formatted number string
jtulach@1334
   775
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   776
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   777
     * @see java.text.FieldPosition
jtulach@1334
   778
     */
jtulach@1334
   779
    private StringBuffer format(BigInteger number, StringBuffer result,
jtulach@1334
   780
                               FieldDelegate delegate, boolean formatLong) {
jtulach@1334
   781
        if (multiplier != 1) {
jtulach@1334
   782
            number = number.multiply(getBigIntegerMultiplier());
jtulach@1334
   783
        }
jtulach@1334
   784
        boolean isNegative = number.signum() == -1;
jtulach@1334
   785
        if (isNegative) {
jtulach@1334
   786
            number = number.negate();
jtulach@1334
   787
        }
jtulach@1334
   788
jtulach@1334
   789
        synchronized(digitList) {
jtulach@1334
   790
            int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
jtulach@1334
   791
            if (formatLong) {
jtulach@1334
   792
                maxIntDigits = super.getMaximumIntegerDigits();
jtulach@1334
   793
                minIntDigits = super.getMinimumIntegerDigits();
jtulach@1334
   794
                maxFraDigits = super.getMaximumFractionDigits();
jtulach@1334
   795
                minFraDigits = super.getMinimumFractionDigits();
jtulach@1334
   796
                maximumDigits = maxIntDigits + maxFraDigits;
jtulach@1334
   797
            } else {
jtulach@1334
   798
                maxIntDigits = getMaximumIntegerDigits();
jtulach@1334
   799
                minIntDigits = getMinimumIntegerDigits();
jtulach@1334
   800
                maxFraDigits = getMaximumFractionDigits();
jtulach@1334
   801
                minFraDigits = getMinimumFractionDigits();
jtulach@1334
   802
                maximumDigits = maxIntDigits + maxFraDigits;
jtulach@1334
   803
                if (maximumDigits < 0) {
jtulach@1334
   804
                    maximumDigits = Integer.MAX_VALUE;
jtulach@1334
   805
                }
jtulach@1334
   806
            }
jtulach@1334
   807
jtulach@1334
   808
            digitList.set(isNegative, number,
jtulach@1334
   809
                          useExponentialNotation ? maximumDigits : 0);
jtulach@1334
   810
jtulach@1334
   811
            return subformat(result, delegate, isNegative, true,
jtulach@1334
   812
                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
jtulach@1334
   813
        }
jtulach@1334
   814
    }
jtulach@1334
   815
jtulach@1334
   816
    /**
jtulach@1334
   817
     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
jtulach@1334
   818
     * You can use the returned <code>AttributedCharacterIterator</code>
jtulach@1334
   819
     * to build the resulting String, as well as to determine information
jtulach@1334
   820
     * about the resulting String.
jtulach@1334
   821
     * <p>
jtulach@1334
   822
     * Each attribute key of the AttributedCharacterIterator will be of type
jtulach@1334
   823
     * <code>NumberFormat.Field</code>, with the attribute value being the
jtulach@1334
   824
     * same as the attribute key.
jtulach@1334
   825
     *
jtulach@1334
   826
     * @exception NullPointerException if obj is null.
jtulach@1334
   827
     * @exception IllegalArgumentException when the Format cannot format the
jtulach@1334
   828
     *            given object.
jtulach@1334
   829
     * @exception        ArithmeticException if rounding is needed with rounding
jtulach@1334
   830
     *                   mode being set to RoundingMode.UNNECESSARY
jtulach@1334
   831
     * @param obj The object to format
jtulach@1334
   832
     * @return AttributedCharacterIterator describing the formatted value.
jtulach@1334
   833
     * @since 1.4
jtulach@1334
   834
     */
jtulach@1334
   835
    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
jtulach@1334
   836
        CharacterIteratorFieldDelegate delegate =
jtulach@1334
   837
                         new CharacterIteratorFieldDelegate();
jtulach@1334
   838
        StringBuffer sb = new StringBuffer();
jtulach@1334
   839
jtulach@1334
   840
        if (obj instanceof Double || obj instanceof Float) {
jtulach@1334
   841
            format(((Number)obj).doubleValue(), sb, delegate);
jtulach@1334
   842
        } else if (obj instanceof Long || obj instanceof Integer ||
jtulach@1334
   843
                   obj instanceof Short || obj instanceof Byte ||
jtulach@1334
   844
                   obj instanceof AtomicInteger || obj instanceof AtomicLong) {
jtulach@1334
   845
            format(((Number)obj).longValue(), sb, delegate);
jtulach@1334
   846
        } else if (obj instanceof BigDecimal) {
jtulach@1334
   847
            format((BigDecimal)obj, sb, delegate);
jtulach@1334
   848
        } else if (obj instanceof BigInteger) {
jtulach@1334
   849
            format((BigInteger)obj, sb, delegate, false);
jtulach@1334
   850
        } else if (obj == null) {
jtulach@1334
   851
            throw new NullPointerException(
jtulach@1334
   852
                "formatToCharacterIterator must be passed non-null object");
jtulach@1334
   853
        } else {
jtulach@1334
   854
            throw new IllegalArgumentException(
jtulach@1334
   855
                "Cannot format given Object as a Number");
jtulach@1334
   856
        }
jtulach@1334
   857
        return delegate.getIterator(sb.toString());
jtulach@1334
   858
    }
jtulach@1334
   859
jtulach@1334
   860
    /**
jtulach@1334
   861
     * Complete the formatting of a finite number.  On entry, the digitList must
jtulach@1334
   862
     * be filled in with the correct digits.
jtulach@1334
   863
     */
jtulach@1334
   864
    private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
jtulach@1334
   865
                                   boolean isNegative, boolean isInteger,
jtulach@1334
   866
                                   int maxIntDigits, int minIntDigits,
jtulach@1334
   867
                                   int maxFraDigits, int minFraDigits) {
jtulach@1334
   868
        // NOTE: This isn't required anymore because DigitList takes care of this.
jtulach@1334
   869
        //
jtulach@1334
   870
        //  // The negative of the exponent represents the number of leading
jtulach@1334
   871
        //  // zeros between the decimal and the first non-zero digit, for
jtulach@1334
   872
        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
jtulach@1334
   873
        //  // is more than the maximum fraction digits, then we have an underflow
jtulach@1334
   874
        //  // for the printed representation.  We recognize this here and set
jtulach@1334
   875
        //  // the DigitList representation to zero in this situation.
jtulach@1334
   876
        //
jtulach@1334
   877
        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
jtulach@1334
   878
        //  {
jtulach@1334
   879
        //      digitList.count = 0;
jtulach@1334
   880
        //  }
jtulach@1334
   881
jtulach@1334
   882
        char zero = symbols.getZeroDigit();
jtulach@1334
   883
        int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
jtulach@1334
   884
        char grouping = symbols.getGroupingSeparator();
jtulach@1334
   885
        char decimal = isCurrencyFormat ?
jtulach@1334
   886
            symbols.getMonetaryDecimalSeparator() :
jtulach@1334
   887
            symbols.getDecimalSeparator();
jtulach@1334
   888
jtulach@1334
   889
        /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
jtulach@1334
   890
         * format as zero.  This allows sensible computations and preserves
jtulach@1334
   891
         * relations such as signum(1/x) = signum(x), where x is +Infinity or
jtulach@1334
   892
         * -Infinity.  Prior to this fix, we always formatted zero values as if
jtulach@1334
   893
         * they were positive.  Liu 7/6/98.
jtulach@1334
   894
         */
jtulach@1334
   895
        if (digitList.isZero()) {
jtulach@1334
   896
            digitList.decimalAt = 0; // Normalize
jtulach@1334
   897
        }
jtulach@1334
   898
jtulach@1334
   899
        if (isNegative) {
jtulach@1334
   900
            append(result, negativePrefix, delegate,
jtulach@1334
   901
                   getNegativePrefixFieldPositions(), Field.SIGN);
jtulach@1334
   902
        } else {
jtulach@1334
   903
            append(result, positivePrefix, delegate,
jtulach@1334
   904
                   getPositivePrefixFieldPositions(), Field.SIGN);
jtulach@1334
   905
        }
jtulach@1334
   906
jtulach@1334
   907
        if (useExponentialNotation) {
jtulach@1334
   908
            int iFieldStart = result.length();
jtulach@1334
   909
            int iFieldEnd = -1;
jtulach@1334
   910
            int fFieldStart = -1;
jtulach@1334
   911
jtulach@1334
   912
            // Minimum integer digits are handled in exponential format by
jtulach@1334
   913
            // adjusting the exponent.  For example, 0.01234 with 3 minimum
jtulach@1334
   914
            // integer digits is "123.4E-4".
jtulach@1334
   915
jtulach@1334
   916
            // Maximum integer digits are interpreted as indicating the
jtulach@1334
   917
            // repeating range.  This is useful for engineering notation, in
jtulach@1334
   918
            // which the exponent is restricted to a multiple of 3.  For
jtulach@1334
   919
            // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
jtulach@1334
   920
            // If maximum integer digits are > 1 and are larger than
jtulach@1334
   921
            // minimum integer digits, then minimum integer digits are
jtulach@1334
   922
            // ignored.
jtulach@1334
   923
            int exponent = digitList.decimalAt;
jtulach@1334
   924
            int repeat = maxIntDigits;
jtulach@1334
   925
            int minimumIntegerDigits = minIntDigits;
jtulach@1334
   926
            if (repeat > 1 && repeat > minIntDigits) {
jtulach@1334
   927
                // A repeating range is defined; adjust to it as follows.
jtulach@1334
   928
                // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
jtulach@1334
   929
                // -3,-4,-5=>-6, etc. This takes into account that the
jtulach@1334
   930
                // exponent we have here is off by one from what we expect;
jtulach@1334
   931
                // it is for the format 0.MMMMMx10^n.
jtulach@1334
   932
                if (exponent >= 1) {
jtulach@1334
   933
                    exponent = ((exponent - 1) / repeat) * repeat;
jtulach@1334
   934
                } else {
jtulach@1334
   935
                    // integer division rounds towards 0
jtulach@1334
   936
                    exponent = ((exponent - repeat) / repeat) * repeat;
jtulach@1334
   937
                }
jtulach@1334
   938
                minimumIntegerDigits = 1;
jtulach@1334
   939
            } else {
jtulach@1334
   940
                // No repeating range is defined; use minimum integer digits.
jtulach@1334
   941
                exponent -= minimumIntegerDigits;
jtulach@1334
   942
            }
jtulach@1334
   943
jtulach@1334
   944
            // We now output a minimum number of digits, and more if there
jtulach@1334
   945
            // are more digits, up to the maximum number of digits.  We
jtulach@1334
   946
            // place the decimal point after the "integer" digits, which
jtulach@1334
   947
            // are the first (decimalAt - exponent) digits.
jtulach@1334
   948
            int minimumDigits = minIntDigits + minFraDigits;
jtulach@1334
   949
            if (minimumDigits < 0) {    // overflow?
jtulach@1334
   950
                minimumDigits = Integer.MAX_VALUE;
jtulach@1334
   951
            }
jtulach@1334
   952
jtulach@1334
   953
            // The number of integer digits is handled specially if the number
jtulach@1334
   954
            // is zero, since then there may be no digits.
jtulach@1334
   955
            int integerDigits = digitList.isZero() ? minimumIntegerDigits :
jtulach@1334
   956
                    digitList.decimalAt - exponent;
jtulach@1334
   957
            if (minimumDigits < integerDigits) {
jtulach@1334
   958
                minimumDigits = integerDigits;
jtulach@1334
   959
            }
jtulach@1334
   960
            int totalDigits = digitList.count;
jtulach@1334
   961
            if (minimumDigits > totalDigits) {
jtulach@1334
   962
                totalDigits = minimumDigits;
jtulach@1334
   963
            }
jtulach@1334
   964
            boolean addedDecimalSeparator = false;
jtulach@1334
   965
jtulach@1334
   966
            for (int i=0; i<totalDigits; ++i) {
jtulach@1334
   967
                if (i == integerDigits) {
jtulach@1334
   968
                    // Record field information for caller.
jtulach@1334
   969
                    iFieldEnd = result.length();
jtulach@1334
   970
jtulach@1334
   971
                    result.append(decimal);
jtulach@1334
   972
                    addedDecimalSeparator = true;
jtulach@1334
   973
jtulach@1334
   974
                    // Record field information for caller.
jtulach@1334
   975
                    fFieldStart = result.length();
jtulach@1334
   976
                }
jtulach@1334
   977
                result.append((i < digitList.count) ?
jtulach@1334
   978
                              (char)(digitList.digits[i] + zeroDelta) :
jtulach@1334
   979
                              zero);
jtulach@1334
   980
            }
jtulach@1334
   981
jtulach@1334
   982
            if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
jtulach@1334
   983
                // Record field information for caller.
jtulach@1334
   984
                iFieldEnd = result.length();
jtulach@1334
   985
jtulach@1334
   986
                result.append(decimal);
jtulach@1334
   987
                addedDecimalSeparator = true;
jtulach@1334
   988
jtulach@1334
   989
                // Record field information for caller.
jtulach@1334
   990
                fFieldStart = result.length();
jtulach@1334
   991
            }
jtulach@1334
   992
jtulach@1334
   993
            // Record field information
jtulach@1334
   994
            if (iFieldEnd == -1) {
jtulach@1334
   995
                iFieldEnd = result.length();
jtulach@1334
   996
            }
jtulach@1334
   997
            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
jtulach@1334
   998
                               iFieldStart, iFieldEnd, result);
jtulach@1334
   999
            if (addedDecimalSeparator) {
jtulach@1334
  1000
                delegate.formatted(Field.DECIMAL_SEPARATOR,
jtulach@1334
  1001
                                   Field.DECIMAL_SEPARATOR,
jtulach@1334
  1002
                                   iFieldEnd, fFieldStart, result);
jtulach@1334
  1003
            }
jtulach@1334
  1004
            if (fFieldStart == -1) {
jtulach@1334
  1005
                fFieldStart = result.length();
jtulach@1334
  1006
            }
jtulach@1334
  1007
            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
jtulach@1334
  1008
                               fFieldStart, result.length(), result);
jtulach@1334
  1009
jtulach@1334
  1010
            // The exponent is output using the pattern-specified minimum
jtulach@1334
  1011
            // exponent digits.  There is no maximum limit to the exponent
jtulach@1334
  1012
            // digits, since truncating the exponent would result in an
jtulach@1334
  1013
            // unacceptable inaccuracy.
jtulach@1334
  1014
            int fieldStart = result.length();
jtulach@1334
  1015
jtulach@1334
  1016
            result.append(symbols.getExponentSeparator());
jtulach@1334
  1017
jtulach@1334
  1018
            delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
jtulach@1334
  1019
                               fieldStart, result.length(), result);
jtulach@1334
  1020
jtulach@1334
  1021
            // For zero values, we force the exponent to zero.  We
jtulach@1334
  1022
            // must do this here, and not earlier, because the value
jtulach@1334
  1023
            // is used to determine integer digit count above.
jtulach@1334
  1024
            if (digitList.isZero()) {
jtulach@1334
  1025
                exponent = 0;
jtulach@1334
  1026
            }
jtulach@1334
  1027
jtulach@1334
  1028
            boolean negativeExponent = exponent < 0;
jtulach@1334
  1029
            if (negativeExponent) {
jtulach@1334
  1030
                exponent = -exponent;
jtulach@1334
  1031
                fieldStart = result.length();
jtulach@1334
  1032
                result.append(symbols.getMinusSign());
jtulach@1334
  1033
                delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
jtulach@1334
  1034
                                   fieldStart, result.length(), result);
jtulach@1334
  1035
            }
jtulach@1334
  1036
            digitList.set(negativeExponent, exponent);
jtulach@1334
  1037
jtulach@1334
  1038
            int eFieldStart = result.length();
jtulach@1334
  1039
jtulach@1334
  1040
            for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
jtulach@1334
  1041
                result.append(zero);
jtulach@1334
  1042
            }
jtulach@1334
  1043
            for (int i=0; i<digitList.decimalAt; ++i) {
jtulach@1334
  1044
                result.append((i < digitList.count) ?
jtulach@1334
  1045
                          (char)(digitList.digits[i] + zeroDelta) : zero);
jtulach@1334
  1046
            }
jtulach@1334
  1047
            delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
jtulach@1334
  1048
                               result.length(), result);
jtulach@1334
  1049
        } else {
jtulach@1334
  1050
            int iFieldStart = result.length();
jtulach@1334
  1051
jtulach@1334
  1052
            // Output the integer portion.  Here 'count' is the total
jtulach@1334
  1053
            // number of integer digits we will display, including both
jtulach@1334
  1054
            // leading zeros required to satisfy getMinimumIntegerDigits,
jtulach@1334
  1055
            // and actual digits present in the number.
jtulach@1334
  1056
            int count = minIntDigits;
jtulach@1334
  1057
            int digitIndex = 0; // Index into digitList.fDigits[]
jtulach@1334
  1058
            if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
jtulach@1334
  1059
                count = digitList.decimalAt;
jtulach@1334
  1060
            }
jtulach@1334
  1061
jtulach@1334
  1062
            // Handle the case where getMaximumIntegerDigits() is smaller
jtulach@1334
  1063
            // than the real number of integer digits.  If this is so, we
jtulach@1334
  1064
            // output the least significant max integer digits.  For example,
jtulach@1334
  1065
            // the value 1997 printed with 2 max integer digits is just "97".
jtulach@1334
  1066
            if (count > maxIntDigits) {
jtulach@1334
  1067
                count = maxIntDigits;
jtulach@1334
  1068
                digitIndex = digitList.decimalAt - count;
jtulach@1334
  1069
            }
jtulach@1334
  1070
jtulach@1334
  1071
            int sizeBeforeIntegerPart = result.length();
jtulach@1334
  1072
            for (int i=count-1; i>=0; --i) {
jtulach@1334
  1073
                if (i < digitList.decimalAt && digitIndex < digitList.count) {
jtulach@1334
  1074
                    // Output a real digit
jtulach@1334
  1075
                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
jtulach@1334
  1076
                } else {
jtulach@1334
  1077
                    // Output a leading zero
jtulach@1334
  1078
                    result.append(zero);
jtulach@1334
  1079
                }
jtulach@1334
  1080
jtulach@1334
  1081
                // Output grouping separator if necessary.  Don't output a
jtulach@1334
  1082
                // grouping separator if i==0 though; that's at the end of
jtulach@1334
  1083
                // the integer part.
jtulach@1334
  1084
                if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
jtulach@1334
  1085
                    (i % groupingSize == 0)) {
jtulach@1334
  1086
                    int gStart = result.length();
jtulach@1334
  1087
                    result.append(grouping);
jtulach@1334
  1088
                    delegate.formatted(Field.GROUPING_SEPARATOR,
jtulach@1334
  1089
                                       Field.GROUPING_SEPARATOR, gStart,
jtulach@1334
  1090
                                       result.length(), result);
jtulach@1334
  1091
                }
jtulach@1334
  1092
            }
jtulach@1334
  1093
jtulach@1334
  1094
            // Determine whether or not there are any printable fractional
jtulach@1334
  1095
            // digits.  If we've used up the digits we know there aren't.
jtulach@1334
  1096
            boolean fractionPresent = (minFraDigits > 0) ||
jtulach@1334
  1097
                (!isInteger && digitIndex < digitList.count);
jtulach@1334
  1098
jtulach@1334
  1099
            // If there is no fraction present, and we haven't printed any
jtulach@1334
  1100
            // integer digits, then print a zero.  Otherwise we won't print
jtulach@1334
  1101
            // _any_ digits, and we won't be able to parse this string.
jtulach@1334
  1102
            if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
jtulach@1334
  1103
                result.append(zero);
jtulach@1334
  1104
            }
jtulach@1334
  1105
jtulach@1334
  1106
            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
jtulach@1334
  1107
                               iFieldStart, result.length(), result);
jtulach@1334
  1108
jtulach@1334
  1109
            // Output the decimal separator if we always do so.
jtulach@1334
  1110
            int sStart = result.length();
jtulach@1334
  1111
            if (decimalSeparatorAlwaysShown || fractionPresent) {
jtulach@1334
  1112
                result.append(decimal);
jtulach@1334
  1113
            }
jtulach@1334
  1114
jtulach@1334
  1115
            if (sStart != result.length()) {
jtulach@1334
  1116
                delegate.formatted(Field.DECIMAL_SEPARATOR,
jtulach@1334
  1117
                                   Field.DECIMAL_SEPARATOR,
jtulach@1334
  1118
                                   sStart, result.length(), result);
jtulach@1334
  1119
            }
jtulach@1334
  1120
            int fFieldStart = result.length();
jtulach@1334
  1121
jtulach@1334
  1122
            for (int i=0; i < maxFraDigits; ++i) {
jtulach@1334
  1123
                // Here is where we escape from the loop.  We escape if we've
jtulach@1334
  1124
                // output the maximum fraction digits (specified in the for
jtulach@1334
  1125
                // expression above).
jtulach@1334
  1126
                // We also stop when we've output the minimum digits and either:
jtulach@1334
  1127
                // we have an integer, so there is no fractional stuff to
jtulach@1334
  1128
                // display, or we're out of significant digits.
jtulach@1334
  1129
                if (i >= minFraDigits &&
jtulach@1334
  1130
                    (isInteger || digitIndex >= digitList.count)) {
jtulach@1334
  1131
                    break;
jtulach@1334
  1132
                }
jtulach@1334
  1133
jtulach@1334
  1134
                // Output leading fractional zeros. These are zeros that come
jtulach@1334
  1135
                // after the decimal but before any significant digits. These
jtulach@1334
  1136
                // are only output if abs(number being formatted) < 1.0.
jtulach@1334
  1137
                if (-1-i > (digitList.decimalAt-1)) {
jtulach@1334
  1138
                    result.append(zero);
jtulach@1334
  1139
                    continue;
jtulach@1334
  1140
                }
jtulach@1334
  1141
jtulach@1334
  1142
                // Output a digit, if we have any precision left, or a
jtulach@1334
  1143
                // zero if we don't.  We don't want to output noise digits.
jtulach@1334
  1144
                if (!isInteger && digitIndex < digitList.count) {
jtulach@1334
  1145
                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
jtulach@1334
  1146
                } else {
jtulach@1334
  1147
                    result.append(zero);
jtulach@1334
  1148
                }
jtulach@1334
  1149
            }
jtulach@1334
  1150
jtulach@1334
  1151
            // Record field information for caller.
jtulach@1334
  1152
            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
jtulach@1334
  1153
                               fFieldStart, result.length(), result);
jtulach@1334
  1154
        }
jtulach@1334
  1155
jtulach@1334
  1156
        if (isNegative) {
jtulach@1334
  1157
            append(result, negativeSuffix, delegate,
jtulach@1334
  1158
                   getNegativeSuffixFieldPositions(), Field.SIGN);
jtulach@1334
  1159
        }
jtulach@1334
  1160
        else {
jtulach@1334
  1161
            append(result, positiveSuffix, delegate,
jtulach@1334
  1162
                   getPositiveSuffixFieldPositions(), Field.SIGN);
jtulach@1334
  1163
        }
jtulach@1334
  1164
jtulach@1334
  1165
        return result;
jtulach@1334
  1166
    }
jtulach@1334
  1167
jtulach@1334
  1168
    /**
jtulach@1334
  1169
     * Appends the String <code>string</code> to <code>result</code>.
jtulach@1334
  1170
     * <code>delegate</code> is notified of all  the
jtulach@1334
  1171
     * <code>FieldPosition</code>s in <code>positions</code>.
jtulach@1334
  1172
     * <p>
jtulach@1334
  1173
     * If one of the <code>FieldPosition</code>s in <code>positions</code>
jtulach@1334
  1174
     * identifies a <code>SIGN</code> attribute, it is mapped to
jtulach@1334
  1175
     * <code>signAttribute</code>. This is used
jtulach@1334
  1176
     * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
jtulach@1334
  1177
     * attribute as necessary.
jtulach@1334
  1178
     * <p>
jtulach@1334
  1179
     * This is used by <code>subformat</code> to add the prefix/suffix.
jtulach@1334
  1180
     */
jtulach@1334
  1181
    private void append(StringBuffer result, String string,
jtulach@1334
  1182
                        FieldDelegate delegate,
jtulach@1334
  1183
                        FieldPosition[] positions,
jtulach@1334
  1184
                        Format.Field signAttribute) {
jtulach@1334
  1185
        int start = result.length();
jtulach@1334
  1186
jtulach@1334
  1187
        if (string.length() > 0) {
jtulach@1334
  1188
            result.append(string);
jtulach@1334
  1189
            for (int counter = 0, max = positions.length; counter < max;
jtulach@1334
  1190
                 counter++) {
jtulach@1334
  1191
                FieldPosition fp = positions[counter];
jtulach@1334
  1192
                Format.Field attribute = fp.getFieldAttribute();
jtulach@1334
  1193
jtulach@1334
  1194
                if (attribute == Field.SIGN) {
jtulach@1334
  1195
                    attribute = signAttribute;
jtulach@1334
  1196
                }
jtulach@1334
  1197
                delegate.formatted(attribute, attribute,
jtulach@1334
  1198
                                   start + fp.getBeginIndex(),
jtulach@1334
  1199
                                   start + fp.getEndIndex(), result);
jtulach@1334
  1200
            }
jtulach@1334
  1201
        }
jtulach@1334
  1202
    }
jtulach@1334
  1203
jtulach@1334
  1204
    /**
jtulach@1334
  1205
     * Parses text from a string to produce a <code>Number</code>.
jtulach@1334
  1206
     * <p>
jtulach@1334
  1207
     * The method attempts to parse text starting at the index given by
jtulach@1334
  1208
     * <code>pos</code>.
jtulach@1334
  1209
     * If parsing succeeds, then the index of <code>pos</code> is updated
jtulach@1334
  1210
     * to the index after the last character used (parsing does not necessarily
jtulach@1334
  1211
     * use all characters up to the end of the string), and the parsed
jtulach@1334
  1212
     * number is returned. The updated <code>pos</code> can be used to
jtulach@1334
  1213
     * indicate the starting point for the next call to this method.
jtulach@1334
  1214
     * If an error occurs, then the index of <code>pos</code> is not
jtulach@1334
  1215
     * changed, the error index of <code>pos</code> is set to the index of
jtulach@1334
  1216
     * the character where the error occurred, and null is returned.
jtulach@1334
  1217
     * <p>
jtulach@1334
  1218
     * The subclass returned depends on the value of {@link #isParseBigDecimal}
jtulach@1334
  1219
     * as well as on the string being parsed.
jtulach@1334
  1220
     * <ul>
jtulach@1334
  1221
     *   <li>If <code>isParseBigDecimal()</code> is false (the default),
jtulach@1334
  1222
     *       most integer values are returned as <code>Long</code>
jtulach@1334
  1223
     *       objects, no matter how they are written: <code>"17"</code> and
jtulach@1334
  1224
     *       <code>"17.000"</code> both parse to <code>Long(17)</code>.
jtulach@1334
  1225
     *       Values that cannot fit into a <code>Long</code> are returned as
jtulach@1334
  1226
     *       <code>Double</code>s. This includes values with a fractional part,
jtulach@1334
  1227
     *       infinite values, <code>NaN</code>, and the value -0.0.
jtulach@1334
  1228
     *       <code>DecimalFormat</code> does <em>not</em> decide whether to
jtulach@1334
  1229
     *       return a <code>Double</code> or a <code>Long</code> based on the
jtulach@1334
  1230
     *       presence of a decimal separator in the source string. Doing so
jtulach@1334
  1231
     *       would prevent integers that overflow the mantissa of a double,
jtulach@1334
  1232
     *       such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
jtulach@1334
  1233
     *       parsed accurately.
jtulach@1334
  1234
     *       <p>
jtulach@1334
  1235
     *       Callers may use the <code>Number</code> methods
jtulach@1334
  1236
     *       <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
jtulach@1334
  1237
     *       the type they want.
jtulach@1334
  1238
     *   <li>If <code>isParseBigDecimal()</code> is true, values are returned
jtulach@1334
  1239
     *       as <code>BigDecimal</code> objects. The values are the ones
jtulach@1334
  1240
     *       constructed by {@link java.math.BigDecimal#BigDecimal(String)}
jtulach@1334
  1241
     *       for corresponding strings in locale-independent format. The
jtulach@1334
  1242
     *       special cases negative and positive infinity and NaN are returned
jtulach@1334
  1243
     *       as <code>Double</code> instances holding the values of the
jtulach@1334
  1244
     *       corresponding <code>Double</code> constants.
jtulach@1334
  1245
     * </ul>
jtulach@1334
  1246
     * <p>
jtulach@1334
  1247
     * <code>DecimalFormat</code> parses all Unicode characters that represent
jtulach@1334
  1248
     * decimal digits, as defined by <code>Character.digit()</code>. In
jtulach@1334
  1249
     * addition, <code>DecimalFormat</code> also recognizes as digits the ten
jtulach@1334
  1250
     * consecutive characters starting with the localized zero digit defined in
jtulach@1334
  1251
     * the <code>DecimalFormatSymbols</code> object.
jtulach@1334
  1252
     *
jtulach@1334
  1253
     * @param text the string to be parsed
jtulach@1334
  1254
     * @param pos  A <code>ParsePosition</code> object with index and error
jtulach@1334
  1255
     *             index information as described above.
jtulach@1334
  1256
     * @return     the parsed value, or <code>null</code> if the parse fails
jtulach@1334
  1257
     * @exception  NullPointerException if <code>text</code> or
jtulach@1334
  1258
     *             <code>pos</code> is null.
jtulach@1334
  1259
     */
jtulach@1334
  1260
    public Number parse(String text, ParsePosition pos) {
jtulach@1334
  1261
        // special case NaN
jtulach@1334
  1262
        if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
jtulach@1334
  1263
            pos.index = pos.index + symbols.getNaN().length();
jtulach@1334
  1264
            return new Double(Double.NaN);
jtulach@1334
  1265
        }
jtulach@1334
  1266
jtulach@1334
  1267
        boolean[] status = new boolean[STATUS_LENGTH];
jtulach@1334
  1268
        if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
jtulach@1334
  1269
            return null;
jtulach@1334
  1270
        }
jtulach@1334
  1271
jtulach@1334
  1272
        // special case INFINITY
jtulach@1334
  1273
        if (status[STATUS_INFINITE]) {
jtulach@1334
  1274
            if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
jtulach@1334
  1275
                return new Double(Double.POSITIVE_INFINITY);
jtulach@1334
  1276
            } else {
jtulach@1334
  1277
                return new Double(Double.NEGATIVE_INFINITY);
jtulach@1334
  1278
            }
jtulach@1334
  1279
        }
jtulach@1334
  1280
jtulach@1334
  1281
        if (multiplier == 0) {
jtulach@1334
  1282
            if (digitList.isZero()) {
jtulach@1334
  1283
                return new Double(Double.NaN);
jtulach@1334
  1284
            } else if (status[STATUS_POSITIVE]) {
jtulach@1334
  1285
                return new Double(Double.POSITIVE_INFINITY);
jtulach@1334
  1286
            } else {
jtulach@1334
  1287
                return new Double(Double.NEGATIVE_INFINITY);
jtulach@1334
  1288
            }
jtulach@1334
  1289
        }
jtulach@1334
  1290
jtulach@1334
  1291
        if (isParseBigDecimal()) {
jtulach@1334
  1292
            BigDecimal bigDecimalResult = digitList.getBigDecimal();
jtulach@1334
  1293
jtulach@1334
  1294
            if (multiplier != 1) {
jtulach@1334
  1295
                try {
jtulach@1334
  1296
                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
jtulach@1334
  1297
                }
jtulach@1334
  1298
                catch (ArithmeticException e) {  // non-terminating decimal expansion
jtulach@1334
  1299
                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
jtulach@1334
  1300
                }
jtulach@1334
  1301
            }
jtulach@1334
  1302
jtulach@1334
  1303
            if (!status[STATUS_POSITIVE]) {
jtulach@1334
  1304
                bigDecimalResult = bigDecimalResult.negate();
jtulach@1334
  1305
            }
jtulach@1334
  1306
            return bigDecimalResult;
jtulach@1334
  1307
        } else {
jtulach@1334
  1308
            boolean gotDouble = true;
jtulach@1334
  1309
            boolean gotLongMinimum = false;
jtulach@1334
  1310
            double  doubleResult = 0.0;
jtulach@1334
  1311
            long    longResult = 0;
jtulach@1334
  1312
jtulach@1334
  1313
            // Finally, have DigitList parse the digits into a value.
jtulach@1334
  1314
            if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
jtulach@1334
  1315
                gotDouble = false;
jtulach@1334
  1316
                longResult = digitList.getLong();
jtulach@1334
  1317
                if (longResult < 0) {  // got Long.MIN_VALUE
jtulach@1334
  1318
                    gotLongMinimum = true;
jtulach@1334
  1319
                }
jtulach@1334
  1320
            } else {
jtulach@1334
  1321
                doubleResult = digitList.getDouble();
jtulach@1334
  1322
            }
jtulach@1334
  1323
jtulach@1334
  1324
            // Divide by multiplier. We have to be careful here not to do
jtulach@1334
  1325
            // unneeded conversions between double and long.
jtulach@1334
  1326
            if (multiplier != 1) {
jtulach@1334
  1327
                if (gotDouble) {
jtulach@1334
  1328
                    doubleResult /= multiplier;
jtulach@1334
  1329
                } else {
jtulach@1334
  1330
                    // Avoid converting to double if we can
jtulach@1334
  1331
                    if (longResult % multiplier == 0) {
jtulach@1334
  1332
                        longResult /= multiplier;
jtulach@1334
  1333
                    } else {
jtulach@1334
  1334
                        doubleResult = ((double)longResult) / multiplier;
jtulach@1334
  1335
                        gotDouble = true;
jtulach@1334
  1336
                    }
jtulach@1334
  1337
                }
jtulach@1334
  1338
            }
jtulach@1334
  1339
jtulach@1334
  1340
            if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
jtulach@1334
  1341
                doubleResult = -doubleResult;
jtulach@1334
  1342
                longResult = -longResult;
jtulach@1334
  1343
            }
jtulach@1334
  1344
jtulach@1334
  1345
            // At this point, if we divided the result by the multiplier, the
jtulach@1334
  1346
            // result may fit into a long.  We check for this case and return
jtulach@1334
  1347
            // a long if possible.
jtulach@1334
  1348
            // We must do this AFTER applying the negative (if appropriate)
jtulach@1334
  1349
            // in order to handle the case of LONG_MIN; otherwise, if we do
jtulach@1334
  1350
            // this with a positive value -LONG_MIN, the double is > 0, but
jtulach@1334
  1351
            // the long is < 0. We also must retain a double in the case of
jtulach@1334
  1352
            // -0.0, which will compare as == to a long 0 cast to a double
jtulach@1334
  1353
            // (bug 4162852).
jtulach@1334
  1354
            if (multiplier != 1 && gotDouble) {
jtulach@1334
  1355
                longResult = (long)doubleResult;
jtulach@1334
  1356
                gotDouble = ((doubleResult != (double)longResult) ||
jtulach@1334
  1357
                            (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
jtulach@1334
  1358
                            !isParseIntegerOnly();
jtulach@1334
  1359
            }
jtulach@1334
  1360
jtulach@1334
  1361
            return gotDouble ?
jtulach@1334
  1362
                (Number)new Double(doubleResult) : (Number)new Long(longResult);
jtulach@1334
  1363
        }
jtulach@1334
  1364
    }
jtulach@1334
  1365
jtulach@1334
  1366
    /**
jtulach@1334
  1367
     * Return a BigInteger multiplier.
jtulach@1334
  1368
     */
jtulach@1334
  1369
    private BigInteger getBigIntegerMultiplier() {
jtulach@1334
  1370
        if (bigIntegerMultiplier == null) {
jtulach@1334
  1371
            bigIntegerMultiplier = BigInteger.valueOf(multiplier);
jtulach@1334
  1372
        }
jtulach@1334
  1373
        return bigIntegerMultiplier;
jtulach@1334
  1374
    }
jtulach@1334
  1375
    private transient BigInteger bigIntegerMultiplier;
jtulach@1334
  1376
jtulach@1334
  1377
    /**
jtulach@1334
  1378
     * Return a BigDecimal multiplier.
jtulach@1334
  1379
     */
jtulach@1334
  1380
    private BigDecimal getBigDecimalMultiplier() {
jtulach@1334
  1381
        if (bigDecimalMultiplier == null) {
jtulach@1334
  1382
            bigDecimalMultiplier = new BigDecimal(multiplier);
jtulach@1334
  1383
        }
jtulach@1334
  1384
        return bigDecimalMultiplier;
jtulach@1334
  1385
    }
jtulach@1334
  1386
    private transient BigDecimal bigDecimalMultiplier;
jtulach@1334
  1387
jtulach@1334
  1388
    private static final int STATUS_INFINITE = 0;
jtulach@1334
  1389
    private static final int STATUS_POSITIVE = 1;
jtulach@1334
  1390
    private static final int STATUS_LENGTH   = 2;
jtulach@1334
  1391
jtulach@1334
  1392
    /**
jtulach@1334
  1393
     * Parse the given text into a number.  The text is parsed beginning at
jtulach@1334
  1394
     * parsePosition, until an unparseable character is seen.
jtulach@1334
  1395
     * @param text The string to parse.
jtulach@1334
  1396
     * @param parsePosition The position at which to being parsing.  Upon
jtulach@1334
  1397
     * return, the first unparseable character.
jtulach@1334
  1398
     * @param digits The DigitList to set to the parsed value.
jtulach@1334
  1399
     * @param isExponent If true, parse an exponent.  This means no
jtulach@1334
  1400
     * infinite values and integer only.
jtulach@1334
  1401
     * @param status Upon return contains boolean status flags indicating
jtulach@1334
  1402
     * whether the value was infinite and whether it was positive.
jtulach@1334
  1403
     */
jtulach@1334
  1404
    private final boolean subparse(String text, ParsePosition parsePosition,
jtulach@1334
  1405
                   String positivePrefix, String negativePrefix,
jtulach@1334
  1406
                   DigitList digits, boolean isExponent,
jtulach@1334
  1407
                   boolean status[]) {
jtulach@1334
  1408
        int position = parsePosition.index;
jtulach@1334
  1409
        int oldStart = parsePosition.index;
jtulach@1334
  1410
        int backup;
jtulach@1334
  1411
        boolean gotPositive, gotNegative;
jtulach@1334
  1412
jtulach@1334
  1413
        // check for positivePrefix; take longest
jtulach@1334
  1414
        gotPositive = text.regionMatches(position, positivePrefix, 0,
jtulach@1334
  1415
                                         positivePrefix.length());
jtulach@1334
  1416
        gotNegative = text.regionMatches(position, negativePrefix, 0,
jtulach@1334
  1417
                                         negativePrefix.length());
jtulach@1334
  1418
jtulach@1334
  1419
        if (gotPositive && gotNegative) {
jtulach@1334
  1420
            if (positivePrefix.length() > negativePrefix.length()) {
jtulach@1334
  1421
                gotNegative = false;
jtulach@1334
  1422
            } else if (positivePrefix.length() < negativePrefix.length()) {
jtulach@1334
  1423
                gotPositive = false;
jtulach@1334
  1424
            }
jtulach@1334
  1425
        }
jtulach@1334
  1426
jtulach@1334
  1427
        if (gotPositive) {
jtulach@1334
  1428
            position += positivePrefix.length();
jtulach@1334
  1429
        } else if (gotNegative) {
jtulach@1334
  1430
            position += negativePrefix.length();
jtulach@1334
  1431
        } else {
jtulach@1334
  1432
            parsePosition.errorIndex = position;
jtulach@1334
  1433
            return false;
jtulach@1334
  1434
        }
jtulach@1334
  1435
jtulach@1334
  1436
        // process digits or Inf, find decimal position
jtulach@1334
  1437
        status[STATUS_INFINITE] = false;
jtulach@1334
  1438
        if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
jtulach@1334
  1439
                          symbols.getInfinity().length())) {
jtulach@1334
  1440
            position += symbols.getInfinity().length();
jtulach@1334
  1441
            status[STATUS_INFINITE] = true;
jtulach@1334
  1442
        } else {
jtulach@1334
  1443
            // We now have a string of digits, possibly with grouping symbols,
jtulach@1334
  1444
            // and decimal points.  We want to process these into a DigitList.
jtulach@1334
  1445
            // We don't want to put a bunch of leading zeros into the DigitList
jtulach@1334
  1446
            // though, so we keep track of the location of the decimal point,
jtulach@1334
  1447
            // put only significant digits into the DigitList, and adjust the
jtulach@1334
  1448
            // exponent as needed.
jtulach@1334
  1449
jtulach@1334
  1450
            digits.decimalAt = digits.count = 0;
jtulach@1334
  1451
            char zero = symbols.getZeroDigit();
jtulach@1334
  1452
            char decimal = isCurrencyFormat ?
jtulach@1334
  1453
                symbols.getMonetaryDecimalSeparator() :
jtulach@1334
  1454
                symbols.getDecimalSeparator();
jtulach@1334
  1455
            char grouping = symbols.getGroupingSeparator();
jtulach@1334
  1456
            String exponentString = symbols.getExponentSeparator();
jtulach@1334
  1457
            boolean sawDecimal = false;
jtulach@1334
  1458
            boolean sawExponent = false;
jtulach@1334
  1459
            boolean sawDigit = false;
jtulach@1334
  1460
            int exponent = 0; // Set to the exponent value, if any
jtulach@1334
  1461
jtulach@1334
  1462
            // We have to track digitCount ourselves, because digits.count will
jtulach@1334
  1463
            // pin when the maximum allowable digits is reached.
jtulach@1334
  1464
            int digitCount = 0;
jtulach@1334
  1465
jtulach@1334
  1466
            backup = -1;
jtulach@1334
  1467
            for (; position < text.length(); ++position) {
jtulach@1334
  1468
                char ch = text.charAt(position);
jtulach@1334
  1469
jtulach@1334
  1470
                /* We recognize all digit ranges, not only the Latin digit range
jtulach@1334
  1471
                 * '0'..'9'.  We do so by using the Character.digit() method,
jtulach@1334
  1472
                 * which converts a valid Unicode digit to the range 0..9.
jtulach@1334
  1473
                 *
jtulach@1334
  1474
                 * The character 'ch' may be a digit.  If so, place its value
jtulach@1334
  1475
                 * from 0 to 9 in 'digit'.  First try using the locale digit,
jtulach@1334
  1476
                 * which may or MAY NOT be a standard Unicode digit range.  If
jtulach@1334
  1477
                 * this fails, try using the standard Unicode digit ranges by
jtulach@1334
  1478
                 * calling Character.digit().  If this also fails, digit will
jtulach@1334
  1479
                 * have a value outside the range 0..9.
jtulach@1334
  1480
                 */
jtulach@1334
  1481
                int digit = ch - zero;
jtulach@1334
  1482
                if (digit < 0 || digit > 9) {
jtulach@1334
  1483
                    digit = Character.digit(ch, 10);
jtulach@1334
  1484
                }
jtulach@1334
  1485
jtulach@1334
  1486
                if (digit == 0) {
jtulach@1334
  1487
                    // Cancel out backup setting (see grouping handler below)
jtulach@1334
  1488
                    backup = -1; // Do this BEFORE continue statement below!!!
jtulach@1334
  1489
                    sawDigit = true;
jtulach@1334
  1490
jtulach@1334
  1491
                    // Handle leading zeros
jtulach@1334
  1492
                    if (digits.count == 0) {
jtulach@1334
  1493
                        // Ignore leading zeros in integer part of number.
jtulach@1334
  1494
                        if (!sawDecimal) {
jtulach@1334
  1495
                            continue;
jtulach@1334
  1496
                        }
jtulach@1334
  1497
jtulach@1334
  1498
                        // If we have seen the decimal, but no significant
jtulach@1334
  1499
                        // digits yet, then we account for leading zeros by
jtulach@1334
  1500
                        // decrementing the digits.decimalAt into negative
jtulach@1334
  1501
                        // values.
jtulach@1334
  1502
                        --digits.decimalAt;
jtulach@1334
  1503
                    } else {
jtulach@1334
  1504
                        ++digitCount;
jtulach@1334
  1505
                        digits.append((char)(digit + '0'));
jtulach@1334
  1506
                    }
jtulach@1334
  1507
                } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
jtulach@1334
  1508
                    sawDigit = true;
jtulach@1334
  1509
                    ++digitCount;
jtulach@1334
  1510
                    digits.append((char)(digit + '0'));
jtulach@1334
  1511
jtulach@1334
  1512
                    // Cancel out backup setting (see grouping handler below)
jtulach@1334
  1513
                    backup = -1;
jtulach@1334
  1514
                } else if (!isExponent && ch == decimal) {
jtulach@1334
  1515
                    // If we're only parsing integers, or if we ALREADY saw the
jtulach@1334
  1516
                    // decimal, then don't parse this one.
jtulach@1334
  1517
                    if (isParseIntegerOnly() || sawDecimal) {
jtulach@1334
  1518
                        break;
jtulach@1334
  1519
                    }
jtulach@1334
  1520
                    digits.decimalAt = digitCount; // Not digits.count!
jtulach@1334
  1521
                    sawDecimal = true;
jtulach@1334
  1522
                } else if (!isExponent && ch == grouping && isGroupingUsed()) {
jtulach@1334
  1523
                    if (sawDecimal) {
jtulach@1334
  1524
                        break;
jtulach@1334
  1525
                    }
jtulach@1334
  1526
                    // Ignore grouping characters, if we are using them, but
jtulach@1334
  1527
                    // require that they be followed by a digit.  Otherwise
jtulach@1334
  1528
                    // we backup and reprocess them.
jtulach@1334
  1529
                    backup = position;
jtulach@1334
  1530
                } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
jtulach@1334
  1531
                             && !sawExponent) {
jtulach@1334
  1532
                    // Process the exponent by recursively calling this method.
jtulach@1334
  1533
                     ParsePosition pos = new ParsePosition(position + exponentString.length());
jtulach@1334
  1534
                    boolean[] stat = new boolean[STATUS_LENGTH];
jtulach@1334
  1535
                    DigitList exponentDigits = new DigitList();
jtulach@1334
  1536
jtulach@1334
  1537
                    if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
jtulach@1334
  1538
                        exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
jtulach@1334
  1539
                        position = pos.index; // Advance past the exponent
jtulach@1334
  1540
                        exponent = (int)exponentDigits.getLong();
jtulach@1334
  1541
                        if (!stat[STATUS_POSITIVE]) {
jtulach@1334
  1542
                            exponent = -exponent;
jtulach@1334
  1543
                        }
jtulach@1334
  1544
                        sawExponent = true;
jtulach@1334
  1545
                    }
jtulach@1334
  1546
                    break; // Whether we fail or succeed, we exit this loop
jtulach@1334
  1547
                }
jtulach@1334
  1548
                else {
jtulach@1334
  1549
                    break;
jtulach@1334
  1550
                }
jtulach@1334
  1551
            }
jtulach@1334
  1552
jtulach@1334
  1553
            if (backup != -1) {
jtulach@1334
  1554
                position = backup;
jtulach@1334
  1555
            }
jtulach@1334
  1556
jtulach@1334
  1557
            // If there was no decimal point we have an integer
jtulach@1334
  1558
            if (!sawDecimal) {
jtulach@1334
  1559
                digits.decimalAt = digitCount; // Not digits.count!
jtulach@1334
  1560
            }
jtulach@1334
  1561
jtulach@1334
  1562
            // Adjust for exponent, if any
jtulach@1334
  1563
            digits.decimalAt += exponent;
jtulach@1334
  1564
jtulach@1334
  1565
            // If none of the text string was recognized.  For example, parse
jtulach@1334
  1566
            // "x" with pattern "#0.00" (return index and error index both 0)
jtulach@1334
  1567
            // parse "$" with pattern "$#0.00". (return index 0 and error
jtulach@1334
  1568
            // index 1).
jtulach@1334
  1569
            if (!sawDigit && digitCount == 0) {
jtulach@1334
  1570
                parsePosition.index = oldStart;
jtulach@1334
  1571
                parsePosition.errorIndex = oldStart;
jtulach@1334
  1572
                return false;
jtulach@1334
  1573
            }
jtulach@1334
  1574
        }
jtulach@1334
  1575
jtulach@1334
  1576
        // check for suffix
jtulach@1334
  1577
        if (!isExponent) {
jtulach@1334
  1578
            if (gotPositive) {
jtulach@1334
  1579
                gotPositive = text.regionMatches(position,positiveSuffix,0,
jtulach@1334
  1580
                                                 positiveSuffix.length());
jtulach@1334
  1581
            }
jtulach@1334
  1582
            if (gotNegative) {
jtulach@1334
  1583
                gotNegative = text.regionMatches(position,negativeSuffix,0,
jtulach@1334
  1584
                                                 negativeSuffix.length());
jtulach@1334
  1585
            }
jtulach@1334
  1586
jtulach@1334
  1587
        // if both match, take longest
jtulach@1334
  1588
        if (gotPositive && gotNegative) {
jtulach@1334
  1589
            if (positiveSuffix.length() > negativeSuffix.length()) {
jtulach@1334
  1590
                gotNegative = false;
jtulach@1334
  1591
            } else if (positiveSuffix.length() < negativeSuffix.length()) {
jtulach@1334
  1592
                gotPositive = false;
jtulach@1334
  1593
            }
jtulach@1334
  1594
        }
jtulach@1334
  1595
jtulach@1334
  1596
        // fail if neither or both
jtulach@1334
  1597
        if (gotPositive == gotNegative) {
jtulach@1334
  1598
            parsePosition.errorIndex = position;
jtulach@1334
  1599
            return false;
jtulach@1334
  1600
        }
jtulach@1334
  1601
jtulach@1334
  1602
        parsePosition.index = position +
jtulach@1334
  1603
            (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
jtulach@1334
  1604
        } else {
jtulach@1334
  1605
            parsePosition.index = position;
jtulach@1334
  1606
        }
jtulach@1334
  1607
jtulach@1334
  1608
        status[STATUS_POSITIVE] = gotPositive;
jtulach@1334
  1609
        if (parsePosition.index == oldStart) {
jtulach@1334
  1610
            parsePosition.errorIndex = position;
jtulach@1334
  1611
            return false;
jtulach@1334
  1612
        }
jtulach@1334
  1613
        return true;
jtulach@1334
  1614
    }
jtulach@1334
  1615
jtulach@1334
  1616
    /**
jtulach@1334
  1617
     * Returns a copy of the decimal format symbols, which is generally not
jtulach@1334
  1618
     * changed by the programmer or user.
jtulach@1334
  1619
     * @return a copy of the desired DecimalFormatSymbols
jtulach@1334
  1620
     * @see java.text.DecimalFormatSymbols
jtulach@1334
  1621
     */
jtulach@1334
  1622
    public DecimalFormatSymbols getDecimalFormatSymbols() {
jtulach@1334
  1623
        try {
jtulach@1334
  1624
            // don't allow multiple references
jtulach@1334
  1625
            return (DecimalFormatSymbols) symbols.clone();
jtulach@1334
  1626
        } catch (Exception foo) {
jtulach@1334
  1627
            return null; // should never happen
jtulach@1334
  1628
        }
jtulach@1334
  1629
    }
jtulach@1334
  1630
jtulach@1334
  1631
jtulach@1334
  1632
    /**
jtulach@1334
  1633
     * Sets the decimal format symbols, which is generally not changed
jtulach@1334
  1634
     * by the programmer or user.
jtulach@1334
  1635
     * @param newSymbols desired DecimalFormatSymbols
jtulach@1334
  1636
     * @see java.text.DecimalFormatSymbols
jtulach@1334
  1637
     */
jtulach@1334
  1638
    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
jtulach@1334
  1639
        try {
jtulach@1334
  1640
            // don't allow multiple references
jtulach@1334
  1641
            symbols = (DecimalFormatSymbols) newSymbols.clone();
jtulach@1334
  1642
            expandAffixes();
jtulach@1334
  1643
        } catch (Exception foo) {
jtulach@1334
  1644
            // should never happen
jtulach@1334
  1645
        }
jtulach@1334
  1646
    }
jtulach@1334
  1647
jtulach@1334
  1648
    /**
jtulach@1334
  1649
     * Get the positive prefix.
jtulach@1334
  1650
     * <P>Examples: +123, $123, sFr123
jtulach@1334
  1651
     */
jtulach@1334
  1652
    public String getPositivePrefix () {
jtulach@1334
  1653
        return positivePrefix;
jtulach@1334
  1654
    }
jtulach@1334
  1655
jtulach@1334
  1656
    /**
jtulach@1334
  1657
     * Set the positive prefix.
jtulach@1334
  1658
     * <P>Examples: +123, $123, sFr123
jtulach@1334
  1659
     */
jtulach@1334
  1660
    public void setPositivePrefix (String newValue) {
jtulach@1334
  1661
        positivePrefix = newValue;
jtulach@1334
  1662
        posPrefixPattern = null;
jtulach@1334
  1663
        positivePrefixFieldPositions = null;
jtulach@1334
  1664
    }
jtulach@1334
  1665
jtulach@1334
  1666
    /**
jtulach@1334
  1667
     * Returns the FieldPositions of the fields in the prefix used for
jtulach@1334
  1668
     * positive numbers. This is not used if the user has explicitly set
jtulach@1334
  1669
     * a positive prefix via <code>setPositivePrefix</code>. This is
jtulach@1334
  1670
     * lazily created.
jtulach@1334
  1671
     *
jtulach@1334
  1672
     * @return FieldPositions in positive prefix
jtulach@1334
  1673
     */
jtulach@1334
  1674
    private FieldPosition[] getPositivePrefixFieldPositions() {
jtulach@1334
  1675
        if (positivePrefixFieldPositions == null) {
jtulach@1334
  1676
            if (posPrefixPattern != null) {
jtulach@1334
  1677
                positivePrefixFieldPositions = expandAffix(posPrefixPattern);
jtulach@1334
  1678
            }
jtulach@1334
  1679
            else {
jtulach@1334
  1680
                positivePrefixFieldPositions = EmptyFieldPositionArray;
jtulach@1334
  1681
            }
jtulach@1334
  1682
        }
jtulach@1334
  1683
        return positivePrefixFieldPositions;
jtulach@1334
  1684
    }
jtulach@1334
  1685
jtulach@1334
  1686
    /**
jtulach@1334
  1687
     * Get the negative prefix.
jtulach@1334
  1688
     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
jtulach@1334
  1689
     */
jtulach@1334
  1690
    public String getNegativePrefix () {
jtulach@1334
  1691
        return negativePrefix;
jtulach@1334
  1692
    }
jtulach@1334
  1693
jtulach@1334
  1694
    /**
jtulach@1334
  1695
     * Set the negative prefix.
jtulach@1334
  1696
     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
jtulach@1334
  1697
     */
jtulach@1334
  1698
    public void setNegativePrefix (String newValue) {
jtulach@1334
  1699
        negativePrefix = newValue;
jtulach@1334
  1700
        negPrefixPattern = null;
jtulach@1334
  1701
    }
jtulach@1334
  1702
jtulach@1334
  1703
    /**
jtulach@1334
  1704
     * Returns the FieldPositions of the fields in the prefix used for
jtulach@1334
  1705
     * negative numbers. This is not used if the user has explicitly set
jtulach@1334
  1706
     * a negative prefix via <code>setNegativePrefix</code>. This is
jtulach@1334
  1707
     * lazily created.
jtulach@1334
  1708
     *
jtulach@1334
  1709
     * @return FieldPositions in positive prefix
jtulach@1334
  1710
     */
jtulach@1334
  1711
    private FieldPosition[] getNegativePrefixFieldPositions() {
jtulach@1334
  1712
        if (negativePrefixFieldPositions == null) {
jtulach@1334
  1713
            if (negPrefixPattern != null) {
jtulach@1334
  1714
                negativePrefixFieldPositions = expandAffix(negPrefixPattern);
jtulach@1334
  1715
            }
jtulach@1334
  1716
            else {
jtulach@1334
  1717
                negativePrefixFieldPositions = EmptyFieldPositionArray;
jtulach@1334
  1718
            }
jtulach@1334
  1719
        }
jtulach@1334
  1720
        return negativePrefixFieldPositions;
jtulach@1334
  1721
    }
jtulach@1334
  1722
jtulach@1334
  1723
    /**
jtulach@1334
  1724
     * Get the positive suffix.
jtulach@1334
  1725
     * <P>Example: 123%
jtulach@1334
  1726
     */
jtulach@1334
  1727
    public String getPositiveSuffix () {
jtulach@1334
  1728
        return positiveSuffix;
jtulach@1334
  1729
    }
jtulach@1334
  1730
jtulach@1334
  1731
    /**
jtulach@1334
  1732
     * Set the positive suffix.
jtulach@1334
  1733
     * <P>Example: 123%
jtulach@1334
  1734
     */
jtulach@1334
  1735
    public void setPositiveSuffix (String newValue) {
jtulach@1334
  1736
        positiveSuffix = newValue;
jtulach@1334
  1737
        posSuffixPattern = null;
jtulach@1334
  1738
    }
jtulach@1334
  1739
jtulach@1334
  1740
    /**
jtulach@1334
  1741
     * Returns the FieldPositions of the fields in the suffix used for
jtulach@1334
  1742
     * positive numbers. This is not used if the user has explicitly set
jtulach@1334
  1743
     * a positive suffix via <code>setPositiveSuffix</code>. This is
jtulach@1334
  1744
     * lazily created.
jtulach@1334
  1745
     *
jtulach@1334
  1746
     * @return FieldPositions in positive prefix
jtulach@1334
  1747
     */
jtulach@1334
  1748
    private FieldPosition[] getPositiveSuffixFieldPositions() {
jtulach@1334
  1749
        if (positiveSuffixFieldPositions == null) {
jtulach@1334
  1750
            if (posSuffixPattern != null) {
jtulach@1334
  1751
                positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
jtulach@1334
  1752
            }
jtulach@1334
  1753
            else {
jtulach@1334
  1754
                positiveSuffixFieldPositions = EmptyFieldPositionArray;
jtulach@1334
  1755
            }
jtulach@1334
  1756
        }
jtulach@1334
  1757
        return positiveSuffixFieldPositions;
jtulach@1334
  1758
    }
jtulach@1334
  1759
jtulach@1334
  1760
    /**
jtulach@1334
  1761
     * Get the negative suffix.
jtulach@1334
  1762
     * <P>Examples: -123%, ($123) (with positive suffixes)
jtulach@1334
  1763
     */
jtulach@1334
  1764
    public String getNegativeSuffix () {
jtulach@1334
  1765
        return negativeSuffix;
jtulach@1334
  1766
    }
jtulach@1334
  1767
jtulach@1334
  1768
    /**
jtulach@1334
  1769
     * Set the negative suffix.
jtulach@1334
  1770
     * <P>Examples: 123%
jtulach@1334
  1771
     */
jtulach@1334
  1772
    public void setNegativeSuffix (String newValue) {
jtulach@1334
  1773
        negativeSuffix = newValue;
jtulach@1334
  1774
        negSuffixPattern = null;
jtulach@1334
  1775
    }
jtulach@1334
  1776
jtulach@1334
  1777
    /**
jtulach@1334
  1778
     * Returns the FieldPositions of the fields in the suffix used for
jtulach@1334
  1779
     * negative numbers. This is not used if the user has explicitly set
jtulach@1334
  1780
     * a negative suffix via <code>setNegativeSuffix</code>. This is
jtulach@1334
  1781
     * lazily created.
jtulach@1334
  1782
     *
jtulach@1334
  1783
     * @return FieldPositions in positive prefix
jtulach@1334
  1784
     */
jtulach@1334
  1785
    private FieldPosition[] getNegativeSuffixFieldPositions() {
jtulach@1334
  1786
        if (negativeSuffixFieldPositions == null) {
jtulach@1334
  1787
            if (negSuffixPattern != null) {
jtulach@1334
  1788
                negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
jtulach@1334
  1789
            }
jtulach@1334
  1790
            else {
jtulach@1334
  1791
                negativeSuffixFieldPositions = EmptyFieldPositionArray;
jtulach@1334
  1792
            }
jtulach@1334
  1793
        }
jtulach@1334
  1794
        return negativeSuffixFieldPositions;
jtulach@1334
  1795
    }
jtulach@1334
  1796
jtulach@1334
  1797
    /**
jtulach@1334
  1798
     * Gets the multiplier for use in percent, per mille, and similar
jtulach@1334
  1799
     * formats.
jtulach@1334
  1800
     *
jtulach@1334
  1801
     * @see #setMultiplier(int)
jtulach@1334
  1802
     */
jtulach@1334
  1803
    public int getMultiplier () {
jtulach@1334
  1804
        return multiplier;
jtulach@1334
  1805
    }
jtulach@1334
  1806
jtulach@1334
  1807
    /**
jtulach@1334
  1808
     * Sets the multiplier for use in percent, per mille, and similar
jtulach@1334
  1809
     * formats.
jtulach@1334
  1810
     * For a percent format, set the multiplier to 100 and the suffixes to
jtulach@1334
  1811
     * have '%' (for Arabic, use the Arabic percent sign).
jtulach@1334
  1812
     * For a per mille format, set the multiplier to 1000 and the suffixes to
jtulach@1334
  1813
     * have '&#92;u2030'.
jtulach@1334
  1814
     *
jtulach@1334
  1815
     * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
jtulach@1334
  1816
     * "123" is parsed into 1.23.
jtulach@1334
  1817
     *
jtulach@1334
  1818
     * @see #getMultiplier
jtulach@1334
  1819
     */
jtulach@1334
  1820
    public void setMultiplier (int newValue) {
jtulach@1334
  1821
        multiplier = newValue;
jtulach@1334
  1822
        bigDecimalMultiplier = null;
jtulach@1334
  1823
        bigIntegerMultiplier = null;
jtulach@1334
  1824
    }
jtulach@1334
  1825
jtulach@1334
  1826
    /**
jtulach@1334
  1827
     * Return the grouping size. Grouping size is the number of digits between
jtulach@1334
  1828
     * grouping separators in the integer portion of a number.  For example,
jtulach@1334
  1829
     * in the number "123,456.78", the grouping size is 3.
jtulach@1334
  1830
     * @see #setGroupingSize
jtulach@1334
  1831
     * @see java.text.NumberFormat#isGroupingUsed
jtulach@1334
  1832
     * @see java.text.DecimalFormatSymbols#getGroupingSeparator
jtulach@1334
  1833
     */
jtulach@1334
  1834
    public int getGroupingSize () {
jtulach@1334
  1835
        return groupingSize;
jtulach@1334
  1836
    }
jtulach@1334
  1837
jtulach@1334
  1838
    /**
jtulach@1334
  1839
     * Set the grouping size. Grouping size is the number of digits between
jtulach@1334
  1840
     * grouping separators in the integer portion of a number.  For example,
jtulach@1334
  1841
     * in the number "123,456.78", the grouping size is 3.
jtulach@1334
  1842
     * <br>
jtulach@1334
  1843
     * The value passed in is converted to a byte, which may lose information.
jtulach@1334
  1844
     * @see #getGroupingSize
jtulach@1334
  1845
     * @see java.text.NumberFormat#setGroupingUsed
jtulach@1334
  1846
     * @see java.text.DecimalFormatSymbols#setGroupingSeparator
jtulach@1334
  1847
     */
jtulach@1334
  1848
    public void setGroupingSize (int newValue) {
jtulach@1334
  1849
        groupingSize = (byte)newValue;
jtulach@1334
  1850
    }
jtulach@1334
  1851
jtulach@1334
  1852
    /**
jtulach@1334
  1853
     * Allows you to get the behavior of the decimal separator with integers.
jtulach@1334
  1854
     * (The decimal separator will always appear with decimals.)
jtulach@1334
  1855
     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
jtulach@1334
  1856
     */
jtulach@1334
  1857
    public boolean isDecimalSeparatorAlwaysShown() {
jtulach@1334
  1858
        return decimalSeparatorAlwaysShown;
jtulach@1334
  1859
    }
jtulach@1334
  1860
jtulach@1334
  1861
    /**
jtulach@1334
  1862
     * Allows you to set the behavior of the decimal separator with integers.
jtulach@1334
  1863
     * (The decimal separator will always appear with decimals.)
jtulach@1334
  1864
     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
jtulach@1334
  1865
     */
jtulach@1334
  1866
    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
jtulach@1334
  1867
        decimalSeparatorAlwaysShown = newValue;
jtulach@1334
  1868
    }
jtulach@1334
  1869
jtulach@1334
  1870
    /**
jtulach@1334
  1871
     * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
jtulach@1334
  1872
     * method returns <code>BigDecimal</code>. The default value is false.
jtulach@1334
  1873
     * @see #setParseBigDecimal
jtulach@1334
  1874
     * @since 1.5
jtulach@1334
  1875
     */
jtulach@1334
  1876
    public boolean isParseBigDecimal() {
jtulach@1334
  1877
        return parseBigDecimal;
jtulach@1334
  1878
    }
jtulach@1334
  1879
jtulach@1334
  1880
    /**
jtulach@1334
  1881
     * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
jtulach@1334
  1882
     * method returns <code>BigDecimal</code>.
jtulach@1334
  1883
     * @see #isParseBigDecimal
jtulach@1334
  1884
     * @since 1.5
jtulach@1334
  1885
     */
jtulach@1334
  1886
    public void setParseBigDecimal(boolean newValue) {
jtulach@1334
  1887
        parseBigDecimal = newValue;
jtulach@1334
  1888
    }
jtulach@1334
  1889
jtulach@1334
  1890
    /**
jtulach@1334
  1891
     * Standard override; no change in semantics.
jtulach@1334
  1892
     */
jtulach@1334
  1893
    public Object clone() {
jtulach@1334
  1894
        try {
jtulach@1334
  1895
            DecimalFormat other = (DecimalFormat) super.clone();
jtulach@1334
  1896
            other.symbols = (DecimalFormatSymbols) symbols.clone();
jtulach@1334
  1897
            other.digitList = (DigitList) digitList.clone();
jtulach@1334
  1898
            return other;
jtulach@1334
  1899
        } catch (Exception e) {
jtulach@1334
  1900
            throw new InternalError();
jtulach@1334
  1901
        }
jtulach@1334
  1902
    }
jtulach@1334
  1903
jtulach@1334
  1904
    /**
jtulach@1334
  1905
     * Overrides equals
jtulach@1334
  1906
     */
jtulach@1334
  1907
    public boolean equals(Object obj)
jtulach@1334
  1908
    {
jtulach@1334
  1909
        if (obj == null) return false;
jtulach@1334
  1910
        if (!super.equals(obj)) return false; // super does class check
jtulach@1334
  1911
        DecimalFormat other = (DecimalFormat) obj;
jtulach@1334
  1912
        return ((posPrefixPattern == other.posPrefixPattern &&
jtulach@1334
  1913
                 positivePrefix.equals(other.positivePrefix))
jtulach@1334
  1914
                || (posPrefixPattern != null &&
jtulach@1334
  1915
                    posPrefixPattern.equals(other.posPrefixPattern)))
jtulach@1334
  1916
            && ((posSuffixPattern == other.posSuffixPattern &&
jtulach@1334
  1917
                 positiveSuffix.equals(other.positiveSuffix))
jtulach@1334
  1918
                || (posSuffixPattern != null &&
jtulach@1334
  1919
                    posSuffixPattern.equals(other.posSuffixPattern)))
jtulach@1334
  1920
            && ((negPrefixPattern == other.negPrefixPattern &&
jtulach@1334
  1921
                 negativePrefix.equals(other.negativePrefix))
jtulach@1334
  1922
                || (negPrefixPattern != null &&
jtulach@1334
  1923
                    negPrefixPattern.equals(other.negPrefixPattern)))
jtulach@1334
  1924
            && ((negSuffixPattern == other.negSuffixPattern &&
jtulach@1334
  1925
                 negativeSuffix.equals(other.negativeSuffix))
jtulach@1334
  1926
                || (negSuffixPattern != null &&
jtulach@1334
  1927
                    negSuffixPattern.equals(other.negSuffixPattern)))
jtulach@1334
  1928
            && multiplier == other.multiplier
jtulach@1334
  1929
            && groupingSize == other.groupingSize
jtulach@1334
  1930
            && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
jtulach@1334
  1931
            && parseBigDecimal == other.parseBigDecimal
jtulach@1334
  1932
            && useExponentialNotation == other.useExponentialNotation
jtulach@1334
  1933
            && (!useExponentialNotation ||
jtulach@1334
  1934
                minExponentDigits == other.minExponentDigits)
jtulach@1334
  1935
            && maximumIntegerDigits == other.maximumIntegerDigits
jtulach@1334
  1936
            && minimumIntegerDigits == other.minimumIntegerDigits
jtulach@1334
  1937
            && maximumFractionDigits == other.maximumFractionDigits
jtulach@1334
  1938
            && minimumFractionDigits == other.minimumFractionDigits
jtulach@1334
  1939
            && roundingMode == other.roundingMode
jtulach@1334
  1940
            && symbols.equals(other.symbols);
jtulach@1334
  1941
    }
jtulach@1334
  1942
jtulach@1334
  1943
    /**
jtulach@1334
  1944
     * Overrides hashCode
jtulach@1334
  1945
     */
jtulach@1334
  1946
    public int hashCode() {
jtulach@1334
  1947
        return super.hashCode() * 37 + positivePrefix.hashCode();
jtulach@1334
  1948
        // just enough fields for a reasonable distribution
jtulach@1334
  1949
    }
jtulach@1334
  1950
jtulach@1334
  1951
    /**
jtulach@1334
  1952
     * Synthesizes a pattern string that represents the current state
jtulach@1334
  1953
     * of this Format object.
jtulach@1334
  1954
     * @see #applyPattern
jtulach@1334
  1955
     */
jtulach@1334
  1956
    public String toPattern() {
jtulach@1334
  1957
        return toPattern( false );
jtulach@1334
  1958
    }
jtulach@1334
  1959
jtulach@1334
  1960
    /**
jtulach@1334
  1961
     * Synthesizes a localized pattern string that represents the current
jtulach@1334
  1962
     * state of this Format object.
jtulach@1334
  1963
     * @see #applyPattern
jtulach@1334
  1964
     */
jtulach@1334
  1965
    public String toLocalizedPattern() {
jtulach@1334
  1966
        return toPattern( true );
jtulach@1334
  1967
    }
jtulach@1334
  1968
jtulach@1334
  1969
    /**
jtulach@1334
  1970
     * Expand the affix pattern strings into the expanded affix strings.  If any
jtulach@1334
  1971
     * affix pattern string is null, do not expand it.  This method should be
jtulach@1334
  1972
     * called any time the symbols or the affix patterns change in order to keep
jtulach@1334
  1973
     * the expanded affix strings up to date.
jtulach@1334
  1974
     */
jtulach@1334
  1975
    private void expandAffixes() {
jtulach@1334
  1976
        // Reuse one StringBuffer for better performance
jtulach@1334
  1977
        StringBuffer buffer = new StringBuffer();
jtulach@1334
  1978
        if (posPrefixPattern != null) {
jtulach@1334
  1979
            positivePrefix = expandAffix(posPrefixPattern, buffer);
jtulach@1334
  1980
            positivePrefixFieldPositions = null;
jtulach@1334
  1981
        }
jtulach@1334
  1982
        if (posSuffixPattern != null) {
jtulach@1334
  1983
            positiveSuffix = expandAffix(posSuffixPattern, buffer);
jtulach@1334
  1984
            positiveSuffixFieldPositions = null;
jtulach@1334
  1985
        }
jtulach@1334
  1986
        if (negPrefixPattern != null) {
jtulach@1334
  1987
            negativePrefix = expandAffix(negPrefixPattern, buffer);
jtulach@1334
  1988
            negativePrefixFieldPositions = null;
jtulach@1334
  1989
        }
jtulach@1334
  1990
        if (negSuffixPattern != null) {
jtulach@1334
  1991
            negativeSuffix = expandAffix(negSuffixPattern, buffer);
jtulach@1334
  1992
            negativeSuffixFieldPositions = null;
jtulach@1334
  1993
        }
jtulach@1334
  1994
    }
jtulach@1334
  1995
jtulach@1334
  1996
    /**
jtulach@1334
  1997
     * Expand an affix pattern into an affix string.  All characters in the
jtulach@1334
  1998
     * pattern are literal unless prefixed by QUOTE.  The following characters
jtulach@1334
  1999
     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
jtulach@1334
  2000
     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
jtulach@1334
  2001
     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
jtulach@1334
  2002
     * currency code.  Any other character after a QUOTE represents itself.
jtulach@1334
  2003
     * QUOTE must be followed by another character; QUOTE may not occur by
jtulach@1334
  2004
     * itself at the end of the pattern.
jtulach@1334
  2005
     *
jtulach@1334
  2006
     * @param pattern the non-null, possibly empty pattern
jtulach@1334
  2007
     * @param buffer a scratch StringBuffer; its contents will be lost
jtulach@1334
  2008
     * @return the expanded equivalent of pattern
jtulach@1334
  2009
     */
jtulach@1334
  2010
    private String expandAffix(String pattern, StringBuffer buffer) {
jtulach@1334
  2011
        buffer.setLength(0);
jtulach@1334
  2012
        for (int i=0; i<pattern.length(); ) {
jtulach@1334
  2013
            char c = pattern.charAt(i++);
jtulach@1334
  2014
            if (c == QUOTE) {
jtulach@1334
  2015
                c = pattern.charAt(i++);
jtulach@1334
  2016
                switch (c) {
jtulach@1334
  2017
                case CURRENCY_SIGN:
jtulach@1334
  2018
                    if (i<pattern.length() &&
jtulach@1334
  2019
                        pattern.charAt(i) == CURRENCY_SIGN) {
jtulach@1334
  2020
                        ++i;
jtulach@1334
  2021
                        buffer.append(symbols.getInternationalCurrencySymbol());
jtulach@1334
  2022
                    } else {
jtulach@1334
  2023
                        buffer.append(symbols.getCurrencySymbol());
jtulach@1334
  2024
                    }
jtulach@1334
  2025
                    continue;
jtulach@1334
  2026
                case PATTERN_PERCENT:
jtulach@1334
  2027
                    c = symbols.getPercent();
jtulach@1334
  2028
                    break;
jtulach@1334
  2029
                case PATTERN_PER_MILLE:
jtulach@1334
  2030
                    c = symbols.getPerMill();
jtulach@1334
  2031
                    break;
jtulach@1334
  2032
                case PATTERN_MINUS:
jtulach@1334
  2033
                    c = symbols.getMinusSign();
jtulach@1334
  2034
                    break;
jtulach@1334
  2035
                }
jtulach@1334
  2036
            }
jtulach@1334
  2037
            buffer.append(c);
jtulach@1334
  2038
        }
jtulach@1334
  2039
        return buffer.toString();
jtulach@1334
  2040
    }
jtulach@1334
  2041
jtulach@1334
  2042
    /**
jtulach@1334
  2043
     * Expand an affix pattern into an array of FieldPositions describing
jtulach@1334
  2044
     * how the pattern would be expanded.
jtulach@1334
  2045
     * All characters in the
jtulach@1334
  2046
     * pattern are literal unless prefixed by QUOTE.  The following characters
jtulach@1334
  2047
     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
jtulach@1334
  2048
     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
jtulach@1334
  2049
     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
jtulach@1334
  2050
     * currency code.  Any other character after a QUOTE represents itself.
jtulach@1334
  2051
     * QUOTE must be followed by another character; QUOTE may not occur by
jtulach@1334
  2052
     * itself at the end of the pattern.
jtulach@1334
  2053
     *
jtulach@1334
  2054
     * @param pattern the non-null, possibly empty pattern
jtulach@1334
  2055
     * @return FieldPosition array of the resulting fields.
jtulach@1334
  2056
     */
jtulach@1334
  2057
    private FieldPosition[] expandAffix(String pattern) {
jtulach@1334
  2058
        ArrayList positions = null;
jtulach@1334
  2059
        int stringIndex = 0;
jtulach@1334
  2060
        for (int i=0; i<pattern.length(); ) {
jtulach@1334
  2061
            char c = pattern.charAt(i++);
jtulach@1334
  2062
            if (c == QUOTE) {
jtulach@1334
  2063
                int field = -1;
jtulach@1334
  2064
                Format.Field fieldID = null;
jtulach@1334
  2065
                c = pattern.charAt(i++);
jtulach@1334
  2066
                switch (c) {
jtulach@1334
  2067
                case CURRENCY_SIGN:
jtulach@1334
  2068
                    String string;
jtulach@1334
  2069
                    if (i<pattern.length() &&
jtulach@1334
  2070
                        pattern.charAt(i) == CURRENCY_SIGN) {
jtulach@1334
  2071
                        ++i;
jtulach@1334
  2072
                        string = symbols.getInternationalCurrencySymbol();
jtulach@1334
  2073
                    } else {
jtulach@1334
  2074
                        string = symbols.getCurrencySymbol();
jtulach@1334
  2075
                    }
jtulach@1334
  2076
                    if (string.length() > 0) {
jtulach@1334
  2077
                        if (positions == null) {
jtulach@1334
  2078
                            positions = new ArrayList(2);
jtulach@1334
  2079
                        }
jtulach@1334
  2080
                        FieldPosition fp = new FieldPosition(Field.CURRENCY);
jtulach@1334
  2081
                        fp.setBeginIndex(stringIndex);
jtulach@1334
  2082
                        fp.setEndIndex(stringIndex + string.length());
jtulach@1334
  2083
                        positions.add(fp);
jtulach@1334
  2084
                        stringIndex += string.length();
jtulach@1334
  2085
                    }
jtulach@1334
  2086
                    continue;
jtulach@1334
  2087
                case PATTERN_PERCENT:
jtulach@1334
  2088
                    c = symbols.getPercent();
jtulach@1334
  2089
                    field = -1;
jtulach@1334
  2090
                    fieldID = Field.PERCENT;
jtulach@1334
  2091
                    break;
jtulach@1334
  2092
                case PATTERN_PER_MILLE:
jtulach@1334
  2093
                    c = symbols.getPerMill();
jtulach@1334
  2094
                    field = -1;
jtulach@1334
  2095
                    fieldID = Field.PERMILLE;
jtulach@1334
  2096
                    break;
jtulach@1334
  2097
                case PATTERN_MINUS:
jtulach@1334
  2098
                    c = symbols.getMinusSign();
jtulach@1334
  2099
                    field = -1;
jtulach@1334
  2100
                    fieldID = Field.SIGN;
jtulach@1334
  2101
                    break;
jtulach@1334
  2102
                }
jtulach@1334
  2103
                if (fieldID != null) {
jtulach@1334
  2104
                    if (positions == null) {
jtulach@1334
  2105
                        positions = new ArrayList(2);
jtulach@1334
  2106
                    }
jtulach@1334
  2107
                    FieldPosition fp = new FieldPosition(fieldID, field);
jtulach@1334
  2108
                    fp.setBeginIndex(stringIndex);
jtulach@1334
  2109
                    fp.setEndIndex(stringIndex + 1);
jtulach@1334
  2110
                    positions.add(fp);
jtulach@1334
  2111
                }
jtulach@1334
  2112
            }
jtulach@1334
  2113
            stringIndex++;
jtulach@1334
  2114
        }
jtulach@1334
  2115
        if (positions != null) {
jtulach@1334
  2116
            return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
jtulach@1334
  2117
        }
jtulach@1334
  2118
        return EmptyFieldPositionArray;
jtulach@1334
  2119
    }
jtulach@1334
  2120
jtulach@1334
  2121
    /**
jtulach@1334
  2122
     * Appends an affix pattern to the given StringBuffer, quoting special
jtulach@1334
  2123
     * characters as needed.  Uses the internal affix pattern, if that exists,
jtulach@1334
  2124
     * or the literal affix, if the internal affix pattern is null.  The
jtulach@1334
  2125
     * appended string will generate the same affix pattern (or literal affix)
jtulach@1334
  2126
     * when passed to toPattern().
jtulach@1334
  2127
     *
jtulach@1334
  2128
     * @param buffer the affix string is appended to this
jtulach@1334
  2129
     * @param affixPattern a pattern such as posPrefixPattern; may be null
jtulach@1334
  2130
     * @param expAffix a corresponding expanded affix, such as positivePrefix.
jtulach@1334
  2131
     * Ignored unless affixPattern is null.  If affixPattern is null, then
jtulach@1334
  2132
     * expAffix is appended as a literal affix.
jtulach@1334
  2133
     * @param localized true if the appended pattern should contain localized
jtulach@1334
  2134
     * pattern characters; otherwise, non-localized pattern chars are appended
jtulach@1334
  2135
     */
jtulach@1334
  2136
    private void appendAffix(StringBuffer buffer, String affixPattern,
jtulach@1334
  2137
                             String expAffix, boolean localized) {
jtulach@1334
  2138
        if (affixPattern == null) {
jtulach@1334
  2139
            appendAffix(buffer, expAffix, localized);
jtulach@1334
  2140
        } else {
jtulach@1334
  2141
            int i;
jtulach@1334
  2142
            for (int pos=0; pos<affixPattern.length(); pos=i) {
jtulach@1334
  2143
                i = affixPattern.indexOf(QUOTE, pos);
jtulach@1334
  2144
                if (i < 0) {
jtulach@1334
  2145
                    appendAffix(buffer, affixPattern.substring(pos), localized);
jtulach@1334
  2146
                    break;
jtulach@1334
  2147
                }
jtulach@1334
  2148
                if (i > pos) {
jtulach@1334
  2149
                    appendAffix(buffer, affixPattern.substring(pos, i), localized);
jtulach@1334
  2150
                }
jtulach@1334
  2151
                char c = affixPattern.charAt(++i);
jtulach@1334
  2152
                ++i;
jtulach@1334
  2153
                if (c == QUOTE) {
jtulach@1334
  2154
                    buffer.append(c);
jtulach@1334
  2155
                    // Fall through and append another QUOTE below
jtulach@1334
  2156
                } else if (c == CURRENCY_SIGN &&
jtulach@1334
  2157
                           i<affixPattern.length() &&
jtulach@1334
  2158
                           affixPattern.charAt(i) == CURRENCY_SIGN) {
jtulach@1334
  2159
                    ++i;
jtulach@1334
  2160
                    buffer.append(c);
jtulach@1334
  2161
                    // Fall through and append another CURRENCY_SIGN below
jtulach@1334
  2162
                } else if (localized) {
jtulach@1334
  2163
                    switch (c) {
jtulach@1334
  2164
                    case PATTERN_PERCENT:
jtulach@1334
  2165
                        c = symbols.getPercent();
jtulach@1334
  2166
                        break;
jtulach@1334
  2167
                    case PATTERN_PER_MILLE:
jtulach@1334
  2168
                        c = symbols.getPerMill();
jtulach@1334
  2169
                        break;
jtulach@1334
  2170
                    case PATTERN_MINUS:
jtulach@1334
  2171
                        c = symbols.getMinusSign();
jtulach@1334
  2172
                        break;
jtulach@1334
  2173
                    }
jtulach@1334
  2174
                }
jtulach@1334
  2175
                buffer.append(c);
jtulach@1334
  2176
            }
jtulach@1334
  2177
        }
jtulach@1334
  2178
    }
jtulach@1334
  2179
jtulach@1334
  2180
    /**
jtulach@1334
  2181
     * Append an affix to the given StringBuffer, using quotes if
jtulach@1334
  2182
     * there are special characters.  Single quotes themselves must be
jtulach@1334
  2183
     * escaped in either case.
jtulach@1334
  2184
     */
jtulach@1334
  2185
    private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
jtulach@1334
  2186
        boolean needQuote;
jtulach@1334
  2187
        if (localized) {
jtulach@1334
  2188
            needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
jtulach@1334
  2189
                || affix.indexOf(symbols.getGroupingSeparator()) >= 0
jtulach@1334
  2190
                || affix.indexOf(symbols.getDecimalSeparator()) >= 0
jtulach@1334
  2191
                || affix.indexOf(symbols.getPercent()) >= 0
jtulach@1334
  2192
                || affix.indexOf(symbols.getPerMill()) >= 0
jtulach@1334
  2193
                || affix.indexOf(symbols.getDigit()) >= 0
jtulach@1334
  2194
                || affix.indexOf(symbols.getPatternSeparator()) >= 0
jtulach@1334
  2195
                || affix.indexOf(symbols.getMinusSign()) >= 0
jtulach@1334
  2196
                || affix.indexOf(CURRENCY_SIGN) >= 0;
jtulach@1334
  2197
        }
jtulach@1334
  2198
        else {
jtulach@1334
  2199
            needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
jtulach@1334
  2200
                || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
jtulach@1334
  2201
                || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
jtulach@1334
  2202
                || affix.indexOf(PATTERN_PERCENT) >= 0
jtulach@1334
  2203
                || affix.indexOf(PATTERN_PER_MILLE) >= 0
jtulach@1334
  2204
                || affix.indexOf(PATTERN_DIGIT) >= 0
jtulach@1334
  2205
                || affix.indexOf(PATTERN_SEPARATOR) >= 0
jtulach@1334
  2206
                || affix.indexOf(PATTERN_MINUS) >= 0
jtulach@1334
  2207
                || affix.indexOf(CURRENCY_SIGN) >= 0;
jtulach@1334
  2208
        }
jtulach@1334
  2209
        if (needQuote) buffer.append('\'');
jtulach@1334
  2210
        if (affix.indexOf('\'') < 0) buffer.append(affix);
jtulach@1334
  2211
        else {
jtulach@1334
  2212
            for (int j=0; j<affix.length(); ++j) {
jtulach@1334
  2213
                char c = affix.charAt(j);
jtulach@1334
  2214
                buffer.append(c);
jtulach@1334
  2215
                if (c == '\'') buffer.append(c);
jtulach@1334
  2216
            }
jtulach@1334
  2217
        }
jtulach@1334
  2218
        if (needQuote) buffer.append('\'');
jtulach@1334
  2219
    }
jtulach@1334
  2220
jtulach@1334
  2221
    /**
jtulach@1334
  2222
     * Does the real work of generating a pattern.  */
jtulach@1334
  2223
    private String toPattern(boolean localized) {
jtulach@1334
  2224
        StringBuffer result = new StringBuffer();
jtulach@1334
  2225
        for (int j = 1; j >= 0; --j) {
jtulach@1334
  2226
            if (j == 1)
jtulach@1334
  2227
                appendAffix(result, posPrefixPattern, positivePrefix, localized);
jtulach@1334
  2228
            else appendAffix(result, negPrefixPattern, negativePrefix, localized);
jtulach@1334
  2229
            int i;
jtulach@1334
  2230
            int digitCount = useExponentialNotation
jtulach@1334
  2231
                        ? getMaximumIntegerDigits()
jtulach@1334
  2232
                        : Math.max(groupingSize, getMinimumIntegerDigits())+1;
jtulach@1334
  2233
            for (i = digitCount; i > 0; --i) {
jtulach@1334
  2234
                if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
jtulach@1334
  2235
                    i % groupingSize == 0) {
jtulach@1334
  2236
                    result.append(localized ? symbols.getGroupingSeparator() :
jtulach@1334
  2237
                                  PATTERN_GROUPING_SEPARATOR);
jtulach@1334
  2238
                }
jtulach@1334
  2239
                result.append(i <= getMinimumIntegerDigits()
jtulach@1334
  2240
                    ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
jtulach@1334
  2241
                    : (localized ? symbols.getDigit() : PATTERN_DIGIT));
jtulach@1334
  2242
            }
jtulach@1334
  2243
            if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
jtulach@1334
  2244
                result.append(localized ? symbols.getDecimalSeparator() :
jtulach@1334
  2245
                              PATTERN_DECIMAL_SEPARATOR);
jtulach@1334
  2246
            for (i = 0; i < getMaximumFractionDigits(); ++i) {
jtulach@1334
  2247
                if (i < getMinimumFractionDigits()) {
jtulach@1334
  2248
                    result.append(localized ? symbols.getZeroDigit() :
jtulach@1334
  2249
                                  PATTERN_ZERO_DIGIT);
jtulach@1334
  2250
                } else {
jtulach@1334
  2251
                    result.append(localized ? symbols.getDigit() :
jtulach@1334
  2252
                                  PATTERN_DIGIT);
jtulach@1334
  2253
                }
jtulach@1334
  2254
            }
jtulach@1334
  2255
        if (useExponentialNotation)
jtulach@1334
  2256
        {
jtulach@1334
  2257
            result.append(localized ? symbols.getExponentSeparator() :
jtulach@1334
  2258
                  PATTERN_EXPONENT);
jtulach@1334
  2259
        for (i=0; i<minExponentDigits; ++i)
jtulach@1334
  2260
                    result.append(localized ? symbols.getZeroDigit() :
jtulach@1334
  2261
                                  PATTERN_ZERO_DIGIT);
jtulach@1334
  2262
        }
jtulach@1334
  2263
            if (j == 1) {
jtulach@1334
  2264
                appendAffix(result, posSuffixPattern, positiveSuffix, localized);
jtulach@1334
  2265
                if ((negSuffixPattern == posSuffixPattern && // n == p == null
jtulach@1334
  2266
                     negativeSuffix.equals(positiveSuffix))
jtulach@1334
  2267
                    || (negSuffixPattern != null &&
jtulach@1334
  2268
                        negSuffixPattern.equals(posSuffixPattern))) {
jtulach@1334
  2269
                    if ((negPrefixPattern != null && posPrefixPattern != null &&
jtulach@1334
  2270
                         negPrefixPattern.equals("'-" + posPrefixPattern)) ||
jtulach@1334
  2271
                        (negPrefixPattern == posPrefixPattern && // n == p == null
jtulach@1334
  2272
                         negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
jtulach@1334
  2273
                        break;
jtulach@1334
  2274
                }
jtulach@1334
  2275
                result.append(localized ? symbols.getPatternSeparator() :
jtulach@1334
  2276
                              PATTERN_SEPARATOR);
jtulach@1334
  2277
            } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
jtulach@1334
  2278
        }
jtulach@1334
  2279
        return result.toString();
jtulach@1334
  2280
    }
jtulach@1334
  2281
jtulach@1334
  2282
    /**
jtulach@1334
  2283
     * Apply the given pattern to this Format object.  A pattern is a
jtulach@1334
  2284
     * short-hand specification for the various formatting properties.
jtulach@1334
  2285
     * These properties can also be changed individually through the
jtulach@1334
  2286
     * various setter methods.
jtulach@1334
  2287
     * <p>
jtulach@1334
  2288
     * There is no limit to integer digits set
jtulach@1334
  2289
     * by this routine, since that is the typical end-user desire;
jtulach@1334
  2290
     * use setMaximumInteger if you want to set a real value.
jtulach@1334
  2291
     * For negative numbers, use a second pattern, separated by a semicolon
jtulach@1334
  2292
     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
jtulach@1334
  2293
     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
jtulach@1334
  2294
     * a maximum of 2 fraction digits.
jtulach@1334
  2295
     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
jtulach@1334
  2296
     * parentheses.
jtulach@1334
  2297
     * <p>In negative patterns, the minimum and maximum counts are ignored;
jtulach@1334
  2298
     * these are presumed to be set in the positive pattern.
jtulach@1334
  2299
     *
jtulach@1334
  2300
     * @exception NullPointerException if <code>pattern</code> is null
jtulach@1334
  2301
     * @exception IllegalArgumentException if the given pattern is invalid.
jtulach@1334
  2302
     */
jtulach@1334
  2303
    public void applyPattern(String pattern) {
jtulach@1334
  2304
        applyPattern(pattern, false);
jtulach@1334
  2305
    }
jtulach@1334
  2306
jtulach@1334
  2307
    /**
jtulach@1334
  2308
     * Apply the given pattern to this Format object.  The pattern
jtulach@1334
  2309
     * is assumed to be in a localized notation. A pattern is a
jtulach@1334
  2310
     * short-hand specification for the various formatting properties.
jtulach@1334
  2311
     * These properties can also be changed individually through the
jtulach@1334
  2312
     * various setter methods.
jtulach@1334
  2313
     * <p>
jtulach@1334
  2314
     * There is no limit to integer digits set
jtulach@1334
  2315
     * by this routine, since that is the typical end-user desire;
jtulach@1334
  2316
     * use setMaximumInteger if you want to set a real value.
jtulach@1334
  2317
     * For negative numbers, use a second pattern, separated by a semicolon
jtulach@1334
  2318
     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
jtulach@1334
  2319
     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
jtulach@1334
  2320
     * a maximum of 2 fraction digits.
jtulach@1334
  2321
     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
jtulach@1334
  2322
     * parentheses.
jtulach@1334
  2323
     * <p>In negative patterns, the minimum and maximum counts are ignored;
jtulach@1334
  2324
     * these are presumed to be set in the positive pattern.
jtulach@1334
  2325
     *
jtulach@1334
  2326
     * @exception NullPointerException if <code>pattern</code> is null
jtulach@1334
  2327
     * @exception IllegalArgumentException if the given pattern is invalid.
jtulach@1334
  2328
     */
jtulach@1334
  2329
    public void applyLocalizedPattern(String pattern) {
jtulach@1334
  2330
        applyPattern(pattern, true);
jtulach@1334
  2331
    }
jtulach@1334
  2332
jtulach@1334
  2333
    /**
jtulach@1334
  2334
     * Does the real work of applying a pattern.
jtulach@1334
  2335
     */
jtulach@1334
  2336
    private void applyPattern(String pattern, boolean localized) {
jtulach@1334
  2337
        char zeroDigit         = PATTERN_ZERO_DIGIT;
jtulach@1334
  2338
        char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
jtulach@1334
  2339
        char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
jtulach@1334
  2340
        char percent           = PATTERN_PERCENT;
jtulach@1334
  2341
        char perMill           = PATTERN_PER_MILLE;
jtulach@1334
  2342
        char digit             = PATTERN_DIGIT;
jtulach@1334
  2343
        char separator         = PATTERN_SEPARATOR;
jtulach@1334
  2344
        String exponent          = PATTERN_EXPONENT;
jtulach@1334
  2345
        char minus             = PATTERN_MINUS;
jtulach@1334
  2346
        if (localized) {
jtulach@1334
  2347
            zeroDigit         = symbols.getZeroDigit();
jtulach@1334
  2348
            groupingSeparator = symbols.getGroupingSeparator();
jtulach@1334
  2349
            decimalSeparator  = symbols.getDecimalSeparator();
jtulach@1334
  2350
            percent           = symbols.getPercent();
jtulach@1334
  2351
            perMill           = symbols.getPerMill();
jtulach@1334
  2352
            digit             = symbols.getDigit();
jtulach@1334
  2353
            separator         = symbols.getPatternSeparator();
jtulach@1334
  2354
            exponent          = symbols.getExponentSeparator();
jtulach@1334
  2355
            minus             = symbols.getMinusSign();
jtulach@1334
  2356
        }
jtulach@1334
  2357
        boolean gotNegative = false;
jtulach@1334
  2358
        decimalSeparatorAlwaysShown = false;
jtulach@1334
  2359
        isCurrencyFormat = false;
jtulach@1334
  2360
        useExponentialNotation = false;
jtulach@1334
  2361
jtulach@1334
  2362
        // Two variables are used to record the subrange of the pattern
jtulach@1334
  2363
        // occupied by phase 1.  This is used during the processing of the
jtulach@1334
  2364
        // second pattern (the one representing negative numbers) to ensure
jtulach@1334
  2365
        // that no deviation exists in phase 1 between the two patterns.
jtulach@1334
  2366
        int phaseOneStart = 0;
jtulach@1334
  2367
        int phaseOneLength = 0;
jtulach@1334
  2368
jtulach@1334
  2369
        int start = 0;
jtulach@1334
  2370
        for (int j = 1; j >= 0 && start < pattern.length(); --j) {
jtulach@1334
  2371
            boolean inQuote = false;
jtulach@1334
  2372
            StringBuffer prefix = new StringBuffer();
jtulach@1334
  2373
            StringBuffer suffix = new StringBuffer();
jtulach@1334
  2374
            int decimalPos = -1;
jtulach@1334
  2375
            int multiplier = 1;
jtulach@1334
  2376
            int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
jtulach@1334
  2377
            byte groupingCount = -1;
jtulach@1334
  2378
jtulach@1334
  2379
            // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
jtulach@1334
  2380
            // the section of the pattern with digits, decimal separator,
jtulach@1334
  2381
            // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
jtulach@1334
  2382
            // percent, per mille, and currency symbols are recognized and
jtulach@1334
  2383
            // translated.  The separation of the characters into phases is
jtulach@1334
  2384
            // strictly enforced; if phase 1 characters are to appear in the
jtulach@1334
  2385
            // suffix, for example, they must be quoted.
jtulach@1334
  2386
            int phase = 0;
jtulach@1334
  2387
jtulach@1334
  2388
            // The affix is either the prefix or the suffix.
jtulach@1334
  2389
            StringBuffer affix = prefix;
jtulach@1334
  2390
jtulach@1334
  2391
            for (int pos = start; pos < pattern.length(); ++pos) {
jtulach@1334
  2392
                char ch = pattern.charAt(pos);
jtulach@1334
  2393
                switch (phase) {
jtulach@1334
  2394
                case 0:
jtulach@1334
  2395
                case 2:
jtulach@1334
  2396
                    // Process the prefix / suffix characters
jtulach@1334
  2397
                    if (inQuote) {
jtulach@1334
  2398
                        // A quote within quotes indicates either the closing
jtulach@1334
  2399
                        // quote or two quotes, which is a quote literal. That
jtulach@1334
  2400
                        // is, we have the second quote in 'do' or 'don''t'.
jtulach@1334
  2401
                        if (ch == QUOTE) {
jtulach@1334
  2402
                            if ((pos+1) < pattern.length() &&
jtulach@1334
  2403
                                pattern.charAt(pos+1) == QUOTE) {
jtulach@1334
  2404
                                ++pos;
jtulach@1334
  2405
                                affix.append("''"); // 'don''t'
jtulach@1334
  2406
                            } else {
jtulach@1334
  2407
                                inQuote = false; // 'do'
jtulach@1334
  2408
                            }
jtulach@1334
  2409
                            continue;
jtulach@1334
  2410
                        }
jtulach@1334
  2411
                    } else {
jtulach@1334
  2412
                        // Process unquoted characters seen in prefix or suffix
jtulach@1334
  2413
                        // phase.
jtulach@1334
  2414
                        if (ch == digit ||
jtulach@1334
  2415
                            ch == zeroDigit ||
jtulach@1334
  2416
                            ch == groupingSeparator ||
jtulach@1334
  2417
                            ch == decimalSeparator) {
jtulach@1334
  2418
                            phase = 1;
jtulach@1334
  2419
                            if (j == 1) {
jtulach@1334
  2420
                                phaseOneStart = pos;
jtulach@1334
  2421
                            }
jtulach@1334
  2422
                            --pos; // Reprocess this character
jtulach@1334
  2423
                            continue;
jtulach@1334
  2424
                        } else if (ch == CURRENCY_SIGN) {
jtulach@1334
  2425
                            // Use lookahead to determine if the currency sign
jtulach@1334
  2426
                            // is doubled or not.
jtulach@1334
  2427
                            boolean doubled = (pos + 1) < pattern.length() &&
jtulach@1334
  2428
                                pattern.charAt(pos + 1) == CURRENCY_SIGN;
jtulach@1334
  2429
                            if (doubled) { // Skip over the doubled character
jtulach@1334
  2430
                             ++pos;
jtulach@1334
  2431
                            }
jtulach@1334
  2432
                            isCurrencyFormat = true;
jtulach@1334
  2433
                            affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
jtulach@1334
  2434
                            continue;
jtulach@1334
  2435
                        } else if (ch == QUOTE) {
jtulach@1334
  2436
                            // A quote outside quotes indicates either the
jtulach@1334
  2437
                            // opening quote or two quotes, which is a quote
jtulach@1334
  2438
                            // literal. That is, we have the first quote in 'do'
jtulach@1334
  2439
                            // or o''clock.
jtulach@1334
  2440
                            if (ch == QUOTE) {
jtulach@1334
  2441
                                if ((pos+1) < pattern.length() &&
jtulach@1334
  2442
                                    pattern.charAt(pos+1) == QUOTE) {
jtulach@1334
  2443
                                    ++pos;
jtulach@1334
  2444
                                    affix.append("''"); // o''clock
jtulach@1334
  2445
                                } else {
jtulach@1334
  2446
                                    inQuote = true; // 'do'
jtulach@1334
  2447
                                }
jtulach@1334
  2448
                                continue;
jtulach@1334
  2449
                            }
jtulach@1334
  2450
                        } else if (ch == separator) {
jtulach@1334
  2451
                            // Don't allow separators before we see digit
jtulach@1334
  2452
                            // characters of phase 1, and don't allow separators
jtulach@1334
  2453
                            // in the second pattern (j == 0).
jtulach@1334
  2454
                            if (phase == 0 || j == 0) {
jtulach@1334
  2455
                                throw new IllegalArgumentException("Unquoted special character '" +
jtulach@1334
  2456
                                    ch + "' in pattern \"" + pattern + '"');
jtulach@1334
  2457
                            }
jtulach@1334
  2458
                            start = pos + 1;
jtulach@1334
  2459
                            pos = pattern.length();
jtulach@1334
  2460
                            continue;
jtulach@1334
  2461
                        }
jtulach@1334
  2462
jtulach@1334
  2463
                        // Next handle characters which are appended directly.
jtulach@1334
  2464
                        else if (ch == percent) {
jtulach@1334
  2465
                            if (multiplier != 1) {
jtulach@1334
  2466
                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
jtulach@1334
  2467
                                    pattern + '"');
jtulach@1334
  2468
                            }
jtulach@1334
  2469
                            multiplier = 100;
jtulach@1334
  2470
                            affix.append("'%");
jtulach@1334
  2471
                            continue;
jtulach@1334
  2472
                        } else if (ch == perMill) {
jtulach@1334
  2473
                            if (multiplier != 1) {
jtulach@1334
  2474
                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
jtulach@1334
  2475
                                    pattern + '"');
jtulach@1334
  2476
                            }
jtulach@1334
  2477
                            multiplier = 1000;
jtulach@1334
  2478
                            affix.append("'\u2030");
jtulach@1334
  2479
                            continue;
jtulach@1334
  2480
                        } else if (ch == minus) {
jtulach@1334
  2481
                            affix.append("'-");
jtulach@1334
  2482
                            continue;
jtulach@1334
  2483
                        }
jtulach@1334
  2484
                    }
jtulach@1334
  2485
                    // Note that if we are within quotes, or if this is an
jtulach@1334
  2486
                    // unquoted, non-special character, then we usually fall
jtulach@1334
  2487
                    // through to here.
jtulach@1334
  2488
                    affix.append(ch);
jtulach@1334
  2489
                    break;
jtulach@1334
  2490
jtulach@1334
  2491
                case 1:
jtulach@1334
  2492
                    // Phase one must be identical in the two sub-patterns. We
jtulach@1334
  2493
                    // enforce this by doing a direct comparison. While
jtulach@1334
  2494
                    // processing the first sub-pattern, we just record its
jtulach@1334
  2495
                    // length. While processing the second, we compare
jtulach@1334
  2496
                    // characters.
jtulach@1334
  2497
                    if (j == 1) {
jtulach@1334
  2498
                        ++phaseOneLength;
jtulach@1334
  2499
                    } else {
jtulach@1334
  2500
                        if (--phaseOneLength == 0) {
jtulach@1334
  2501
                            phase = 2;
jtulach@1334
  2502
                            affix = suffix;
jtulach@1334
  2503
                        }
jtulach@1334
  2504
                        continue;
jtulach@1334
  2505
                    }
jtulach@1334
  2506
jtulach@1334
  2507
                    // Process the digits, decimal, and grouping characters. We
jtulach@1334
  2508
                    // record five pieces of information. We expect the digits
jtulach@1334
  2509
                    // to occur in the pattern ####0000.####, and we record the
jtulach@1334
  2510
                    // number of left digits, zero (central) digits, and right
jtulach@1334
  2511
                    // digits. The position of the last grouping character is
jtulach@1334
  2512
                    // recorded (should be somewhere within the first two blocks
jtulach@1334
  2513
                    // of characters), as is the position of the decimal point,
jtulach@1334
  2514
                    // if any (should be in the zero digits). If there is no
jtulach@1334
  2515
                    // decimal point, then there should be no right digits.
jtulach@1334
  2516
                    if (ch == digit) {
jtulach@1334
  2517
                        if (zeroDigitCount > 0) {
jtulach@1334
  2518
                            ++digitRightCount;
jtulach@1334
  2519
                        } else {
jtulach@1334
  2520
                            ++digitLeftCount;
jtulach@1334
  2521
                        }
jtulach@1334
  2522
                        if (groupingCount >= 0 && decimalPos < 0) {
jtulach@1334
  2523
                            ++groupingCount;
jtulach@1334
  2524
                        }
jtulach@1334
  2525
                    } else if (ch == zeroDigit) {
jtulach@1334
  2526
                        if (digitRightCount > 0) {
jtulach@1334
  2527
                            throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
jtulach@1334
  2528
                                pattern + '"');
jtulach@1334
  2529
                        }
jtulach@1334
  2530
                        ++zeroDigitCount;
jtulach@1334
  2531
                        if (groupingCount >= 0 && decimalPos < 0) {
jtulach@1334
  2532
                            ++groupingCount;
jtulach@1334
  2533
                        }
jtulach@1334
  2534
                    } else if (ch == groupingSeparator) {
jtulach@1334
  2535
                        groupingCount = 0;
jtulach@1334
  2536
                    } else if (ch == decimalSeparator) {
jtulach@1334
  2537
                        if (decimalPos >= 0) {
jtulach@1334
  2538
                            throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
jtulach@1334
  2539
                                pattern + '"');
jtulach@1334
  2540
                        }
jtulach@1334
  2541
                        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
jtulach@1334
  2542
                    } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
jtulach@1334
  2543
                        if (useExponentialNotation) {
jtulach@1334
  2544
                            throw new IllegalArgumentException("Multiple exponential " +
jtulach@1334
  2545
                                "symbols in pattern \"" + pattern + '"');
jtulach@1334
  2546
                        }
jtulach@1334
  2547
                        useExponentialNotation = true;
jtulach@1334
  2548
                        minExponentDigits = 0;
jtulach@1334
  2549
jtulach@1334
  2550
                        // Use lookahead to parse out the exponential part
jtulach@1334
  2551
                        // of the pattern, then jump into phase 2.
jtulach@1334
  2552
                        pos = pos+exponent.length();
jtulach@1334
  2553
                         while (pos < pattern.length() &&
jtulach@1334
  2554
                               pattern.charAt(pos) == zeroDigit) {
jtulach@1334
  2555
                            ++minExponentDigits;
jtulach@1334
  2556
                            ++phaseOneLength;
jtulach@1334
  2557
                            ++pos;
jtulach@1334
  2558
                        }
jtulach@1334
  2559
jtulach@1334
  2560
                        if ((digitLeftCount + zeroDigitCount) < 1 ||
jtulach@1334
  2561
                            minExponentDigits < 1) {
jtulach@1334
  2562
                            throw new IllegalArgumentException("Malformed exponential " +
jtulach@1334
  2563
                                "pattern \"" + pattern + '"');
jtulach@1334
  2564
                        }
jtulach@1334
  2565
jtulach@1334
  2566
                        // Transition to phase 2
jtulach@1334
  2567
                        phase = 2;
jtulach@1334
  2568
                        affix = suffix;
jtulach@1334
  2569
                        --pos;
jtulach@1334
  2570
                        continue;
jtulach@1334
  2571
                    } else {
jtulach@1334
  2572
                        phase = 2;
jtulach@1334
  2573
                        affix = suffix;
jtulach@1334
  2574
                        --pos;
jtulach@1334
  2575
                        --phaseOneLength;
jtulach@1334
  2576
                        continue;
jtulach@1334
  2577
                    }
jtulach@1334
  2578
                    break;
jtulach@1334
  2579
                }
jtulach@1334
  2580
            }
jtulach@1334
  2581
jtulach@1334
  2582
            // Handle patterns with no '0' pattern character. These patterns
jtulach@1334
  2583
            // are legal, but must be interpreted.  "##.###" -> "#0.###".
jtulach@1334
  2584
            // ".###" -> ".0##".
jtulach@1334
  2585
            /* We allow patterns of the form "####" to produce a zeroDigitCount
jtulach@1334
  2586
             * of zero (got that?); although this seems like it might make it
jtulach@1334
  2587
             * possible for format() to produce empty strings, format() checks
jtulach@1334
  2588
             * for this condition and outputs a zero digit in this situation.
jtulach@1334
  2589
             * Having a zeroDigitCount of zero yields a minimum integer digits
jtulach@1334
  2590
             * of zero, which allows proper round-trip patterns.  That is, we
jtulach@1334
  2591
             * don't want "#" to become "#0" when toPattern() is called (even
jtulach@1334
  2592
             * though that's what it really is, semantically).
jtulach@1334
  2593
             */
jtulach@1334
  2594
            if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
jtulach@1334
  2595
                // Handle "###.###" and "###." and ".###"
jtulach@1334
  2596
                int n = decimalPos;
jtulach@1334
  2597
                if (n == 0) { // Handle ".###"
jtulach@1334
  2598
                    ++n;
jtulach@1334
  2599
                }
jtulach@1334
  2600
                digitRightCount = digitLeftCount - n;
jtulach@1334
  2601
                digitLeftCount = n - 1;
jtulach@1334
  2602
                zeroDigitCount = 1;
jtulach@1334
  2603
            }
jtulach@1334
  2604
jtulach@1334
  2605
            // Do syntax checking on the digits.
jtulach@1334
  2606
            if ((decimalPos < 0 && digitRightCount > 0) ||
jtulach@1334
  2607
                (decimalPos >= 0 && (decimalPos < digitLeftCount ||
jtulach@1334
  2608
                 decimalPos > (digitLeftCount + zeroDigitCount))) ||
jtulach@1334
  2609
                 groupingCount == 0 || inQuote) {
jtulach@1334
  2610
                throw new IllegalArgumentException("Malformed pattern \"" +
jtulach@1334
  2611
                    pattern + '"');
jtulach@1334
  2612
            }
jtulach@1334
  2613
jtulach@1334
  2614
            if (j == 1) {
jtulach@1334
  2615
                posPrefixPattern = prefix.toString();
jtulach@1334
  2616
                posSuffixPattern = suffix.toString();
jtulach@1334
  2617
                negPrefixPattern = posPrefixPattern;   // assume these for now
jtulach@1334
  2618
                negSuffixPattern = posSuffixPattern;
jtulach@1334
  2619
                int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
jtulach@1334
  2620
                /* The effectiveDecimalPos is the position the decimal is at or
jtulach@1334
  2621
                 * would be at if there is no decimal. Note that if decimalPos<0,
jtulach@1334
  2622
                 * then digitTotalCount == digitLeftCount + zeroDigitCount.
jtulach@1334
  2623
                 */
jtulach@1334
  2624
                int effectiveDecimalPos = decimalPos >= 0 ?
jtulach@1334
  2625
                    decimalPos : digitTotalCount;
jtulach@1334
  2626
                setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
jtulach@1334
  2627
                setMaximumIntegerDigits(useExponentialNotation ?
jtulach@1334
  2628
                    digitLeftCount + getMinimumIntegerDigits() :
jtulach@1334
  2629
                    MAXIMUM_INTEGER_DIGITS);
jtulach@1334
  2630
                setMaximumFractionDigits(decimalPos >= 0 ?
jtulach@1334
  2631
                    (digitTotalCount - decimalPos) : 0);
jtulach@1334
  2632
                setMinimumFractionDigits(decimalPos >= 0 ?
jtulach@1334
  2633
                    (digitLeftCount + zeroDigitCount - decimalPos) : 0);
jtulach@1334
  2634
                setGroupingUsed(groupingCount > 0);
jtulach@1334
  2635
                this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
jtulach@1334
  2636
                this.multiplier = multiplier;
jtulach@1334
  2637
                setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
jtulach@1334
  2638
                    decimalPos == digitTotalCount);
jtulach@1334
  2639
            } else {
jtulach@1334
  2640
                negPrefixPattern = prefix.toString();
jtulach@1334
  2641
                negSuffixPattern = suffix.toString();
jtulach@1334
  2642
                gotNegative = true;
jtulach@1334
  2643
            }
jtulach@1334
  2644
        }
jtulach@1334
  2645
jtulach@1334
  2646
        if (pattern.length() == 0) {
jtulach@1334
  2647
            posPrefixPattern = posSuffixPattern = "";
jtulach@1334
  2648
            setMinimumIntegerDigits(0);
jtulach@1334
  2649
            setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
jtulach@1334
  2650
            setMinimumFractionDigits(0);
jtulach@1334
  2651
            setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
jtulach@1334
  2652
        }
jtulach@1334
  2653
jtulach@1334
  2654
        // If there was no negative pattern, or if the negative pattern is
jtulach@1334
  2655
        // identical to the positive pattern, then prepend the minus sign to
jtulach@1334
  2656
        // the positive pattern to form the negative pattern.
jtulach@1334
  2657
        if (!gotNegative ||
jtulach@1334
  2658
            (negPrefixPattern.equals(posPrefixPattern)
jtulach@1334
  2659
             && negSuffixPattern.equals(posSuffixPattern))) {
jtulach@1334
  2660
            negSuffixPattern = posSuffixPattern;
jtulach@1334
  2661
            negPrefixPattern = "'-" + posPrefixPattern;
jtulach@1334
  2662
        }
jtulach@1334
  2663
jtulach@1334
  2664
        expandAffixes();
jtulach@1334
  2665
    }
jtulach@1334
  2666
jtulach@1334
  2667
    /**
jtulach@1334
  2668
     * Sets the maximum number of digits allowed in the integer portion of a
jtulach@1334
  2669
     * number.
jtulach@1334
  2670
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2671
     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
jtulach@1334
  2672
     * 309 is used. Negative input values are replaced with 0.
jtulach@1334
  2673
     * @see NumberFormat#setMaximumIntegerDigits
jtulach@1334
  2674
     */
jtulach@1334
  2675
    public void setMaximumIntegerDigits(int newValue) {
jtulach@1334
  2676
        maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
jtulach@1334
  2677
        super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
jtulach@1334
  2678
            DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
jtulach@1334
  2679
        if (minimumIntegerDigits > maximumIntegerDigits) {
jtulach@1334
  2680
            minimumIntegerDigits = maximumIntegerDigits;
jtulach@1334
  2681
            super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
jtulach@1334
  2682
                DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
jtulach@1334
  2683
        }
jtulach@1334
  2684
    }
jtulach@1334
  2685
jtulach@1334
  2686
    /**
jtulach@1334
  2687
     * Sets the minimum number of digits allowed in the integer portion of a
jtulach@1334
  2688
     * number.
jtulach@1334
  2689
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2690
     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
jtulach@1334
  2691
     * 309 is used. Negative input values are replaced with 0.
jtulach@1334
  2692
     * @see NumberFormat#setMinimumIntegerDigits
jtulach@1334
  2693
     */
jtulach@1334
  2694
    public void setMinimumIntegerDigits(int newValue) {
jtulach@1334
  2695
        minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
jtulach@1334
  2696
        super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
jtulach@1334
  2697
            DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
jtulach@1334
  2698
        if (minimumIntegerDigits > maximumIntegerDigits) {
jtulach@1334
  2699
            maximumIntegerDigits = minimumIntegerDigits;
jtulach@1334
  2700
            super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
jtulach@1334
  2701
                DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
jtulach@1334
  2702
        }
jtulach@1334
  2703
    }
jtulach@1334
  2704
jtulach@1334
  2705
    /**
jtulach@1334
  2706
     * Sets the maximum number of digits allowed in the fraction portion of a
jtulach@1334
  2707
     * number.
jtulach@1334
  2708
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2709
     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
jtulach@1334
  2710
     * 340 is used. Negative input values are replaced with 0.
jtulach@1334
  2711
     * @see NumberFormat#setMaximumFractionDigits
jtulach@1334
  2712
     */
jtulach@1334
  2713
    public void setMaximumFractionDigits(int newValue) {
jtulach@1334
  2714
        maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
jtulach@1334
  2715
        super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
jtulach@1334
  2716
            DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
jtulach@1334
  2717
        if (minimumFractionDigits > maximumFractionDigits) {
jtulach@1334
  2718
            minimumFractionDigits = maximumFractionDigits;
jtulach@1334
  2719
            super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
jtulach@1334
  2720
                DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
jtulach@1334
  2721
        }
jtulach@1334
  2722
    }
jtulach@1334
  2723
jtulach@1334
  2724
    /**
jtulach@1334
  2725
     * Sets the minimum number of digits allowed in the fraction portion of a
jtulach@1334
  2726
     * number.
jtulach@1334
  2727
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2728
     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
jtulach@1334
  2729
     * 340 is used. Negative input values are replaced with 0.
jtulach@1334
  2730
     * @see NumberFormat#setMinimumFractionDigits
jtulach@1334
  2731
     */
jtulach@1334
  2732
    public void setMinimumFractionDigits(int newValue) {
jtulach@1334
  2733
        minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
jtulach@1334
  2734
        super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
jtulach@1334
  2735
            DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
jtulach@1334
  2736
        if (minimumFractionDigits > maximumFractionDigits) {
jtulach@1334
  2737
            maximumFractionDigits = minimumFractionDigits;
jtulach@1334
  2738
            super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
jtulach@1334
  2739
                DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
jtulach@1334
  2740
        }
jtulach@1334
  2741
    }
jtulach@1334
  2742
jtulach@1334
  2743
    /**
jtulach@1334
  2744
     * Gets the maximum number of digits allowed in the integer portion of a
jtulach@1334
  2745
     * number.
jtulach@1334
  2746
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2747
     * <code>BigDecimal</code> objects, the lower of the return value and
jtulach@1334
  2748
     * 309 is used.
jtulach@1334
  2749
     * @see #setMaximumIntegerDigits
jtulach@1334
  2750
     */
jtulach@1334
  2751
    public int getMaximumIntegerDigits() {
jtulach@1334
  2752
        return maximumIntegerDigits;
jtulach@1334
  2753
    }
jtulach@1334
  2754
jtulach@1334
  2755
    /**
jtulach@1334
  2756
     * Gets the minimum number of digits allowed in the integer portion of a
jtulach@1334
  2757
     * number.
jtulach@1334
  2758
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2759
     * <code>BigDecimal</code> objects, the lower of the return value and
jtulach@1334
  2760
     * 309 is used.
jtulach@1334
  2761
     * @see #setMinimumIntegerDigits
jtulach@1334
  2762
     */
jtulach@1334
  2763
    public int getMinimumIntegerDigits() {
jtulach@1334
  2764
        return minimumIntegerDigits;
jtulach@1334
  2765
    }
jtulach@1334
  2766
jtulach@1334
  2767
    /**
jtulach@1334
  2768
     * Gets the maximum number of digits allowed in the fraction portion of a
jtulach@1334
  2769
     * number.
jtulach@1334
  2770
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2771
     * <code>BigDecimal</code> objects, the lower of the return value and
jtulach@1334
  2772
     * 340 is used.
jtulach@1334
  2773
     * @see #setMaximumFractionDigits
jtulach@1334
  2774
     */
jtulach@1334
  2775
    public int getMaximumFractionDigits() {
jtulach@1334
  2776
        return maximumFractionDigits;
jtulach@1334
  2777
    }
jtulach@1334
  2778
jtulach@1334
  2779
    /**
jtulach@1334
  2780
     * Gets the minimum number of digits allowed in the fraction portion of a
jtulach@1334
  2781
     * number.
jtulach@1334
  2782
     * For formatting numbers other than <code>BigInteger</code> and
jtulach@1334
  2783
     * <code>BigDecimal</code> objects, the lower of the return value and
jtulach@1334
  2784
     * 340 is used.
jtulach@1334
  2785
     * @see #setMinimumFractionDigits
jtulach@1334
  2786
     */
jtulach@1334
  2787
    public int getMinimumFractionDigits() {
jtulach@1334
  2788
        return minimumFractionDigits;
jtulach@1334
  2789
    }
jtulach@1334
  2790
jtulach@1334
  2791
    /**
jtulach@1334
  2792
     * Gets the currency used by this decimal format when formatting
jtulach@1334
  2793
     * currency values.
jtulach@1334
  2794
     * The currency is obtained by calling
jtulach@1334
  2795
     * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
jtulach@1334
  2796
     * on this number format's symbols.
jtulach@1334
  2797
     *
jtulach@1334
  2798
     * @return the currency used by this decimal format, or <code>null</code>
jtulach@1334
  2799
     * @since 1.4
jtulach@1334
  2800
     */
jtulach@1334
  2801
    public Currency getCurrency() {
jtulach@1334
  2802
        return symbols.getCurrency();
jtulach@1334
  2803
    }
jtulach@1334
  2804
jtulach@1334
  2805
    /**
jtulach@1334
  2806
     * Sets the currency used by this number format when formatting
jtulach@1334
  2807
     * currency values. This does not update the minimum or maximum
jtulach@1334
  2808
     * number of fraction digits used by the number format.
jtulach@1334
  2809
     * The currency is set by calling
jtulach@1334
  2810
     * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
jtulach@1334
  2811
     * on this number format's symbols.
jtulach@1334
  2812
     *
jtulach@1334
  2813
     * @param currency the new currency to be used by this decimal format
jtulach@1334
  2814
     * @exception NullPointerException if <code>currency</code> is null
jtulach@1334
  2815
     * @since 1.4
jtulach@1334
  2816
     */
jtulach@1334
  2817
    public void setCurrency(Currency currency) {
jtulach@1334
  2818
        if (currency != symbols.getCurrency()) {
jtulach@1334
  2819
            symbols.setCurrency(currency);
jtulach@1334
  2820
            if (isCurrencyFormat) {
jtulach@1334
  2821
                expandAffixes();
jtulach@1334
  2822
            }
jtulach@1334
  2823
        }
jtulach@1334
  2824
    }
jtulach@1334
  2825
jtulach@1334
  2826
    /**
jtulach@1334
  2827
     * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
jtulach@1334
  2828
     *
jtulach@1334
  2829
     * @return The <code>RoundingMode</code> used for this DecimalFormat.
jtulach@1334
  2830
     * @see #setRoundingMode(RoundingMode)
jtulach@1334
  2831
     * @since 1.6
jtulach@1334
  2832
     */
jtulach@1334
  2833
    public RoundingMode getRoundingMode() {
jtulach@1334
  2834
        return roundingMode;
jtulach@1334
  2835
    }
jtulach@1334
  2836
jtulach@1334
  2837
    /**
jtulach@1334
  2838
     * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
jtulach@1334
  2839
     *
jtulach@1334
  2840
     * @param roundingMode The <code>RoundingMode</code> to be used
jtulach@1334
  2841
     * @see #getRoundingMode()
jtulach@1334
  2842
     * @exception NullPointerException if <code>roundingMode</code> is null.
jtulach@1334
  2843
     * @since 1.6
jtulach@1334
  2844
     */
jtulach@1334
  2845
    public void setRoundingMode(RoundingMode roundingMode) {
jtulach@1334
  2846
        if (roundingMode == null) {
jtulach@1334
  2847
            throw new NullPointerException();
jtulach@1334
  2848
        }
jtulach@1334
  2849
jtulach@1334
  2850
        this.roundingMode = roundingMode;
jtulach@1334
  2851
        digitList.setRoundingMode(roundingMode);
jtulach@1334
  2852
    }
jtulach@1334
  2853
jtulach@1334
  2854
    /**
jtulach@1334
  2855
     * Adjusts the minimum and maximum fraction digits to values that
jtulach@1334
  2856
     * are reasonable for the currency's default fraction digits.
jtulach@1334
  2857
     */
jtulach@1334
  2858
    void adjustForCurrencyDefaultFractionDigits() {
jtulach@1334
  2859
        Currency currency = symbols.getCurrency();
jtulach@1334
  2860
        if (currency == null) {
jtulach@1334
  2861
            try {
jtulach@1334
  2862
                currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
jtulach@1334
  2863
            } catch (IllegalArgumentException e) {
jtulach@1334
  2864
            }
jtulach@1334
  2865
        }
jtulach@1334
  2866
        if (currency != null) {
jtulach@1334
  2867
            int digits = currency.getDefaultFractionDigits();
jtulach@1334
  2868
            if (digits != -1) {
jtulach@1334
  2869
                int oldMinDigits = getMinimumFractionDigits();
jtulach@1334
  2870
                // Common patterns are "#.##", "#.00", "#".
jtulach@1334
  2871
                // Try to adjust all of them in a reasonable way.
jtulach@1334
  2872
                if (oldMinDigits == getMaximumFractionDigits()) {
jtulach@1334
  2873
                    setMinimumFractionDigits(digits);
jtulach@1334
  2874
                    setMaximumFractionDigits(digits);
jtulach@1334
  2875
                } else {
jtulach@1334
  2876
                    setMinimumFractionDigits(Math.min(digits, oldMinDigits));
jtulach@1334
  2877
                    setMaximumFractionDigits(digits);
jtulach@1334
  2878
                }
jtulach@1334
  2879
            }
jtulach@1334
  2880
        }
jtulach@1334
  2881
    }
jtulach@1334
  2882
jtulach@1334
  2883
    /**
jtulach@1334
  2884
     * Reads the default serializable fields from the stream and performs
jtulach@1334
  2885
     * validations and adjustments for older serialized versions. The
jtulach@1334
  2886
     * validations and adjustments are:
jtulach@1334
  2887
     * <ol>
jtulach@1334
  2888
     * <li>
jtulach@1334
  2889
     * Verify that the superclass's digit count fields correctly reflect
jtulach@1334
  2890
     * the limits imposed on formatting numbers other than
jtulach@1334
  2891
     * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
jtulach@1334
  2892
     * limits are stored in the superclass for serialization compatibility
jtulach@1334
  2893
     * with older versions, while the limits for <code>BigInteger</code> and
jtulach@1334
  2894
     * <code>BigDecimal</code> objects are kept in this class.
jtulach@1334
  2895
     * If, in the superclass, the minimum or maximum integer digit count is
jtulach@1334
  2896
     * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
jtulach@1334
  2897
     * maximum fraction digit count is larger than
jtulach@1334
  2898
     * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
jtulach@1334
  2899
     * and this method throws an <code>InvalidObjectException</code>.
jtulach@1334
  2900
     * <li>
jtulach@1334
  2901
     * If <code>serialVersionOnStream</code> is less than 4, initialize
jtulach@1334
  2902
     * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
jtulach@1334
  2903
     * RoundingMode.HALF_EVEN}.  This field is new with version 4.
jtulach@1334
  2904
     * <li>
jtulach@1334
  2905
     * If <code>serialVersionOnStream</code> is less than 3, then call
jtulach@1334
  2906
     * the setters for the minimum and maximum integer and fraction digits with
jtulach@1334
  2907
     * the values of the corresponding superclass getters to initialize the
jtulach@1334
  2908
     * fields in this class. The fields in this class are new with version 3.
jtulach@1334
  2909
     * <li>
jtulach@1334
  2910
     * If <code>serialVersionOnStream</code> is less than 1, indicating that
jtulach@1334
  2911
     * the stream was written by JDK 1.1, initialize
jtulach@1334
  2912
     * <code>useExponentialNotation</code>
jtulach@1334
  2913
     * to false, since it was not present in JDK 1.1.
jtulach@1334
  2914
     * <li>
jtulach@1334
  2915
     * Set <code>serialVersionOnStream</code> to the maximum allowed value so
jtulach@1334
  2916
     * that default serialization will work properly if this object is streamed
jtulach@1334
  2917
     * out again.
jtulach@1334
  2918
     * </ol>
jtulach@1334
  2919
     *
jtulach@1334
  2920
     * <p>Stream versions older than 2 will not have the affix pattern variables
jtulach@1334
  2921
     * <code>posPrefixPattern</code> etc.  As a result, they will be initialized
jtulach@1334
  2922
     * to <code>null</code>, which means the affix strings will be taken as
jtulach@1334
  2923
     * literal values.  This is exactly what we want, since that corresponds to
jtulach@1334
  2924
     * the pre-version-2 behavior.
jtulach@1334
  2925
     */
jtulach@1334
  2926
    private void readObject(ObjectInputStream stream)
jtulach@1334
  2927
         throws IOException, ClassNotFoundException
jtulach@1334
  2928
    {
jtulach@1334
  2929
        stream.defaultReadObject();
jtulach@1334
  2930
        digitList = new DigitList();
jtulach@1334
  2931
jtulach@1334
  2932
        if (serialVersionOnStream < 4) {
jtulach@1334
  2933
            setRoundingMode(RoundingMode.HALF_EVEN);
jtulach@1334
  2934
        }
jtulach@1334
  2935
        // We only need to check the maximum counts because NumberFormat
jtulach@1334
  2936
        // .readObject has already ensured that the maximum is greater than the
jtulach@1334
  2937
        // minimum count.
jtulach@1334
  2938
        if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
jtulach@1334
  2939
            super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
jtulach@1334
  2940
            throw new InvalidObjectException("Digit count out of range");
jtulach@1334
  2941
        }
jtulach@1334
  2942
        if (serialVersionOnStream < 3) {
jtulach@1334
  2943
            setMaximumIntegerDigits(super.getMaximumIntegerDigits());
jtulach@1334
  2944
            setMinimumIntegerDigits(super.getMinimumIntegerDigits());
jtulach@1334
  2945
            setMaximumFractionDigits(super.getMaximumFractionDigits());
jtulach@1334
  2946
            setMinimumFractionDigits(super.getMinimumFractionDigits());
jtulach@1334
  2947
        }
jtulach@1334
  2948
        if (serialVersionOnStream < 1) {
jtulach@1334
  2949
            // Didn't have exponential fields
jtulach@1334
  2950
            useExponentialNotation = false;
jtulach@1334
  2951
        }
jtulach@1334
  2952
        serialVersionOnStream = currentSerialVersion;
jtulach@1334
  2953
    }
jtulach@1334
  2954
jtulach@1334
  2955
    //----------------------------------------------------------------------
jtulach@1334
  2956
    // INSTANCE VARIABLES
jtulach@1334
  2957
    //----------------------------------------------------------------------
jtulach@1334
  2958
jtulach@1334
  2959
    private transient DigitList digitList = new DigitList();
jtulach@1334
  2960
jtulach@1334
  2961
    /**
jtulach@1334
  2962
     * The symbol used as a prefix when formatting positive numbers, e.g. "+".
jtulach@1334
  2963
     *
jtulach@1334
  2964
     * @serial
jtulach@1334
  2965
     * @see #getPositivePrefix
jtulach@1334
  2966
     */
jtulach@1334
  2967
    private String  positivePrefix = "";
jtulach@1334
  2968
jtulach@1334
  2969
    /**
jtulach@1334
  2970
     * The symbol used as a suffix when formatting positive numbers.
jtulach@1334
  2971
     * This is often an empty string.
jtulach@1334
  2972
     *
jtulach@1334
  2973
     * @serial
jtulach@1334
  2974
     * @see #getPositiveSuffix
jtulach@1334
  2975
     */
jtulach@1334
  2976
    private String  positiveSuffix = "";
jtulach@1334
  2977
jtulach@1334
  2978
    /**
jtulach@1334
  2979
     * The symbol used as a prefix when formatting negative numbers, e.g. "-".
jtulach@1334
  2980
     *
jtulach@1334
  2981
     * @serial
jtulach@1334
  2982
     * @see #getNegativePrefix
jtulach@1334
  2983
     */
jtulach@1334
  2984
    private String  negativePrefix = "-";
jtulach@1334
  2985
jtulach@1334
  2986
    /**
jtulach@1334
  2987
     * The symbol used as a suffix when formatting negative numbers.
jtulach@1334
  2988
     * This is often an empty string.
jtulach@1334
  2989
     *
jtulach@1334
  2990
     * @serial
jtulach@1334
  2991
     * @see #getNegativeSuffix
jtulach@1334
  2992
     */
jtulach@1334
  2993
    private String  negativeSuffix = "";
jtulach@1334
  2994
jtulach@1334
  2995
    /**
jtulach@1334
  2996
     * The prefix pattern for non-negative numbers.  This variable corresponds
jtulach@1334
  2997
     * to <code>positivePrefix</code>.
jtulach@1334
  2998
     *
jtulach@1334
  2999
     * <p>This pattern is expanded by the method <code>expandAffix()</code> to
jtulach@1334
  3000
     * <code>positivePrefix</code> to update the latter to reflect changes in
jtulach@1334
  3001
     * <code>symbols</code>.  If this variable is <code>null</code> then
jtulach@1334
  3002
     * <code>positivePrefix</code> is taken as a literal value that does not
jtulach@1334
  3003
     * change when <code>symbols</code> changes.  This variable is always
jtulach@1334
  3004
     * <code>null</code> for <code>DecimalFormat</code> objects older than
jtulach@1334
  3005
     * stream version 2 restored from stream.
jtulach@1334
  3006
     *
jtulach@1334
  3007
     * @serial
jtulach@1334
  3008
     * @since 1.3
jtulach@1334
  3009
     */
jtulach@1334
  3010
    private String posPrefixPattern;
jtulach@1334
  3011
jtulach@1334
  3012
    /**
jtulach@1334
  3013
     * The suffix pattern for non-negative numbers.  This variable corresponds
jtulach@1334
  3014
     * to <code>positiveSuffix</code>.  This variable is analogous to
jtulach@1334
  3015
     * <code>posPrefixPattern</code>; see that variable for further
jtulach@1334
  3016
     * documentation.
jtulach@1334
  3017
     *
jtulach@1334
  3018
     * @serial
jtulach@1334
  3019
     * @since 1.3
jtulach@1334
  3020
     */
jtulach@1334
  3021
    private String posSuffixPattern;
jtulach@1334
  3022
jtulach@1334
  3023
    /**
jtulach@1334
  3024
     * The prefix pattern for negative numbers.  This variable corresponds
jtulach@1334
  3025
     * to <code>negativePrefix</code>.  This variable is analogous to
jtulach@1334
  3026
     * <code>posPrefixPattern</code>; see that variable for further
jtulach@1334
  3027
     * documentation.
jtulach@1334
  3028
     *
jtulach@1334
  3029
     * @serial
jtulach@1334
  3030
     * @since 1.3
jtulach@1334
  3031
     */
jtulach@1334
  3032
    private String negPrefixPattern;
jtulach@1334
  3033
jtulach@1334
  3034
    /**
jtulach@1334
  3035
     * The suffix pattern for negative numbers.  This variable corresponds
jtulach@1334
  3036
     * to <code>negativeSuffix</code>.  This variable is analogous to
jtulach@1334
  3037
     * <code>posPrefixPattern</code>; see that variable for further
jtulach@1334
  3038
     * documentation.
jtulach@1334
  3039
     *
jtulach@1334
  3040
     * @serial
jtulach@1334
  3041
     * @since 1.3
jtulach@1334
  3042
     */
jtulach@1334
  3043
    private String negSuffixPattern;
jtulach@1334
  3044
jtulach@1334
  3045
    /**
jtulach@1334
  3046
     * The multiplier for use in percent, per mille, etc.
jtulach@1334
  3047
     *
jtulach@1334
  3048
     * @serial
jtulach@1334
  3049
     * @see #getMultiplier
jtulach@1334
  3050
     */
jtulach@1334
  3051
    private int     multiplier = 1;
jtulach@1334
  3052
jtulach@1334
  3053
    /**
jtulach@1334
  3054
     * The number of digits between grouping separators in the integer
jtulach@1334
  3055
     * portion of a number.  Must be greater than 0 if
jtulach@1334
  3056
     * <code>NumberFormat.groupingUsed</code> is true.
jtulach@1334
  3057
     *
jtulach@1334
  3058
     * @serial
jtulach@1334
  3059
     * @see #getGroupingSize
jtulach@1334
  3060
     * @see java.text.NumberFormat#isGroupingUsed
jtulach@1334
  3061
     */
jtulach@1334
  3062
    private byte    groupingSize = 3;  // invariant, > 0 if useThousands
jtulach@1334
  3063
jtulach@1334
  3064
    /**
jtulach@1334
  3065
     * If true, forces the decimal separator to always appear in a formatted
jtulach@1334
  3066
     * number, even if the fractional part of the number is zero.
jtulach@1334
  3067
     *
jtulach@1334
  3068
     * @serial
jtulach@1334
  3069
     * @see #isDecimalSeparatorAlwaysShown
jtulach@1334
  3070
     */
jtulach@1334
  3071
    private boolean decimalSeparatorAlwaysShown = false;
jtulach@1334
  3072
jtulach@1334
  3073
    /**
jtulach@1334
  3074
     * If true, parse returns BigDecimal wherever possible.
jtulach@1334
  3075
     *
jtulach@1334
  3076
     * @serial
jtulach@1334
  3077
     * @see #isParseBigDecimal
jtulach@1334
  3078
     * @since 1.5
jtulach@1334
  3079
     */
jtulach@1334
  3080
    private boolean parseBigDecimal = false;
jtulach@1334
  3081
jtulach@1334
  3082
jtulach@1334
  3083
    /**
jtulach@1334
  3084
     * True if this object represents a currency format.  This determines
jtulach@1334
  3085
     * whether the monetary decimal separator is used instead of the normal one.
jtulach@1334
  3086
     */
jtulach@1334
  3087
    private transient boolean isCurrencyFormat = false;
jtulach@1334
  3088
jtulach@1334
  3089
    /**
jtulach@1334
  3090
     * The <code>DecimalFormatSymbols</code> object used by this format.
jtulach@1334
  3091
     * It contains the symbols used to format numbers, e.g. the grouping separator,
jtulach@1334
  3092
     * decimal separator, and so on.
jtulach@1334
  3093
     *
jtulach@1334
  3094
     * @serial
jtulach@1334
  3095
     * @see #setDecimalFormatSymbols
jtulach@1334
  3096
     * @see java.text.DecimalFormatSymbols
jtulach@1334
  3097
     */
jtulach@1334
  3098
    private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
jtulach@1334
  3099
jtulach@1334
  3100
    /**
jtulach@1334
  3101
     * True to force the use of exponential (i.e. scientific) notation when formatting
jtulach@1334
  3102
     * numbers.
jtulach@1334
  3103
     *
jtulach@1334
  3104
     * @serial
jtulach@1334
  3105
     * @since 1.2
jtulach@1334
  3106
     */
jtulach@1334
  3107
    private boolean useExponentialNotation;  // Newly persistent in the Java 2 platform v.1.2
jtulach@1334
  3108
jtulach@1334
  3109
    /**
jtulach@1334
  3110
     * FieldPositions describing the positive prefix String. This is
jtulach@1334
  3111
     * lazily created. Use <code>getPositivePrefixFieldPositions</code>
jtulach@1334
  3112
     * when needed.
jtulach@1334
  3113
     */
jtulach@1334
  3114
    private transient FieldPosition[] positivePrefixFieldPositions;
jtulach@1334
  3115
jtulach@1334
  3116
    /**
jtulach@1334
  3117
     * FieldPositions describing the positive suffix String. This is
jtulach@1334
  3118
     * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
jtulach@1334
  3119
     * when needed.
jtulach@1334
  3120
     */
jtulach@1334
  3121
    private transient FieldPosition[] positiveSuffixFieldPositions;
jtulach@1334
  3122
jtulach@1334
  3123
    /**
jtulach@1334
  3124
     * FieldPositions describing the negative prefix String. This is
jtulach@1334
  3125
     * lazily created. Use <code>getNegativePrefixFieldPositions</code>
jtulach@1334
  3126
     * when needed.
jtulach@1334
  3127
     */
jtulach@1334
  3128
    private transient FieldPosition[] negativePrefixFieldPositions;
jtulach@1334
  3129
jtulach@1334
  3130
    /**
jtulach@1334
  3131
     * FieldPositions describing the negative suffix String. This is
jtulach@1334
  3132
     * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
jtulach@1334
  3133
     * when needed.
jtulach@1334
  3134
     */
jtulach@1334
  3135
    private transient FieldPosition[] negativeSuffixFieldPositions;
jtulach@1334
  3136
jtulach@1334
  3137
    /**
jtulach@1334
  3138
     * The minimum number of digits used to display the exponent when a number is
jtulach@1334
  3139
     * formatted in exponential notation.  This field is ignored if
jtulach@1334
  3140
     * <code>useExponentialNotation</code> is not true.
jtulach@1334
  3141
     *
jtulach@1334
  3142
     * @serial
jtulach@1334
  3143
     * @since 1.2
jtulach@1334
  3144
     */
jtulach@1334
  3145
    private byte    minExponentDigits;       // Newly persistent in the Java 2 platform v.1.2
jtulach@1334
  3146
jtulach@1334
  3147
    /**
jtulach@1334
  3148
     * The maximum number of digits allowed in the integer portion of a
jtulach@1334
  3149
     * <code>BigInteger</code> or <code>BigDecimal</code> number.
jtulach@1334
  3150
     * <code>maximumIntegerDigits</code> must be greater than or equal to
jtulach@1334
  3151
     * <code>minimumIntegerDigits</code>.
jtulach@1334
  3152
     *
jtulach@1334
  3153
     * @serial
jtulach@1334
  3154
     * @see #getMaximumIntegerDigits
jtulach@1334
  3155
     * @since 1.5
jtulach@1334
  3156
     */
jtulach@1334
  3157
    private int    maximumIntegerDigits = super.getMaximumIntegerDigits();
jtulach@1334
  3158
jtulach@1334
  3159
    /**
jtulach@1334
  3160
     * The minimum number of digits allowed in the integer portion of a
jtulach@1334
  3161
     * <code>BigInteger</code> or <code>BigDecimal</code> number.
jtulach@1334
  3162
     * <code>minimumIntegerDigits</code> must be less than or equal to
jtulach@1334
  3163
     * <code>maximumIntegerDigits</code>.
jtulach@1334
  3164
     *
jtulach@1334
  3165
     * @serial
jtulach@1334
  3166
     * @see #getMinimumIntegerDigits
jtulach@1334
  3167
     * @since 1.5
jtulach@1334
  3168
     */
jtulach@1334
  3169
    private int    minimumIntegerDigits = super.getMinimumIntegerDigits();
jtulach@1334
  3170
jtulach@1334
  3171
    /**
jtulach@1334
  3172
     * The maximum number of digits allowed in the fractional portion of a
jtulach@1334
  3173
     * <code>BigInteger</code> or <code>BigDecimal</code> number.
jtulach@1334
  3174
     * <code>maximumFractionDigits</code> must be greater than or equal to
jtulach@1334
  3175
     * <code>minimumFractionDigits</code>.
jtulach@1334
  3176
     *
jtulach@1334
  3177
     * @serial
jtulach@1334
  3178
     * @see #getMaximumFractionDigits
jtulach@1334
  3179
     * @since 1.5
jtulach@1334
  3180
     */
jtulach@1334
  3181
    private int    maximumFractionDigits = super.getMaximumFractionDigits();
jtulach@1334
  3182
jtulach@1334
  3183
    /**
jtulach@1334
  3184
     * The minimum number of digits allowed in the fractional portion of a
jtulach@1334
  3185
     * <code>BigInteger</code> or <code>BigDecimal</code> number.
jtulach@1334
  3186
     * <code>minimumFractionDigits</code> must be less than or equal to
jtulach@1334
  3187
     * <code>maximumFractionDigits</code>.
jtulach@1334
  3188
     *
jtulach@1334
  3189
     * @serial
jtulach@1334
  3190
     * @see #getMinimumFractionDigits
jtulach@1334
  3191
     * @since 1.5
jtulach@1334
  3192
     */
jtulach@1334
  3193
    private int    minimumFractionDigits = super.getMinimumFractionDigits();
jtulach@1334
  3194
jtulach@1334
  3195
    /**
jtulach@1334
  3196
     * The {@link java.math.RoundingMode} used in this DecimalFormat.
jtulach@1334
  3197
     *
jtulach@1334
  3198
     * @serial
jtulach@1334
  3199
     * @since 1.6
jtulach@1334
  3200
     */
jtulach@1334
  3201
    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
jtulach@1334
  3202
jtulach@1334
  3203
    //----------------------------------------------------------------------
jtulach@1334
  3204
jtulach@1334
  3205
    static final int currentSerialVersion = 4;
jtulach@1334
  3206
jtulach@1334
  3207
    /**
jtulach@1334
  3208
     * The internal serial version which says which version was written.
jtulach@1334
  3209
     * Possible values are:
jtulach@1334
  3210
     * <ul>
jtulach@1334
  3211
     * <li><b>0</b> (default): versions before the Java 2 platform v1.2
jtulach@1334
  3212
     * <li><b>1</b>: version for 1.2, which includes the two new fields
jtulach@1334
  3213
     *      <code>useExponentialNotation</code> and
jtulach@1334
  3214
     *      <code>minExponentDigits</code>.
jtulach@1334
  3215
     * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
jtulach@1334
  3216
     *      <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
jtulach@1334
  3217
     *      <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
jtulach@1334
  3218
     * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
jtulach@1334
  3219
     *      <code>maximumIntegerDigits</code>,
jtulach@1334
  3220
     *      <code>minimumIntegerDigits</code>,
jtulach@1334
  3221
     *      <code>maximumFractionDigits</code>,
jtulach@1334
  3222
     *      <code>minimumFractionDigits</code>, and
jtulach@1334
  3223
     *      <code>parseBigDecimal</code>.
jtulach@1334
  3224
     * <li><b>4</b>: version for 1.6 and later, which adds one new field:
jtulach@1334
  3225
     *      <code>roundingMode</code>.
jtulach@1334
  3226
     * </ul>
jtulach@1334
  3227
     * @since 1.2
jtulach@1334
  3228
     * @serial
jtulach@1334
  3229
     */
jtulach@1334
  3230
    private int serialVersionOnStream = currentSerialVersion;
jtulach@1334
  3231
jtulach@1334
  3232
    //----------------------------------------------------------------------
jtulach@1334
  3233
    // CONSTANTS
jtulach@1334
  3234
    //----------------------------------------------------------------------
jtulach@1334
  3235
jtulach@1334
  3236
    // Constants for characters used in programmatic (unlocalized) patterns.
jtulach@1334
  3237
    private static final char       PATTERN_ZERO_DIGIT         = '0';
jtulach@1334
  3238
    private static final char       PATTERN_GROUPING_SEPARATOR = ',';
jtulach@1334
  3239
    private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
jtulach@1334
  3240
    private static final char       PATTERN_PER_MILLE          = '\u2030';
jtulach@1334
  3241
    private static final char       PATTERN_PERCENT            = '%';
jtulach@1334
  3242
    private static final char       PATTERN_DIGIT              = '#';
jtulach@1334
  3243
    private static final char       PATTERN_SEPARATOR          = ';';
jtulach@1334
  3244
    private static final String     PATTERN_EXPONENT           = "E";
jtulach@1334
  3245
    private static final char       PATTERN_MINUS              = '-';
jtulach@1334
  3246
jtulach@1334
  3247
    /**
jtulach@1334
  3248
     * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
jtulach@1334
  3249
     * is used in patterns and substituted with either the currency symbol,
jtulach@1334
  3250
     * or if it is doubled, with the international currency symbol.  If the
jtulach@1334
  3251
     * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
jtulach@1334
  3252
     * replaced with the monetary decimal separator.
jtulach@1334
  3253
     *
jtulach@1334
  3254
     * The CURRENCY_SIGN is not localized.
jtulach@1334
  3255
     */
jtulach@1334
  3256
    private static final char       CURRENCY_SIGN = '\u00A4';
jtulach@1334
  3257
jtulach@1334
  3258
    private static final char       QUOTE = '\'';
jtulach@1334
  3259
jtulach@1334
  3260
    private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
jtulach@1334
  3261
jtulach@1334
  3262
    // Upper limit on integer and fraction digits for a Java double
jtulach@1334
  3263
    static final int DOUBLE_INTEGER_DIGITS  = 309;
jtulach@1334
  3264
    static final int DOUBLE_FRACTION_DIGITS = 340;
jtulach@1334
  3265
jtulach@1334
  3266
    // Upper limit on integer and fraction digits for BigDecimal and BigInteger
jtulach@1334
  3267
    static final int MAXIMUM_INTEGER_DIGITS  = Integer.MAX_VALUE;
jtulach@1334
  3268
    static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
jtulach@1334
  3269
jtulach@1334
  3270
    // Proclaim JDK 1.1 serial compatibility.
jtulach@1334
  3271
    static final long serialVersionUID = 864413376551465018L;
jtulach@1334
  3272
jtulach@1334
  3273
    /**
jtulach@1334
  3274
     * Cache to hold the NumberPattern of a Locale.
jtulach@1334
  3275
     */
jtulach@1334
  3276
    private static final ConcurrentMap<Locale, String> cachedLocaleData
jtulach@1334
  3277
        = new ConcurrentHashMap<Locale, String>(3);
jtulach@1334
  3278
}