001    /* DecimalFormat.java -- Formats and parses numbers
002       Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010     
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    /* 
039     * This class contains few bits from ICU4J (http://icu.sourceforge.net/),
040     * Copyright by IBM and others and distributed under the
041     * distributed under MIT/X.
042     */
043    
044    package java.text;
045    
046    import java.math.BigDecimal;
047    import java.math.BigInteger;
048    
049    import java.util.ArrayList;
050    import java.util.Currency;
051    import java.util.Locale;
052    
053    /*
054     * This note is here for historical reasons and because I had not the courage
055     * to remove it :)
056     *  
057     * @author Tom Tromey (tromey@cygnus.com)
058     * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
059     * @date March 4, 1999
060     *
061     * Written using "Java Class Libraries", 2nd edition, plus online
062     * API docs for JDK 1.2 from http://www.javasoft.com.
063     * Status:  Believed complete and correct to 1.2.
064     * Note however that the docs are very unclear about how format parsing
065     * should work.  No doubt there are problems here.
066     */
067    
068    /**
069     * This class is a concrete implementation of NumberFormat used to format
070     * decimal numbers. The class can format numbers given a specific locale.
071     * Generally, to get an instance of DecimalFormat you should call the factory
072     * methods in the <code>NumberFormat</code> base class.
073     * 
074     * @author Mario Torre <neugens@limasoftware.net>
075     * @author Tom Tromey (tromey@cygnus.com)
076     * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
077     */
078    public class DecimalFormat extends NumberFormat
079    {
080      /** serialVersionUID for serializartion. */
081      private static final long serialVersionUID = 864413376551465018L;
082      
083      /** Defines the default number of digits allowed while formatting integers. */
084      private static final int DEFAULT_INTEGER_DIGITS = 309; 
085    
086      /**
087       * Defines the default number of digits allowed while formatting
088       * fractions.
089       */
090      private static final int DEFAULT_FRACTION_DIGITS = 340;
091      
092      /**
093       * Locale-independent pattern symbols.
094       */
095      // Happen to be the same as the US symbols.
096      private static final DecimalFormatSymbols nonLocalizedSymbols
097        = new DecimalFormatSymbols (Locale.US);
098      
099      /**
100       * Defines if parse should return a BigDecimal or not.
101       */
102      private boolean parseBigDecimal;
103      
104      /**
105       * Defines if we have to use the monetary decimal separator or
106       * the decimal separator while formatting numbers.
107       */
108      private boolean useCurrencySeparator;
109        
110      /** Defines if the decimal separator is always shown or not. */
111      private boolean decimalSeparatorAlwaysShown;
112      
113      /**
114       * Defines if the decimal separator has to be shown.
115       * 
116       * This is different then <code>decimalSeparatorAlwaysShown</code>,
117       * as it defines if the format string contains a decimal separator or no.
118       */
119      private boolean showDecimalSeparator;
120      
121      /**
122       * This field is used to determine if the grouping
123       * separator is included in the format string or not.
124       * This is only needed to match the behaviour of the RI.
125       */
126      private boolean groupingSeparatorInPattern;
127      
128      /** Defines the size of grouping groups when grouping is used. */
129      private byte groupingSize;
130      
131      /**
132       * This is an internal parameter used to keep track of the number
133       * of digits the form the exponent, when exponential notation is used.
134       * It is used with <code>exponentRound</code>
135       */
136      private byte minExponentDigits;
137     
138      /** This field is used to set the exponent in the engineering notation. */
139      private int exponentRound;
140      
141      /** Multiplier used in percent style formats. */
142      private int multiplier;
143      
144      /** Multiplier used in percent style formats. */
145      private int negativePatternMultiplier;
146      
147      /** The negative prefix. */
148      private String negativePrefix;
149      
150      /** The negative suffix. */
151      private String negativeSuffix;
152      
153      /** The positive prefix. */
154      private String positivePrefix;
155      
156      /** The positive suffix. */
157      private String positiveSuffix;
158      
159      /** Decimal Format Symbols for the given locale. */
160      private DecimalFormatSymbols symbols;
161      
162      /** Determine if we have to use exponential notation or not. */
163      private boolean useExponentialNotation;
164      
165      /**
166       * Defines the maximum number of integer digits to show when we use
167       * the exponential notation.
168       */
169      private int maxIntegerDigitsExponent;
170      
171      /** Defines if the format string has a negative prefix or not. */
172      private boolean hasNegativePrefix;
173      
174      /** Defines if the format string has a fractional pattern or not. */
175      private boolean hasFractionalPattern;
176     
177      /** Stores a list of attributes for use by formatToCharacterIterator. */
178      private ArrayList attributes = new ArrayList();
179      
180      /**
181       * Constructs a <code>DecimalFormat</code> which uses the default
182       * pattern and symbols.
183       */
184      public DecimalFormat()
185      {
186        this ("#,##0.###");
187      }
188      
189      /**
190       * Constructs a <code>DecimalFormat</code> which uses the given
191       * pattern and the default symbols for formatting and parsing.
192       *
193       * @param pattern the non-localized pattern to use.
194       * @throws NullPointerException if any argument is null.
195       * @throws IllegalArgumentException if the pattern is invalid.
196       */
197      public DecimalFormat(String pattern)
198      {
199        this (pattern, new DecimalFormatSymbols());
200      }
201    
202      /**
203       * Constructs a <code>DecimalFormat</code> using the given pattern
204       * and formatting symbols.  This construction method is used to give
205       * complete control over the formatting process.  
206       *
207       * @param pattern the non-localized pattern to use.
208       * @param symbols the set of symbols used for parsing and formatting.
209       * @throws NullPointerException if any argument is null.
210       * @throws IllegalArgumentException if the pattern is invalid.
211       */
212      public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
213      {
214        this.symbols = (DecimalFormatSymbols) symbols.clone();
215        applyPatternWithSymbols(pattern, nonLocalizedSymbols);
216      }
217      
218      /**
219       * Apply the given localized patern to the current DecimalFormat object.
220       * 
221       * @param pattern The localized pattern to apply.
222       * @throws IllegalArgumentException if the given pattern is invalid.
223       * @throws NullPointerException if the input pattern is null.
224       */
225      public void applyLocalizedPattern (String pattern)
226      {
227        applyPatternWithSymbols(pattern, this.symbols);
228      }
229    
230      /**
231       * Apply the given localized pattern to the current DecimalFormat object.
232       * 
233       * @param pattern The localized pattern to apply.
234       * @throws IllegalArgumentException if the given pattern is invalid.
235       * @throws NullPointerException if the input pattern is null.
236       */
237      public void applyPattern(String pattern)
238      {
239        applyPatternWithSymbols(pattern, nonLocalizedSymbols);
240      }
241    
242      public Object clone()
243      {
244        DecimalFormat c = (DecimalFormat) super.clone();
245        c.symbols = (DecimalFormatSymbols) symbols.clone();
246        return c;
247      }
248    
249      /**
250       * Tests this instance for equality with an arbitrary object.  This method
251       * returns <code>true</code> if:
252       * <ul>
253       * <li><code>obj</code> is not <code>null</code>;</li>
254       * <li><code>obj</code> is an instance of <code>DecimalFormat</code>;</li>
255       * <li>this instance and <code>obj</code> have the same attributes;</li>
256       * </ul>
257       * 
258       * @param obj  the object (<code>null</code> permitted).
259       * 
260       * @return A boolean.
261       */
262      public boolean equals(Object obj)
263      {
264        if (! (obj instanceof DecimalFormat))
265          return false;
266        DecimalFormat dup = (DecimalFormat) obj;
267        return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown 
268               && groupingUsed == dup.groupingUsed
269               && groupingSeparatorInPattern == dup.groupingSeparatorInPattern 
270               && groupingSize == dup.groupingSize
271               && multiplier == dup.multiplier
272               && useExponentialNotation == dup.useExponentialNotation
273               && minExponentDigits == dup.minExponentDigits
274               && minimumIntegerDigits == dup.minimumIntegerDigits
275               && maximumIntegerDigits == dup.maximumIntegerDigits
276               && minimumFractionDigits == dup.minimumFractionDigits
277               && maximumFractionDigits == dup.maximumFractionDigits
278               && parseBigDecimal == dup.parseBigDecimal
279               && useCurrencySeparator == dup.useCurrencySeparator
280               && showDecimalSeparator == dup.showDecimalSeparator
281               && exponentRound == dup.exponentRound
282               && negativePatternMultiplier == dup.negativePatternMultiplier
283               && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent
284               // XXX: causes equivalent patterns to fail
285               // && hasNegativePrefix == dup.hasNegativePrefix
286               && equals(negativePrefix, dup.negativePrefix)
287               && equals(negativeSuffix, dup.negativeSuffix)
288               && equals(positivePrefix, dup.positivePrefix)
289               && equals(positiveSuffix, dup.positiveSuffix)
290               && symbols.equals(dup.symbols));
291      }
292    
293      /**
294       * Returns a hash code for this object.
295       *
296       * @return A hash code.
297       */
298      public int hashCode()
299      {
300        return toPattern().hashCode();
301      }
302      
303      /**
304       * Produce a formatted {@link String} representation of this object.
305       * The passed object must be of type number. 
306       * 
307       * @param obj The {@link Number} to format.
308       * @param sbuf The destination String; text will be appended to this String. 
309       * @param pos If used on input can be used to define an alignment
310       * field. If used on output defines the offsets of the alignment field.
311       * @return The String representation of this long.
312       */
313      public StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos)
314      {
315        if (obj instanceof BigInteger)
316          {
317            BigDecimal decimal = new BigDecimal((BigInteger) obj);
318            formatInternal(decimal, true, sbuf, pos);
319            return sbuf;
320          }
321        else if (obj instanceof BigDecimal)
322          {
323            formatInternal((BigDecimal) obj, true, sbuf, pos);
324            return sbuf;
325          }
326        
327        return super.format(obj, sbuf, pos);
328      }
329      
330      /**
331       * Produce a formatted {@link String} representation of this double.
332       * 
333       * @param number The double to format.
334       * @param dest The destination String; text will be appended to this String. 
335       * @param fieldPos If used on input can be used to define an alignment
336       * field. If used on output defines the offsets of the alignment field.
337       * @return The String representation of this long.
338       * @throws NullPointerException if <code>dest</code> or fieldPos are null
339       */
340      public StringBuffer format(double number, StringBuffer dest,
341                                 FieldPosition fieldPos)
342      {
343        // special cases for double: NaN and negative or positive infinity
344        if (Double.isNaN(number))
345          {
346            // 1. NaN
347            String nan = symbols.getNaN();
348            dest.append(nan);
349            
350            // update field position if required
351            if ((fieldPos.getField() == INTEGER_FIELD ||
352                 fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
353              {
354                int index = dest.length();
355                fieldPos.setBeginIndex(index - nan.length());
356                fieldPos.setEndIndex(index);
357              }
358          }
359        else if (Double.isInfinite(number))
360          {
361            // 2. Infinity
362            if (number < 0)
363              dest.append(this.negativePrefix);
364            else
365              dest.append(this.positivePrefix);
366            
367            dest.append(symbols.getInfinity());
368            
369            if (number < 0)
370              dest.append(this.negativeSuffix);
371            else
372              dest.append(this.positiveSuffix);
373            
374            if ((fieldPos.getField() == INTEGER_FIELD ||
375                fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
376             {
377               fieldPos.setBeginIndex(dest.length());
378               fieldPos.setEndIndex(0);
379             }
380          }
381        else
382          {
383            // get the number as a BigDecimal
384            BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
385            formatInternal(bigDecimal, false, dest, fieldPos);
386          }
387        
388        return dest;
389      }
390    
391      /**
392       * Produce a formatted {@link String} representation of this long.
393       * 
394       * @param number The long to format.
395       * @param dest The destination String; text will be appended to this String. 
396       * @param fieldPos If used on input can be used to define an alignment
397       * field. If used on output defines the offsets of the alignment field.
398       * @return The String representation of this long.
399       */
400      public StringBuffer format(long number, StringBuffer dest,
401                                 FieldPosition fieldPos)
402      {
403        BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
404        formatInternal(bigDecimal, true, dest, fieldPos);
405        return dest;
406      }
407      
408      /**
409       * Return an <code>AttributedCharacterIterator</code> as a result of
410       * the formatting of the passed {@link Object}.
411       * 
412       * @return An {@link AttributedCharacterIterator}.
413       * @throws NullPointerException if value is <code>null</code>. 
414       * @throws IllegalArgumentException if value is not an instance of
415       * {@link Number}.
416       */
417      public AttributedCharacterIterator formatToCharacterIterator(Object value)
418      {
419        /*
420         * This method implementation derives directly from the
421         * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
422         */
423        
424        if (value == null)
425          throw new NullPointerException("Passed Object is null");
426        
427        if (!(value instanceof Number)) throw new
428          IllegalArgumentException("Cannot format given Object as a Number");
429        
430        StringBuffer text = new StringBuffer();
431        attributes.clear();
432        super.format(value, text, new FieldPosition(0));
433    
434        AttributedString as = new AttributedString(text.toString());
435    
436        // add NumberFormat field attributes to the AttributedString
437        for (int i = 0; i < attributes.size(); i++)
438          {
439            FieldPosition pos = (FieldPosition) attributes.get(i);
440            Format.Field attribute = pos.getFieldAttribute();
441            
442            as.addAttribute(attribute, attribute, pos.getBeginIndex(),
443                            pos.getEndIndex());
444          }
445        
446        // return the CharacterIterator from AttributedString
447        return as.getIterator();
448      }
449      
450      /**
451       * Returns the currency corresponding to the currency symbol stored
452       * in the instance of <code>DecimalFormatSymbols</code> used by this
453       * <code>DecimalFormat</code>.
454       *
455       * @return A new instance of <code>Currency</code> if
456       * the currency code matches a known one, null otherwise.
457       */
458      public Currency getCurrency()
459      {
460        return symbols.getCurrency();
461      }
462      
463      /**
464       * Returns a copy of the symbols used by this instance.
465       * 
466       * @return A copy of the symbols.
467       */
468      public DecimalFormatSymbols getDecimalFormatSymbols()
469      {
470        return (DecimalFormatSymbols) symbols.clone();
471      }
472      
473      /**
474       * Gets the interval used between a grouping separator and the next.
475       * For example, a grouping size of 3 means that the number 1234 is
476       * formatted as 1,234.
477       * 
478       * The actual character used as grouping separator depends on the
479       * locale and is defined by {@link DecimalFormatSymbols#getDecimalSeparator()}
480       * 
481       * @return The interval used between a grouping separator and the next.
482       */
483      public int getGroupingSize()
484      {
485        return groupingSize;
486      }
487    
488      /**
489       * Gets the multiplier used in percent and similar formats.
490       * 
491       * @return The multiplier used in percent and similar formats.
492       */
493      public int getMultiplier()
494      {
495        return multiplier;
496      }
497      
498      /**
499       * Gets the negative prefix.
500       * 
501       * @return The negative prefix.
502       */
503      public String getNegativePrefix()
504      {
505        return negativePrefix;
506      }
507    
508      /**
509       * Gets the negative suffix.
510       * 
511       * @return The negative suffix.
512       */
513      public String getNegativeSuffix()
514      {
515        return negativeSuffix;
516      }
517      
518      /**
519       * Gets the positive prefix.
520       * 
521       * @return The positive prefix.
522       */
523      public String getPositivePrefix()
524      {
525        return positivePrefix;
526      }
527      
528      /**
529       * Gets the positive suffix.
530       *  
531       * @return The positive suffix.
532       */
533      public String getPositiveSuffix()
534      {
535        return positiveSuffix;
536      }
537      
538      public boolean isDecimalSeparatorAlwaysShown()
539      {
540        return decimalSeparatorAlwaysShown;
541      }
542      
543      /**
544       * Define if <code>parse(java.lang.String, java.text.ParsePosition)</code>
545       * should return a {@link BigDecimal} or not. 
546       * 
547       * @param newValue
548       */
549      public void setParseBigDecimal(boolean newValue)
550      {
551        this.parseBigDecimal = newValue;
552      }
553      
554      /**
555       * Returns <code>true</code> if
556       * <code>parse(java.lang.String, java.text.ParsePosition)</code> returns
557       * a <code>BigDecimal</code>, <code>false</code> otherwise.
558       * The default return value for this method is <code>false</code>.
559       * 
560       * @return <code>true</code> if the parse method returns a {@link BigDecimal},
561       * <code>false</code> otherwise.
562       * @since 1.5
563       * @see #setParseBigDecimal(boolean)
564       */
565      public boolean isParseBigDecimal()
566      {
567        return this.parseBigDecimal;
568      }
569      
570      /**
571       * This method parses the specified string into a <code>Number</code>.
572       * 
573       * The parsing starts at <code>pos</code>, which is updated as the parser
574       * consume characters in the passed string.
575       * On error, the <code>Position</code> object index is not updated, while
576       * error position is set appropriately, an <code>null</code> is returned.
577       * 
578       * @param str The string to parse.
579       * @param pos The desired <code>ParsePosition</code>.
580       *
581       * @return The parsed <code>Number</code>
582       */
583      public Number parse(String str, ParsePosition pos)
584      {
585        // a special values before anything else
586        // NaN
587        if (str.contains(this.symbols.getNaN()))
588          return Double.valueOf(Double.NaN);
589       
590        // this will be our final number
591        StringBuffer number = new StringBuffer();
592        
593        // special character
594        char minus = symbols.getMinusSign();
595        
596        // starting parsing position
597        int start = pos.getIndex();
598        
599        // validate the string, it have to be in the 
600        // same form as the format string or parsing will fail
601        String _negativePrefix = (this.negativePrefix.compareTo("") == 0
602                                  ? minus + positivePrefix
603                                  : this.negativePrefix);
604        
605        // we check both prefixes, because one might be empty.
606        // We want to pick the longest prefix that matches.
607        int positiveLen = positivePrefix.length();
608        int negativeLen = _negativePrefix.length();
609        
610        boolean isNegative = str.startsWith(_negativePrefix);
611        boolean isPositive = str.startsWith(positivePrefix);
612        
613        if (isPositive && isNegative)
614          {
615            // By checking this way, we preserve ambiguity in the case
616            // where the negative format differs only in suffix.
617            if (negativeLen > positiveLen)
618              {
619                start += _negativePrefix.length();
620                isNegative = true;
621              }
622            else
623              {
624                start += positivePrefix.length();
625                isPositive = true;
626                if (negativeLen < positiveLen)
627                  isNegative = false;
628              }
629          }
630        else if (isNegative)
631          {
632            start += _negativePrefix.length();
633            isPositive = false;
634          }
635        else if (isPositive)
636          {
637            start += positivePrefix.length();
638            isNegative = false;
639          }
640        else
641          {
642            pos.setErrorIndex(start);
643            return null;
644          }
645        
646        // other special characters used by the parser
647        char decimalSeparator = symbols.getDecimalSeparator();
648        char zero = symbols.getZeroDigit();
649        char exponent = symbols.getExponential(); 
650        
651        // stop parsing position in the string
652        int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2;
653        
654        if (useExponentialNotation)
655          stop += minExponentDigits + 1;
656        
657        boolean inExponent = false;
658    
659        // correct the size of the end parsing flag
660        int len = str.length();
661        if (len < stop) stop = len;
662        char groupingSeparator = symbols.getGroupingSeparator();
663        
664        int i = start;
665        while (i < stop)
666          {
667            char ch = str.charAt(i);
668            i++;
669           
670            if (ch >= zero && ch <= (zero + 9))
671              {
672                number.append(ch);
673              }
674            else if (this.parseIntegerOnly)
675              {
676                i--;
677                break;
678              }
679            else if (ch == decimalSeparator)
680              {
681                number.append('.');
682              }
683            else if (ch == exponent)
684              {
685                number.append(ch);
686                inExponent = !inExponent;
687              }
688            else if ((ch == '+' || ch == '-' || ch == minus))
689              {
690                if (inExponent)
691                  number.append(ch);
692                else
693                  {
694                    i--;
695                    break;
696                  }
697              }
698            else
699              {
700                if (!groupingUsed || ch != groupingSeparator)
701                  {
702                    i--;
703                    break;
704                  }
705              }
706          }
707    
708        // 2nd special case: infinity
709        // XXX: need to be tested
710        if (str.contains(symbols.getInfinity()))
711          {
712            int inf = str.indexOf(symbols.getInfinity()); 
713            pos.setIndex(inf);
714            
715            // FIXME: ouch, this is really ugly and lazy code...
716            if (this.parseBigDecimal)
717              {
718                if (isNegative)
719                  return new BigDecimal(Double.NEGATIVE_INFINITY);
720                
721                return new BigDecimal(Double.POSITIVE_INFINITY);
722              }
723            
724            if (isNegative)
725              return new Double(Double.NEGATIVE_INFINITY);
726    
727            return new Double(Double.POSITIVE_INFINITY);
728          }
729        
730        // no number...
731        if (i == start || number.length() == 0)
732          {
733            pos.setErrorIndex(i);
734            return null;
735          }
736    
737        // now we have to check the suffix, done here after number parsing
738        // or the index will not be updated correctly...
739        boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
740        boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
741        boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
742    
743        positiveLen = positiveSuffix.length();
744        negativeLen = negativeSuffix.length();
745        
746        if (isNegative && !hasNegativeSuffix)
747          {
748            pos.setErrorIndex(i);
749            return null;
750          }
751        else if (hasNegativeSuffix &&
752                 !positiveEqualsNegative &&
753                 (negativeLen > positiveLen))
754          {
755            isNegative = true;
756          }
757        else if (!hasPositiveSuffix)
758          {
759            pos.setErrorIndex(i);
760            return null;
761          }
762        
763        if (isNegative) number.insert(0, '-');
764       
765        pos.setIndex(i);
766        
767        // now we handle the return type
768        BigDecimal bigDecimal = new BigDecimal(number.toString());
769        if (this.parseBigDecimal)
770          return bigDecimal;
771        
772        // want integer?
773        if (this.parseIntegerOnly)
774          return new Long(bigDecimal.longValue());
775    
776        // 3th special case -0.0
777        if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0))
778          return new Double(-0.0);
779        
780        try
781          {
782            BigDecimal integer
783              = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY);
784            return new Long(integer.longValue());
785          }
786        catch (ArithmeticException e)
787          {
788            return new Double(bigDecimal.doubleValue());
789          }
790      }
791    
792      /**
793       * Sets the <code>Currency</code> on the
794       * <code>DecimalFormatSymbols</code> used, which also sets the
795       * currency symbols on those symbols.
796       * 
797       * @param currency The new <code>Currency</code> on the
798       * <code>DecimalFormatSymbols</code>.
799       */
800      public void setCurrency(Currency currency)
801      {
802        symbols.setCurrency(currency);
803      }
804      
805      /**
806       * Sets the symbols used by this instance.  This method makes a copy of 
807       * the supplied symbols.
808       * 
809       * @param newSymbols  the symbols (<code>null</code> not permitted).
810       */
811      public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
812      {
813        symbols = (DecimalFormatSymbols) newSymbols.clone();
814      }
815      
816      /**
817       * Define if the decimal separator should be always visible or only
818       * visible when needed. This method as effect only on integer values.
819       * Pass <code>true</code> if you want the decimal separator to be
820       * always shown, <code>false</code> otherwise.
821       * 
822       * @param newValue true</code> if you want the decimal separator to be
823       * always shown, <code>false</code> otherwise.
824       */
825      public void setDecimalSeparatorAlwaysShown(boolean newValue)
826      {
827        decimalSeparatorAlwaysShown = newValue;
828      }
829      
830      /**
831       * Sets the number of digits used to group portions of the integer part of
832       * the number. For example, the number <code>123456</code>, with a grouping
833       * size of 3, is rendered <code>123,456</code>.
834       * 
835       * @param groupSize The number of digits used while grouping portions
836       * of the integer part of a number.
837       */
838      public void setGroupingSize(int groupSize)
839      {
840        groupingSize = (byte) groupSize;
841      }
842      
843      /**
844       * Sets the maximum number of digits allowed in the integer
845       * portion of a number to the specified value.
846       * The new value will be the choosen as the minimum between
847       * <code>newvalue</code> and 309. Any value below zero will be
848       * replaced by zero.
849       * 
850       * @param newValue The new maximum integer digits value.
851       */
852      public void setMaximumIntegerDigits(int newValue)
853      {
854        newValue = (newValue > 0) ? newValue : 0;
855        super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
856      }
857      
858      /**
859       * Sets the minimum number of digits allowed in the integer
860       * portion of a number to the specified value.
861       * The new value will be the choosen as the minimum between
862       * <code>newvalue</code> and 309. Any value below zero will be
863       * replaced by zero.
864       * 
865       * @param newValue The new minimum integer digits value.
866       */
867      public void setMinimumIntegerDigits(int newValue)
868      {
869        newValue = (newValue > 0) ? newValue : 0;
870        super.setMinimumIntegerDigits(Math.min(newValue,  DEFAULT_INTEGER_DIGITS));
871      }
872      
873      /**
874       * Sets the maximum number of digits allowed in the fraction
875       * portion of a number to the specified value.
876       * The new value will be the choosen as the minimum between
877       * <code>newvalue</code> and 309. Any value below zero will be
878       * replaced by zero.
879       * 
880       * @param newValue The new maximum fraction digits value.
881       */
882      public void setMaximumFractionDigits(int newValue)
883      {
884        newValue = (newValue > 0) ? newValue : 0;
885        super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
886      }
887      
888      /**
889       * Sets the minimum number of digits allowed in the fraction
890       * portion of a number to the specified value.
891       * The new value will be the choosen as the minimum between
892       * <code>newvalue</code> and 309. Any value below zero will be
893       * replaced by zero.
894       * 
895       * @param newValue The new minimum fraction digits value.
896       */
897      public void setMinimumFractionDigits(int newValue)
898      {
899        newValue = (newValue > 0) ? newValue : 0;
900        super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
901      }
902      
903      /**
904       * Sets the multiplier for use in percent and similar formats.
905       * For example, for percent set the multiplier to 100, for permille, set the
906       * miltiplier to 1000.
907       * 
908       * @param newValue the new value for multiplier.
909       */
910      public void setMultiplier(int newValue)
911      {
912        multiplier = newValue;
913      }
914      
915      /**
916       * Sets the negative prefix.
917       * 
918       * @param newValue The new negative prefix.
919       */
920      public void setNegativePrefix(String newValue)
921      {
922        negativePrefix = newValue;
923      }
924    
925      /**
926       * Sets the negative suffix.
927       * 
928       * @param newValue The new negative suffix.
929       */
930      public void setNegativeSuffix(String newValue)
931      {
932        negativeSuffix = newValue;
933      }
934      
935      /**
936       * Sets the positive prefix.
937       * 
938       * @param newValue The new positive prefix.
939       */
940      public void setPositivePrefix(String newValue)
941      {
942        positivePrefix = newValue;
943      }
944      
945      /**
946       * Sets the new positive suffix.
947       * 
948       * @param newValue The new positive suffix.
949       */
950      public void setPositiveSuffix(String newValue)
951      {
952        positiveSuffix = newValue;
953      }
954      
955      /**
956       * This method returns a string with the formatting pattern being used
957       * by this object. The string is localized.
958       * 
959       * @return A localized <code>String</code> with the formatting pattern.
960       * @see #toPattern()
961       */
962      public String toLocalizedPattern()
963      {
964        return computePattern(this.symbols);
965      }
966      
967      /**
968       * This method returns a string with the formatting pattern being used
969       * by this object. The string is not localized.
970       * 
971       * @return A <code>String</code> with the formatting pattern.
972       * @see #toLocalizedPattern()
973       */
974      public String toPattern()
975      {
976        return computePattern(nonLocalizedSymbols);
977      }
978      
979      /* ***** private methods ***** */
980      
981      /**
982       * This is an shortcut helper method used to test if two given strings are
983       * equals.
984       * 
985       * @param s1 The first string to test for equality.
986       * @param s2 The second string to test for equality.
987       * @return <code>true</code> if the strings are both <code>null</code> or
988       * equals.
989       */
990      private boolean equals(String s1, String s2)
991      {
992        if (s1 == null || s2 == null)
993          return s1 == s2;
994        return s1.equals(s2);
995      }
996      
997      
998      /* ****** PATTERN ****** */
999      
1000      /**
1001       * This helper function creates a string consisting of all the
1002       * characters which can appear in a pattern and must be quoted.
1003       */
1004      private String patternChars (DecimalFormatSymbols syms)
1005      {
1006        StringBuffer buf = new StringBuffer ();
1007        
1008        buf.append(syms.getDecimalSeparator());
1009        buf.append(syms.getDigit());
1010        buf.append(syms.getExponential());
1011        buf.append(syms.getGroupingSeparator());
1012        buf.append(syms.getMinusSign());
1013        buf.append(syms.getPatternSeparator());
1014        buf.append(syms.getPercent());
1015        buf.append(syms.getPerMill());
1016        buf.append(syms.getZeroDigit());
1017        buf.append('\'');
1018        buf.append('\u00a4');
1019        
1020        return buf.toString();
1021      }
1022    
1023      /**
1024       * Quote special characters as defined by <code>patChars</code> in the
1025       * input string.
1026       * 
1027       * @param text
1028       * @param patChars
1029       * @return A StringBuffer with special characters quoted.
1030       */
1031      private StringBuffer quoteFix(String text, String patChars)
1032      {
1033        StringBuffer buf = new StringBuffer();
1034        
1035        int len = text.length();
1036        char ch;
1037        for (int index = 0; index < len; ++index)
1038          {
1039            ch = text.charAt(index);
1040            if (patChars.indexOf(ch) != -1)
1041              {
1042                buf.append('\'');
1043                buf.append(ch);
1044                if (ch != '\'') buf.append('\'');
1045              }
1046            else
1047              {
1048                buf.append(ch);
1049              }
1050          }
1051        
1052        return buf;
1053      }
1054      
1055      /**
1056       * Returns the format pattern, localized to follow the given
1057       * symbols.
1058       */
1059      private String computePattern(DecimalFormatSymbols symbols)
1060      {
1061        StringBuffer mainPattern = new StringBuffer();
1062        
1063        // We have to at least emit a zero for the minimum number of
1064        // digits. Past that we need hash marks up to the grouping
1065        // separator (and one beyond).
1066        int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize;
1067        int totalDigits = Math.max(minimumIntegerDigits, _groupingSize);
1068        
1069        // if it is not in exponential notiation,
1070        // we always have a # prebended
1071        if (!useExponentialNotation) mainPattern.append(symbols.getDigit());
1072        
1073        for (int i = 1; i < totalDigits - minimumIntegerDigits; i++)
1074          mainPattern.append(symbols.getDigit());
1075        
1076        for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++)
1077          mainPattern.append(symbols.getZeroDigit());
1078        
1079        if (groupingUsed)
1080          {
1081            mainPattern.insert(mainPattern.length() - groupingSize,
1082                               symbols.getGroupingSeparator());
1083          }
1084    
1085        // See if we need decimal info.
1086        if (minimumFractionDigits > 0 || maximumFractionDigits > 0 ||
1087            decimalSeparatorAlwaysShown)
1088          {
1089            mainPattern.append(symbols.getDecimalSeparator());
1090          }
1091        
1092        for (int i = 0; i < minimumFractionDigits; ++i)
1093          mainPattern.append(symbols.getZeroDigit());
1094        
1095        for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
1096          mainPattern.append(symbols.getDigit());
1097        
1098        if (useExponentialNotation)
1099          {
1100            mainPattern.append(symbols.getExponential());
1101            
1102            for (int i = 0; i < minExponentDigits; ++i)
1103              mainPattern.append(symbols.getZeroDigit());
1104            
1105            if (minExponentDigits == 0)
1106              mainPattern.append(symbols.getDigit());
1107          }
1108        
1109        // save the pattern
1110        String pattern = mainPattern.toString();
1111        
1112        // so far we have the pattern itself, now we need to add
1113        // the positive and the optional negative prefixes and suffixes
1114        String patternChars = patternChars(symbols);
1115        mainPattern.insert(0, quoteFix(positivePrefix, patternChars));
1116        mainPattern.append(quoteFix(positiveSuffix, patternChars));
1117        
1118        if (hasNegativePrefix)
1119          {
1120            mainPattern.append(symbols.getPatternSeparator());
1121            mainPattern.append(quoteFix(negativePrefix, patternChars));
1122            mainPattern.append(pattern);
1123            mainPattern.append(quoteFix(negativeSuffix, patternChars));
1124          }
1125        
1126        // finally, return the pattern string
1127        return mainPattern.toString();
1128      }
1129      
1130      /* ****** FORMAT PARSING ****** */
1131      
1132      /**
1133       * Scan the input string and define a pattern suitable for use
1134       * with this decimal format.
1135       * 
1136       * @param pattern
1137       * @param symbols
1138       */
1139      private void applyPatternWithSymbols(String pattern,
1140                                           DecimalFormatSymbols symbols)
1141      {
1142        // The pattern string is described by a BNF diagram.
1143        // we could use a recursive parser to read and prepare
1144        // the string, but this would be too slow and resource
1145        // intensive, while this code is quite critical as it is
1146        // called always when the class is instantiated and every
1147        // time a new pattern is given.
1148        // Our strategy is to divide the string into section as given by
1149        // the BNF diagram, iterating through the string and setting up
1150        // the parameters we need for formatting (which is basicly what
1151        // a descendent recursive parser would do - but without recursion).
1152        // I'm sure that there are smarter methods to do this.
1153        
1154        // Restore default values. Most of these will be overwritten
1155        // but we want to be sure that nothing is left out.
1156        setDefaultValues();
1157        
1158        int len = pattern.length();
1159        if (len == 0)
1160          {
1161            // this is another special case...
1162            this.minimumIntegerDigits = 1;
1163            this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
1164            this.minimumFractionDigits = 0;
1165            this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
1166            
1167            // FIXME: ...and these values may not be valid in all locales
1168            this.minExponentDigits = 0;
1169            this.showDecimalSeparator = true;
1170            this.groupingUsed = true;
1171            this.groupingSize = 3;
1172            
1173            return;
1174          }
1175        
1176        int start = scanFix(pattern, symbols, 0, true);
1177        if (start < len) start = scanNumberInteger(pattern, symbols, start);
1178        if (start < len)
1179          {
1180            start = scanFractionalPortion(pattern, symbols, start);
1181          }
1182        else
1183          {
1184            // special case, pattern that ends here does not have a fractional
1185            // portion
1186            this.minimumFractionDigits = 0;
1187            this.maximumFractionDigits = 0;
1188            //this.decimalSeparatorAlwaysShown = false;
1189            //this.showDecimalSeparator = false;
1190          }
1191        
1192        // XXX: this fixes a compatibility test with the RI.
1193        // If new uses cases fail, try removing this line first.
1194        //if (!this.hasIntegerPattern && !this.hasFractionalPattern)
1195        //  throw new IllegalArgumentException("No valid pattern found!");
1196        
1197        if (start < len) start = scanExponent(pattern, symbols, start);
1198        if (start < len) start = scanFix(pattern, symbols, start, false);
1199        if (start < len) scanNegativePattern(pattern, symbols, start);
1200        
1201        if (useExponentialNotation &&
1202            (maxIntegerDigitsExponent > minimumIntegerDigits) &&
1203            (maxIntegerDigitsExponent > 1))
1204          {
1205            minimumIntegerDigits = 1;
1206            exponentRound = maxIntegerDigitsExponent;
1207          }
1208        
1209        if (useExponentialNotation)
1210          maximumIntegerDigits = maxIntegerDigitsExponent;
1211        
1212        if (!this.hasFractionalPattern && this.showDecimalSeparator == true)
1213          {
1214            this.decimalSeparatorAlwaysShown = true;
1215          }
1216      }
1217      
1218      /**
1219       * Scans for the prefix or suffix portion of the pattern string.
1220       * This method handles the positive subpattern of the pattern string.
1221       *  
1222       * @param pattern The pattern string to parse.
1223       * @return The position in the pattern string where parsing ended.
1224       */
1225      private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols,
1226                          int start, boolean prefix)
1227      {
1228        StringBuffer buffer = new StringBuffer();
1229        
1230        // the number portion is always delimited by one of those
1231        // characters
1232        char decimalSeparator = sourceSymbols.getDecimalSeparator();
1233        char patternSeparator = sourceSymbols.getPatternSeparator();
1234        char groupingSeparator = sourceSymbols.getGroupingSeparator();
1235        char digit = sourceSymbols.getDigit();
1236        char zero = sourceSymbols.getZeroDigit();
1237        char minus = sourceSymbols.getMinusSign();
1238        
1239        // other special characters, cached here to avoid method calls later
1240        char percent = sourceSymbols.getPercent();
1241        char permille = sourceSymbols.getPerMill();
1242        
1243        String currencySymbol = this.symbols.getCurrencySymbol();
1244        
1245        boolean quote = false;
1246        
1247        char ch = pattern.charAt(start);
1248        if (ch == patternSeparator)
1249          {
1250            // negative subpattern
1251            this.hasNegativePrefix = true;
1252            ++start;
1253            return start;
1254          }
1255        
1256        int len = pattern.length();
1257        int i;
1258        for (i = start; i < len; i++)
1259          {
1260            ch = pattern.charAt(i);
1261    
1262            // we are entering into the negative subpattern
1263            if (!quote && ch == patternSeparator)
1264              {
1265                if (this.hasNegativePrefix)
1266                  {
1267                    throw new IllegalArgumentException("Invalid pattern found: "
1268                                                       + start);
1269                  }
1270                
1271                this.hasNegativePrefix = true;
1272                ++i;
1273                break;
1274              }
1275            
1276            // this means we are inside the number portion
1277            if (!quote &&
1278                (ch == minus || ch == digit || ch == zero ||
1279                 ch == groupingSeparator))
1280              break;
1281    
1282            if (!quote && ch == decimalSeparator)
1283              {
1284                this.showDecimalSeparator = true;
1285                break;
1286              }
1287            else if (quote && ch != '\'')
1288              {
1289                buffer.append(ch);
1290                continue;
1291              }
1292            
1293            if (ch == '\u00A4')
1294              {
1295                // CURRENCY
1296                currencySymbol = this.symbols.getCurrencySymbol();
1297    
1298                // if \u00A4 is doubled, we use the international currency symbol
1299                if (i < len && pattern.charAt(i + 1) == '\u00A4')
1300                  {
1301                    currencySymbol = this.symbols.getInternationalCurrencySymbol();
1302                    i++;
1303                  }
1304    
1305                this.useCurrencySeparator = true;
1306                buffer.append(currencySymbol);
1307              }
1308            else if (ch == percent)
1309              {
1310                // PERCENT
1311                this.multiplier = 100;
1312                buffer.append(this.symbols.getPercent());
1313              }
1314            else if (ch == permille)
1315              {
1316                // PERMILLE
1317                this.multiplier = 1000;
1318                buffer.append(this.symbols.getPerMill());
1319              }
1320            else if (ch == '\'')
1321              {
1322                // QUOTE
1323                if (i < len && pattern.charAt(i + 1) == '\'')
1324                  {
1325                    // we need to add ' to the buffer 
1326                    buffer.append(ch);
1327                    i++;
1328                  }
1329                else
1330                  {
1331                    quote = !quote;
1332                    continue;
1333                  }
1334              }
1335            else
1336              {
1337                buffer.append(ch);
1338              }
1339          }
1340        
1341        if (prefix)
1342          {
1343            this.positivePrefix = buffer.toString();
1344            this.negativePrefix = minus + "" + positivePrefix;
1345          }
1346        else
1347          {
1348            this.positiveSuffix = buffer.toString();
1349          }
1350        
1351        return i;
1352      }
1353      
1354      /**
1355       * Scan the given string for number patterns, starting
1356       * from <code>start</code>.
1357       * This method searches the integer part of the pattern only.
1358       * 
1359       * @param pattern The pattern string to parse.
1360       * @param start The starting parse position in the string.
1361       * @return The position in the pattern string where parsing ended,
1362       * counted from the beginning of the string (that is, 0).
1363       */
1364      private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols,
1365                                    int start)
1366      {
1367        char digit = symbols.getDigit();
1368        char zero = symbols.getZeroDigit();
1369        char groupingSeparator = symbols.getGroupingSeparator();
1370        char decimalSeparator = symbols.getDecimalSeparator();
1371        char exponent = symbols.getExponential();
1372        char patternSeparator = symbols.getPatternSeparator();
1373        
1374        // count the number of zeroes in the pattern
1375        // this number defines the minum digits in the integer portion
1376        int zeros = 0;
1377        
1378        // count the number of digits used in grouping
1379        int _groupingSize = 0;
1380        
1381        this.maxIntegerDigitsExponent = 0;
1382        
1383        boolean intPartTouched = false;
1384        
1385        char ch;
1386        int len = pattern.length();
1387        int i;
1388        for (i = start; i < len; i++)
1389          {
1390            ch = pattern.charAt(i);
1391     
1392            // break on decimal separator or exponent or pattern separator
1393            if (ch == decimalSeparator || ch == exponent)
1394              break;
1395            
1396            if (this.hasNegativePrefix && ch == patternSeparator)
1397              throw new IllegalArgumentException("Invalid pattern found: "
1398                                                 + start);
1399            
1400            if (ch == digit)
1401              {
1402                // in our implementation we could relax this strict
1403                // requirement, but this is used to keep compatibility with
1404                // the RI
1405                if (zeros > 0) throw new
1406                  IllegalArgumentException("digit mark following zero in " +
1407                            "positive subpattern, not allowed. Position: " + i);
1408                
1409                _groupingSize++;
1410                intPartTouched = true;
1411                this.maxIntegerDigitsExponent++;
1412              }
1413            else if (ch == zero)
1414              {
1415                zeros++;
1416                _groupingSize++;
1417                this.maxIntegerDigitsExponent++;
1418              }
1419            else if (ch == groupingSeparator)
1420              {
1421                this.groupingSeparatorInPattern = true;
1422                this.groupingUsed = true;
1423                _groupingSize = 0;
1424              }
1425            else
1426              {
1427                // any other character not listed above
1428                // means we are in the suffix portion
1429                break;
1430              }
1431          }
1432        
1433        if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize;
1434        this.minimumIntegerDigits = zeros;
1435        
1436        // XXX: compatibility code with the RI: the number of minimum integer
1437        // digits is at least one when maximumIntegerDigits is more than zero
1438        if (intPartTouched && this.maximumIntegerDigits > 0 &&
1439            this.minimumIntegerDigits == 0)
1440          this.minimumIntegerDigits = 1;
1441    
1442        return i;
1443      }
1444      
1445      /**
1446       * Scan the given string for number patterns, starting
1447       * from <code>start</code>.
1448       * This method searches the fractional part of the pattern only.
1449       * 
1450       * @param pattern The pattern string to parse.
1451       * @param start The starting parse position in the string.
1452       * @return The position in the pattern string where parsing ended,
1453       * counted from the beginning of the string (that is, 0).
1454       */
1455      private int scanFractionalPortion(String pattern,
1456                                        DecimalFormatSymbols symbols,
1457                                        int start)
1458      {
1459        char digit = symbols.getDigit();
1460        char zero = symbols.getZeroDigit();
1461        char groupingSeparator = symbols.getGroupingSeparator();
1462        char decimalSeparator = symbols.getDecimalSeparator();
1463        char exponent = symbols.getExponential();
1464        char patternSeparator = symbols.getPatternSeparator();
1465        
1466        // first character needs to be '.' otherwise we are not parsing the
1467        // fractional portion
1468        char ch = pattern.charAt(start);
1469        if (ch != decimalSeparator)
1470          {
1471            this.minimumFractionDigits = 0;
1472            this.maximumFractionDigits = 0;
1473            return start;
1474          }
1475        
1476        ++start;
1477        
1478        this.hasFractionalPattern = true;
1479        
1480        this.minimumFractionDigits = 0;
1481        int digits = 0;
1482        
1483        int len = pattern.length();
1484        int i;
1485        for (i = start; i < len; i++)
1486          {
1487            ch = pattern.charAt(i);
1488            
1489            // we hit the exponential or negative subpattern
1490            if (ch == exponent || ch == patternSeparator)
1491              break;
1492            
1493            // pattern error
1494            if (ch == groupingSeparator || ch == decimalSeparator) throw new
1495              IllegalArgumentException("unexpected character '" + ch + "' " +
1496                                       "in fractional subpattern. Position: " + i);
1497            
1498            if (ch == digit)
1499              {
1500                digits++;
1501              }
1502            else if (ch == zero)
1503              {
1504                if (digits > 0) throw new
1505                IllegalArgumentException("digit mark following zero in " +
1506                          "positive subpattern, not allowed. Position: " + i);
1507                
1508                this.minimumFractionDigits++;
1509              }
1510            else
1511              {
1512                // we are in the suffix section of pattern
1513                break;
1514              }
1515          }
1516        
1517        if (i == start) this.hasFractionalPattern = false;
1518        
1519        this.maximumFractionDigits = this.minimumFractionDigits + digits;
1520        this.showDecimalSeparator = true;
1521        
1522        return i;
1523      }
1524      
1525      /**
1526       * Scan the given string for number patterns, starting
1527       * from <code>start</code>.
1528       * This method searches the expoential part of the pattern only.
1529       * 
1530       * @param pattern The pattern string to parse.
1531       * @param start The starting parse position in the string.
1532       * @return The position in the pattern string where parsing ended,
1533       * counted from the beginning of the string (that is, 0).
1534       */
1535      private int scanExponent(String pattern, DecimalFormatSymbols symbols,
1536                               int start)
1537      {
1538        char digit = symbols.getDigit();
1539        char zero = symbols.getZeroDigit();
1540        char groupingSeparator = symbols.getGroupingSeparator();
1541        char decimalSeparator = symbols.getDecimalSeparator();
1542        char exponent = symbols.getExponential();
1543        
1544        char ch = pattern.charAt(start);
1545        
1546        if (ch == decimalSeparator)
1547          {
1548            // ignore dots
1549            ++start;
1550          }
1551        
1552        if (ch != exponent)
1553          {
1554            this.useExponentialNotation = false;
1555            return start;
1556          }
1557        
1558        ++start;
1559        
1560        this.minExponentDigits = 0;
1561        
1562        int len = pattern.length();
1563        int i;
1564        for (i = start; i < len; i++)
1565          {
1566            ch = pattern.charAt(i);
1567            
1568            if (ch == groupingSeparator || ch == decimalSeparator ||
1569                ch == digit || ch == exponent) throw new
1570            IllegalArgumentException("unexpected character '" + ch + "' " + 
1571                                     "in exponential subpattern. Position: " + i);
1572            
1573            if (ch == zero)
1574              {
1575                this.minExponentDigits++;
1576              }
1577            else
1578              {
1579                // any character other than zero is an exit point
1580                break;
1581              }
1582          }
1583        
1584        this.useExponentialNotation = true; 
1585        
1586        return i;
1587      }
1588      
1589      /**
1590       * Scan the given string for number patterns, starting
1591       * from <code>start</code>.
1592       * This method searches the negative part of the pattern only and scan
1593       * throught the end of the string.
1594       * 
1595       * @param pattern The pattern string to parse.
1596       * @param start The starting parse position in the string.
1597       */
1598      private void scanNegativePattern(String pattern,
1599                                       DecimalFormatSymbols sourceSymbols,
1600                                       int start)
1601      {
1602        StringBuffer buffer = new StringBuffer();
1603        
1604        // the number portion is always delimited by one of those
1605        // characters
1606        char decimalSeparator = sourceSymbols.getDecimalSeparator();
1607        char patternSeparator = sourceSymbols.getPatternSeparator();
1608        char groupingSeparator = sourceSymbols.getGroupingSeparator();
1609        char digit = sourceSymbols.getDigit();
1610        char zero = sourceSymbols.getZeroDigit();
1611        char minus = sourceSymbols.getMinusSign();
1612        
1613        // other special charcaters, cached here to avoid method calls later
1614        char percent = sourceSymbols.getPercent();
1615        char permille = sourceSymbols.getPerMill();
1616        
1617        String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol();
1618        String currencySymbol = CURRENCY_SYMBOL;
1619        
1620        boolean quote = false;
1621        boolean prefixDone = false;
1622        
1623        int len = pattern.length();
1624        if (len > 0) this.hasNegativePrefix = true;
1625        
1626        char ch = pattern.charAt(start);
1627        if (ch == patternSeparator)
1628          {
1629            // no pattern separator in the negative pattern
1630            if ((start + 1) > len) throw new
1631              IllegalArgumentException("unexpected character '" + ch + "' " +
1632                                       "in negative subpattern.");    
1633            start++;
1634          }
1635        
1636        int i;
1637        for (i = start; i < len; i++)
1638          {
1639            ch = pattern.charAt(i);
1640            
1641            // this means we are inside the number portion
1642            if (!quote &&
1643                (ch == digit || ch == zero || ch == decimalSeparator ||
1644                 ch == patternSeparator || ch == groupingSeparator))
1645              {
1646                if (!prefixDone)
1647                  {
1648                    this.negativePrefix = buffer.toString();
1649                    buffer.delete(0, buffer.length());
1650                    prefixDone = true;
1651                  }
1652              }
1653            else if (ch == minus)
1654              {
1655                buffer.append(this.symbols.getMinusSign());
1656              }
1657            else if (quote && ch != '\'')
1658              {
1659                buffer.append(ch);
1660              }
1661            else if (ch == '\u00A4')
1662              {
1663                // CURRENCY
1664                currencySymbol = CURRENCY_SYMBOL;
1665    
1666                // if \u00A4 is doubled, we use the international currency symbol
1667                if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1668                  {
1669                    currencySymbol = this.symbols.getInternationalCurrencySymbol();
1670                    i = i + 2;
1671                  }
1672    
1673                // FIXME: not sure about this, the specs says that we only have to
1674                // change prefix and suffix, so leave it as commented
1675                // unless in case of bug report/errors
1676                //this.useCurrencySeparator = true;
1677                
1678                buffer.append(currencySymbol);
1679              }
1680            else if (ch == percent)
1681              {
1682                // PERCENT
1683                this.negativePatternMultiplier = 100;
1684                buffer.append(this.symbols.getPercent());
1685              }
1686            else if (ch == permille)
1687              {
1688                // PERMILLE
1689                this.negativePatternMultiplier = 1000;
1690                buffer.append(this.symbols.getPerMill());
1691              }
1692            else if (ch == '\'')
1693              {
1694                // QUOTE
1695                if (i < len && pattern.charAt(i + 1) == '\'')
1696                  {
1697                    // we need to add ' to the buffer 
1698                    buffer.append(ch);
1699                    i++;
1700                  }
1701                else
1702                  {
1703                    quote = !quote;
1704                  }
1705              }
1706            else if (ch == patternSeparator)
1707              {
1708                // no pattern separator in the negative pattern
1709                throw new IllegalArgumentException("unexpected character '" + ch +
1710                                                   "' in negative subpattern.");
1711              }
1712            else
1713              {
1714                buffer.append(ch);
1715              }
1716          }
1717        
1718        if (prefixDone)
1719          this.negativeSuffix = buffer.toString();
1720        else
1721          this.negativePrefix = buffer.toString();
1722      }
1723      
1724      /* ****** FORMATTING ****** */
1725      
1726      /**
1727       * Handles the real formatting.
1728       * 
1729       * We use a BigDecimal to format the number without precision loss.
1730       * All the rounding is done by methods in BigDecimal.
1731       * The <code>isLong</code> parameter is used to determine if we are
1732       * formatting a long or BigInteger. In this case, we avoid to format
1733       * the fractional part of the number (unless specified otherwise in the
1734       * format string) that would consist only of a 0 digit.
1735       * 
1736       * @param number A BigDecimal representation fo the input number.
1737       * @param dest The destination buffer.
1738       * @param isLong A boolean that indicates if this BigDecimal is a real
1739       * decimal or an integer.
1740       * @param fieldPos Use to keep track of the formatting position.
1741       */
1742      private void formatInternal(BigDecimal number, boolean isLong,
1743                                  StringBuffer dest, FieldPosition fieldPos)
1744      {  
1745        // The specs says that fieldPos should not be null, and that we
1746        // should throw a NPE, but it seems that in few classes that
1747        // reference this one, fieldPos is set to null.
1748        // This is even defined in the javadoc, see for example MessageFormat.
1749        // I think the best here is to check for fieldPos and build one if it is
1750        // null. If it cause harms or regressions, just remove this line and
1751        // fix the classes in the point of call, insted.
1752        if (fieldPos == null) fieldPos = new FieldPosition(0);
1753        
1754        int _multiplier = this.multiplier;
1755        
1756        // used to track attribute starting position for each attribute
1757        int attributeStart = -1;
1758        
1759        // now get the sign this will be used by the special case Inifinity
1760        // and by the normal cases.
1761        boolean isNegative = (number.signum() < 0) ? true : false;
1762        if (isNegative)
1763          {
1764            attributeStart = dest.length();
1765            
1766            // append the negative prefix to the string
1767            dest.append(negativePrefix);
1768            
1769            // once got the negative prefix, we can use
1770            // the absolute value.
1771            number = number.abs();
1772            
1773            _multiplier = negativePatternMultiplier;
1774            
1775            addAttribute(Field.SIGN, attributeStart, dest.length());
1776          }
1777        else
1778          {
1779            // not negative, use the positive prefix
1780            dest.append(positivePrefix);
1781          }
1782        
1783        // these are used ot update the field position
1784        int beginIndexInt = dest.length();
1785        int endIndexInt = 0;
1786        int beginIndexFract = 0;
1787        int endIndexFract = 0;
1788        
1789        // compute the multiplier to use with percent and similar
1790        number = number.multiply(new BigDecimal(_multiplier));
1791        
1792        // XXX: special case, not sure if it belongs here or if it is
1793        // correct at all. There may be other special cases as well
1794        // these should be handled in the format string parser.
1795        if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0)
1796          {
1797            number = BigDecimal.ZERO;
1798            this.maximumIntegerDigits = 1;
1799            this.minimumIntegerDigits = 1;
1800          }
1801        
1802        //  get the absolute number
1803        number = number.abs();
1804    
1805        // the scaling to use while formatting this number
1806        int scale = this.maximumFractionDigits;
1807        
1808        // this is the actual number we will use
1809        // it is corrected later on to handle exponential
1810        // notation, if needed
1811        long exponent = 0;
1812        
1813        // are we using exponential notation?
1814        if (this.useExponentialNotation)
1815          {
1816            exponent = getExponent(number);
1817            number = number.movePointLeft((int) exponent);
1818            
1819            // FIXME: this makes the test ##.###E0 to pass,
1820            // but all all the other tests to fail...
1821            // this should be really something like
1822            // min + max - what is already shown...
1823            //scale = this.minimumIntegerDigits + this.maximumFractionDigits;
1824          }
1825        
1826        // round the number to the nearest neighbor
1827        number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
1828    
1829        // now get the integer and fractional part of the string
1830        // that will be processed later
1831        String plain = number.toPlainString();
1832        
1833        String intPart = null;
1834        String fractPart = null;
1835        
1836        // remove - from the integer part, this is needed as
1837        // the Narrowing Primitive Conversions algorithm used may loose
1838        // information about the sign
1839        int minusIndex = plain.lastIndexOf('-', 0);
1840        if (minusIndex > -1) plain = plain.substring(minusIndex + 1);
1841        
1842        // strip the decimal portion
1843        int dot = plain.indexOf('.');
1844        if (dot > -1)
1845          {
1846            intPart = plain.substring(0, dot);
1847            dot++;
1848            
1849            if (useExponentialNotation)
1850              fractPart = plain.substring(dot, dot + scale);
1851            else
1852              fractPart = plain.substring(dot);
1853          }
1854        else
1855          {
1856            intPart = plain;
1857          }
1858        
1859        // used in various places later on
1860        int intPartLen = intPart.length();
1861        endIndexInt = intPartLen;
1862        
1863        // if the number of digits in our intPart is not greater than the
1864        // minimum we have to display, we append zero to the destination
1865        // buffer before adding the integer portion of the number.
1866        int zeroes = minimumIntegerDigits - intPartLen;
1867        if (zeroes > 0)
1868          {
1869            attributeStart = Math.max(dest.length() - 1, 0);
1870            appendZero(dest, zeroes, minimumIntegerDigits);
1871          }
1872    
1873        if (this.useExponentialNotation)
1874          {
1875            // For exponential numbers, the significant in mantissa are
1876            // the sum of the minimum integer and maximum fraction
1877            // digits, and does not take into account the maximun integer
1878            // digits to display.
1879            
1880            if (attributeStart < 0)
1881              attributeStart = Math.max(dest.length() - 1, 0);
1882            appendDigit(intPart, dest, this.groupingUsed);
1883          }
1884        else
1885          {
1886            // non exponential notation
1887            intPartLen = intPart.length();
1888            int canary = Math.min(intPartLen, this.maximumIntegerDigits);
1889            
1890            // remove from the string the number in excess
1891            // use only latest digits
1892            intPart = intPart.substring(intPartLen - canary);
1893            endIndexInt = intPart.length() + 1;
1894            
1895            // append it
1896            if (maximumIntegerDigits > 0 &&
1897                !(this.minimumIntegerDigits == 0 &&
1898                 intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0))
1899              {
1900                if (attributeStart < 0)
1901                  attributeStart = Math.max(dest.length() - 1, 0);
1902                appendDigit(intPart, dest, this.groupingUsed);
1903              }
1904          }
1905        
1906        // add the INTEGER attribute
1907        addAttribute(Field.INTEGER, attributeStart, dest.length());
1908        
1909        // ...update field position, if needed, and return...
1910        if ((fieldPos.getField() == INTEGER_FIELD ||
1911            fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
1912          {
1913            fieldPos.setBeginIndex(beginIndexInt);
1914            fieldPos.setEndIndex(endIndexInt);
1915          }
1916        
1917        handleFractionalPart(dest, fractPart, fieldPos, isLong);
1918            
1919        // and the exponent
1920        if (this.useExponentialNotation)
1921          {
1922            attributeStart = dest.length();
1923            
1924            dest.append(symbols.getExponential());
1925            
1926            addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
1927            attributeStart = dest.length();
1928            
1929            if (exponent < 0)
1930              {
1931                dest.append(symbols.getMinusSign());
1932                exponent = -exponent;
1933                
1934                addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
1935              }
1936            
1937            attributeStart = dest.length();
1938            
1939            String exponentString = String.valueOf(exponent);
1940            int exponentLength = exponentString.length();
1941            
1942            for (int i = 0; i < minExponentDigits - exponentLength; i++)
1943              dest.append(symbols.getZeroDigit());
1944            
1945            for (int i = 0; i < exponentLength; ++i)
1946              dest.append(exponentString.charAt(i));
1947            
1948            addAttribute(Field.EXPONENT, attributeStart, dest.length());
1949          }
1950     
1951        // now include the suffixes...
1952        if (isNegative)
1953          {
1954            dest.append(negativeSuffix);
1955          }
1956        else
1957          {
1958            dest.append(positiveSuffix);
1959          }
1960      }
1961    
1962      /**
1963       * Add to the input buffer the result of formatting the fractional
1964       * portion of the number.
1965       * 
1966       * @param dest
1967       * @param fractPart
1968       * @param fieldPos
1969       * @param isLong
1970       */
1971      private void handleFractionalPart(StringBuffer dest, String fractPart,
1972                                        FieldPosition fieldPos, boolean isLong)
1973      {
1974        int dotStart = 0;
1975        int dotEnd = 0;
1976        boolean addDecimal = false;
1977        
1978        if (this.decimalSeparatorAlwaysShown  ||
1979             ((!isLong || this.useExponentialNotation) &&
1980               this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
1981            this.minimumFractionDigits > 0)
1982          {
1983            dotStart = dest.length();
1984            
1985            if (this.useCurrencySeparator)
1986              dest.append(symbols.getMonetaryDecimalSeparator());
1987            else
1988              dest.append(symbols.getDecimalSeparator());
1989            
1990            dotEnd = dest.length();
1991            addDecimal = true;
1992          }
1993        
1994        // now handle the fraction portion of the number
1995        int fractStart = 0;
1996        int fractEnd = 0;
1997        boolean addFractional = false;
1998        
1999        if ((!isLong || this.useExponentialNotation)
2000            && this.maximumFractionDigits > 0
2001            || this.minimumFractionDigits > 0)
2002          {
2003            fractStart = dest.length();
2004            fractEnd = fractStart;
2005            
2006            int digits = this.minimumFractionDigits;
2007            
2008            if (this.useExponentialNotation)
2009              {
2010                digits = (this.minimumIntegerDigits + this.minimumFractionDigits)
2011                  - dest.length();
2012                if (digits < 0) digits = 0;
2013              }
2014            
2015            fractPart = adjustTrailingZeros(fractPart, digits);
2016            
2017            // FIXME: this code must be improved
2018            // now check if the factional part is just 0, in this case
2019            // we need to remove the '.' unless requested
2020            boolean allZeros = true;
2021            char fracts[] = fractPart.toCharArray();
2022            for (int i = 0; i < fracts.length; i++)
2023              {
2024                if (fracts[i] != '0')
2025                  allZeros = false;
2026              }
2027            
2028            if (!allZeros || (minimumFractionDigits > 0))
2029              {
2030                appendDigit(fractPart, dest, false);
2031                fractEnd = dest.length();
2032                
2033                addDecimal = true;
2034                addFractional = true;
2035              }
2036            else if (!this.decimalSeparatorAlwaysShown)
2037              {
2038                dest.deleteCharAt(dest.length() - 1);
2039                addDecimal = false;
2040              }
2041            else
2042              {
2043                fractEnd = dest.length();
2044                addFractional = true;
2045              }
2046          }
2047        
2048        if (addDecimal)
2049          addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
2050        
2051        if (addFractional)
2052          addAttribute(Field.FRACTION, fractStart, fractEnd);
2053        
2054        if ((fieldPos.getField() == FRACTION_FIELD ||
2055            fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
2056          {
2057            fieldPos.setBeginIndex(fractStart);
2058            fieldPos.setEndIndex(fractEnd);
2059          }
2060      }
2061      
2062      /**
2063       * Append to <code>dest</code>the give number of zeros.
2064       * Grouping is added if needed.
2065       * The integer totalDigitCount defines the total number of digits
2066       * of the number to which we are appending zeroes.
2067       */
2068      private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount)
2069      {
2070        char ch = symbols.getZeroDigit();
2071        char gSeparator = symbols.getGroupingSeparator();
2072        
2073        int i = 0;
2074        int gPos = totalDigitCount;
2075        for (i = 0; i < zeroes; i++, gPos--)
2076          {
2077            if (this.groupingSeparatorInPattern &&
2078                (this.groupingUsed && this.groupingSize != 0) &&
2079                (gPos % groupingSize == 0 && i > 0))
2080              dest.append(gSeparator);
2081            
2082            dest.append(ch);
2083          }
2084        
2085        // special case, that requires adding an additional separator
2086        if (this.groupingSeparatorInPattern &&
2087            (this.groupingUsed && this.groupingSize != 0) &&
2088            (gPos % groupingSize == 0))
2089          dest.append(gSeparator);
2090      }
2091      
2092      /**
2093       * Append src to <code>dest</code>.
2094       * 
2095       * Grouping is added if <code>groupingUsed</code> is set
2096       * to <code>true</code>.
2097       */
2098      private void appendDigit(String src, StringBuffer dest,
2099                                 boolean groupingUsed)
2100      {
2101        int zero = symbols.getZeroDigit() - '0';
2102        
2103        int ch;
2104        char gSeparator = symbols.getGroupingSeparator();
2105            
2106        int len = src.length();
2107        for (int i = 0, gPos = len; i < len; i++, gPos--)
2108          {
2109            ch = src.charAt(i);
2110            if (groupingUsed && this.groupingSize != 0 &&
2111                gPos % groupingSize == 0 && i > 0)
2112              dest.append(gSeparator);
2113    
2114            dest.append((char) (zero + ch));
2115          }
2116      }
2117      
2118      /**
2119       * Calculate the exponent to use if eponential notation is used.
2120       * The exponent is calculated as a power of ten.
2121       * <code>number</code> should be positive, if is zero, or less than zero,
2122       * zero is returned.
2123       */
2124      private long getExponent(BigDecimal number)
2125      {
2126        long exponent = 0;
2127        
2128        if (number.signum() > 0)
2129          {
2130            double _number = number.doubleValue();
2131            exponent = (long) Math.floor (Math.log10(_number));
2132            
2133            // get the right value for the exponent
2134            exponent = exponent - (exponent % this.exponentRound);
2135            
2136            // if the minimumIntegerDigits is more than zero
2137            // we display minimumIntegerDigits of digits.
2138            // so, for example, if minimumIntegerDigits == 2
2139            // and the actual number is 0.123 it will be
2140            // formatted as 12.3E-2
2141            // this means that the exponent have to be shifted
2142            // to the correct value.
2143            if (minimumIntegerDigits > 0)
2144                  exponent -= minimumIntegerDigits - 1;
2145          }
2146        
2147        return exponent;
2148      }
2149     
2150      /**
2151       * Remove contiguos zeros from the end of the <code>src</code> string,
2152       * if src contains more than <code>minimumDigits</code> digits.
2153       * if src contains less that <code>minimumDigits</code>,
2154       * then append zeros to the string.
2155       * 
2156       * Only the first block of zero digits is removed from the string
2157       * and only if they fall in the src.length - minimumDigits
2158       * portion of the string.
2159       * 
2160       * @param src The string with the correct number of zeros.
2161       */
2162      private String adjustTrailingZeros(String src, int minimumDigits)
2163      {
2164        int len = src.length();
2165        String result;
2166        
2167        // remove all trailing zero
2168        if (len > minimumDigits)
2169          {
2170            int zeros = 0;    
2171            for (int i = len - 1; i > minimumDigits; i--)
2172              {
2173                if (src.charAt(i) == '0')
2174                  ++zeros;
2175                else
2176                  break;
2177              }
2178            result =  src.substring(0, len - zeros);                
2179          }
2180        else
2181          {
2182            char zero = symbols.getZeroDigit();
2183            StringBuffer _result = new StringBuffer(src);
2184            for (int i = len; i < minimumDigits; i++)
2185              {
2186                _result.append(zero);
2187              }
2188            result = _result.toString();
2189          }
2190        
2191        return result;
2192      }
2193      
2194      /**
2195       * Adds an attribute to the attributes list.
2196       * 
2197       * @param field
2198       * @param begin
2199       * @param end
2200       */
2201      private void addAttribute(Field field, int begin, int end)
2202      {
2203        /*
2204         * This method and its implementation derives directly from the
2205         * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
2206         */
2207        
2208        FieldPosition pos = new FieldPosition(field);
2209        pos.setBeginIndex(begin);
2210        pos.setEndIndex(end);
2211        attributes.add(pos);
2212      }
2213      
2214      /**
2215       * Sets the default values for the various properties in this DecimaFormat.
2216       */
2217      private void setDefaultValues()
2218      {
2219        // Maybe we should add these values to the message bundle and take
2220        // the most appropriate for them for any locale.
2221        // Anyway, these seem to be good values for a default in most languages.
2222        // Note that most of these will change based on the format string.
2223        
2224        this.negativePrefix = String.valueOf(symbols.getMinusSign());
2225        this.negativeSuffix = "";
2226        this.positivePrefix = "";
2227        this.positiveSuffix = "";
2228        
2229        this.multiplier = 1;
2230        this.negativePatternMultiplier = 1;
2231        this.exponentRound = 1;
2232        
2233        this.hasNegativePrefix = false;
2234        
2235        this.minimumIntegerDigits = 1;
2236        this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
2237        this.minimumFractionDigits = 0;
2238        this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
2239        this.minExponentDigits = 0;
2240        
2241        this.groupingSize = 0;
2242        
2243        this.decimalSeparatorAlwaysShown = false;
2244        this.showDecimalSeparator = false;
2245        this.useExponentialNotation = false;
2246        this.groupingUsed = false;
2247        this.groupingSeparatorInPattern = false;
2248        
2249        this.useCurrencySeparator = false;
2250        
2251        this.hasFractionalPattern = false;
2252      }
2253    }