You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gh...@apache.org on 2006/04/11 12:02:26 UTC

svn commit: r393171 - in /incubator/harmony/enhanced/classlib/trunk/modules/text: make/common/ src/main/java/java/text/ src/test/java/org/apache/harmony/tests/java/text/

Author: gharley
Date: Tue Apr 11 03:02:16 2006
New Revision: 393171

URL: http://svn.apache.org/viewcvs?rev=393171&view=rev
Log:
Backing out HARMONY-205 changes pending investigation of test failures in LUNI, SQL, Security etc.

Removed:
    incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/text/make/common/build.xml
    incubator/harmony/enhanced/classlib/trunk/modules/text/src/main/java/java/text/DecimalFormat.java
    incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/AllTests.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/text/make/common/build.xml
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/text/make/common/build.xml?rev=393171&r1=393170&r2=393171&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/text/make/common/build.xml (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/text/make/common/build.xml Tue Apr 11 03:02:16 2006
@@ -95,7 +95,7 @@
                                         <exclude name="**/ChoiceFormatTest.java"/>
                                         <exclude name="**/CollationKeyTest.java"/>
                                         <exclude name="**/CollatorTest.java"/>
-                                        <exclude name="tests/api/java/text/DecimalFormatTest.java"/>
+                                        <exclude name="**/DecimalFormatTest.java"/>  
                                         <exclude name="**/MessageFormatTest.java"/>
                                         <exclude name="**/NumberFormatTest.java"/>
                                         <exclude name="**/SimpleDateFormatTest.java"/>

Modified: incubator/harmony/enhanced/classlib/trunk/modules/text/src/main/java/java/text/DecimalFormat.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/text/src/main/java/java/text/DecimalFormat.java?rev=393171&r1=393170&r2=393171&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/text/src/main/java/java/text/DecimalFormat.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/text/src/main/java/java/text/DecimalFormat.java Tue Apr 11 03:02:16 2006
@@ -1,4 +1,4 @@
-/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,15 +15,15 @@
 
 package java.text;
 
+
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.util.Currency;
 import java.util.Locale;
+import java.util.Vector;
 
-import org.apache.harmony.luni.util.NotYetImplementedException;
+import org.apache.harmony.luni.util.Msg;
 
 /**
  * DecimalFormat is used to format and parse numbers, both integers and
@@ -32,17 +32,43 @@
  */
 public class DecimalFormat extends NumberFormat {
 
-	static final long serialVersionUID = 864413376551465018L;
+	private static final long serialVersionUID = 864413376551465018L;
+
+	private static final String patternChars = "0#.,;%\u2030E";
+
+	private static final char CURRENCY_SYMBOL = '\u00a4';
+
+	private static final int DOUBLE_INTEGER_DIGITS = 309;
+
+	private static final int DOUBLE_FRACTION_DIGITS = 340;
+
+	private byte groupingSize = 3;
 
-	private boolean parseBigDecimal = false;
+	private int multiplier = 1;
+
+	private String positivePrefix = "", positiveSuffix = "",
+			negativePrefix = "-", negativeSuffix = "";
+
+	private String posPrefixPattern, posSuffixPattern, negPrefixPattern,
+			negSuffixPattern;
+
+	private boolean decimalSeparatorAlwaysShown = false;
+
+	transient private boolean posPrefixMonetary = false,
+			posSuffixMonetary = false, negPrefixMonetary = false,
+			negSuffixMonetary = false;
 
 	private DecimalFormatSymbols symbols;
 
-	private transient com.ibm.icu.text.DecimalFormat dform;
+	private boolean useExponentialNotation = false;
+
+	private byte minExponentDigits;
+
+	private int serialVersionOnStream = 2;
 
-	private transient com.ibm.icu.text.DecimalFormatSymbols icuSymbols;
+	transient private char zero;
 
-	static final int currentSerialVersion = 3;
+	private static final double log10 = Math.log(10);
 
 	/**
 	 * Constructs a new DecimalFormat for formatting and parsing numbers for the
@@ -63,7 +89,9 @@
 	 *                when the pattern cannot be parsed
 	 */
 	public DecimalFormat(String pattern) {
-		this(pattern, new DecimalFormatSymbols());
+		symbols = new DecimalFormatSymbols();
+		zero = symbols.getZeroDigit();
+		applyPattern(pattern);
 	}
 
 	/**
@@ -79,45 +107,9 @@
 	 *                when the pattern cannot be parsed
 	 */
 	public DecimalFormat(String pattern, DecimalFormatSymbols value) {
-		dform = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat
-				.getInstance();
+		symbols = (DecimalFormatSymbols) value.clone();
+		zero = symbols.getZeroDigit();
 		applyPattern(pattern);
-		symbols = value;
-
-		icuSymbols = adapt2ICU(symbols);
-
-		dform.setDecimalFormatSymbols(icuSymbols);
-		setMaximumFractionDigits(dform.getMaximumFractionDigits());
-		setMinimumFractionDigits(dform.getMinimumFractionDigits());
-		setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
-		setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
-		
-
-	}
-
-	private com.ibm.icu.text.DecimalFormatSymbols adapt2ICU(
-			DecimalFormatSymbols symbols) {
-		com.ibm.icu.text.DecimalFormatSymbols icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols();
-		String currencyCode = symbols.getCurrency().getCurrencyCode();
-		icuSymbols.setCurrency(com.ibm.icu.util.Currency
-				.getInstance(currencyCode));
-		icuSymbols.setCurrencySymbol(symbols.getCurrencySymbol());
-		icuSymbols.setDecimalSeparator(symbols.getDecimalSeparator());
-		icuSymbols.setDigit(symbols.getDigit());
-		icuSymbols.setGroupingSeparator(symbols.getGroupingSeparator());
-		icuSymbols.setInfinity(symbols.getInfinity());
-		icuSymbols.setInternationalCurrencySymbol(symbols
-				.getInternationalCurrencySymbol());
-		icuSymbols.setMinusSign(symbols.getMinusSign());
-		icuSymbols.setMonetaryDecimalSeparator(symbols
-				.getMonetaryDecimalSeparator());
-		icuSymbols.setNaN(symbols.getNaN());
-		icuSymbols.setPatternSeparator(symbols.getPatternSeparator());
-		icuSymbols.setPercent(symbols.getPercent());
-		icuSymbols.setPerMill(symbols.getPerMill());
-		icuSymbols.setZeroDigit(symbols.getZeroDigit());
-
-		return icuSymbols;
 	}
 
 	/**
@@ -131,7 +123,8 @@
 	 *                when the pattern cannot be parsed
 	 */
 	public void applyLocalizedPattern(String pattern) {
-		dform.applyLocalizedPattern(pattern);
+		applyPattern(convertPattern(pattern, symbols.getLocalPatternChars(),
+				patternChars, false));
 	}
 
 	/**
@@ -145,8 +138,184 @@
 	 *                when the pattern cannot be parsed
 	 */
 	public void applyPattern(String pattern) {
+		if (pattern.length() == 0)
+			return;
+		int next, grouping = 0, intCount = 0, minInt = 0, minFraction = 0, maxFraction = 0, localMultiplier = 1, minExponent = 0;
+		boolean inPrefix = true, countGrouping = false, exponent = false, fraction = false, negative = false, inSuffix = false;
+		StringBuffer buffer = new StringBuffer();
+		String prefix = "", suffix = "", negPrefix = "", negSuffix = "", format = null;
+		boolean quote = false, lastQuote = false;
+		final int patternLength = pattern.length();
+		for (int i = 0; i < patternLength; i++) {
+			next = (pattern.charAt(i));
+			if (!quote
+					&& ("0#,.".indexOf(next) != -1 || (!exponent && !inPrefix
+							&& !inSuffix && next == 'E'))) {
+				if (inPrefix) {
+					if (negative)
+						negPrefix = buffer.toString();
+					else
+						prefix = buffer.toString();
+					buffer.setLength(0);
+					inPrefix = false;
+				}
+				if (inSuffix)
+					throw new IllegalArgumentException(Msg.getString("K0014",
+							String.valueOf((char) next), pattern));
+				buffer.append((char) next);
+				if (next == 'E')
+					exponent = true;
+				if (negative)
+					continue;
+				switch (next) {
+				case '0':
+					if (countGrouping)
+						grouping++;
+					if (exponent)
+						minExponent++;
+					else {
+						if (maxFraction > 0)
+							throw new IllegalArgumentException(Msg.getString(
+									"K0015", String.valueOf((char) next),
+									pattern));
+						if (fraction)
+							minFraction++;
+						else
+							minInt++;
+					}
+					break;
+				case '#':
+					if ((!fraction && minInt > 0) || exponent)
+						throw new IllegalArgumentException(Msg.getString(
+								"K0016", String.valueOf((char) next), pattern));
+					if (countGrouping)
+						grouping++;
+					if (fraction)
+						maxFraction++;
+					else
+						intCount++;
+					break;
+				case ',':
+					if (fraction || exponent)
+						throw new IllegalArgumentException(Msg.getString(
+								"K0016", String.valueOf((char) next), pattern));
+					grouping = 0;
+					countGrouping = true;
+					break;
+				case '.':
+					if (fraction || exponent)
+						throw new IllegalArgumentException(Msg.getString(
+								"K0016", String.valueOf((char) next), pattern));
+					countGrouping = false;
+					fraction = true;
+					break;
+				case 'E':
+					countGrouping = false;
+					break;
+				}
+			} else {
+				if (!inPrefix && !inSuffix) {
+					if (!negative)
+						format = buffer.toString();
+					buffer.setLength(0);
+				}
+				if (!inPrefix)
+					inSuffix = true;
+				if (next == '\'') {
+					if (lastQuote)
+						buffer.append('\'');
+					quote = !quote;
+					lastQuote = true;
+				} else {
+					lastQuote = false;
+					if (next == ';' && !quote) {
+						if (format == null || format.length() == 0)
+							throw new IllegalArgumentException(Msg.getString(
+									"K0017", String.valueOf((char) next),
+									pattern));
+						if (exponent && minExponent == 0)
+							throw new IllegalArgumentException(Msg.getString(
+									"K0018", pattern));
+						suffix = buffer.toString();
+						buffer.setLength(0);
+						negative = inPrefix = true;
+						inSuffix = exponent = false;
+						continue;
+					}
+					if (!negative
+							&& (next == symbols.getPercent() || next == symbols
+									.getPerMill()) && !quote) {
+						if (localMultiplier != 1)
+							throw new IllegalArgumentException(Msg.getString(
+									"K0016", String.valueOf((char) next),
+									pattern));
+						localMultiplier = next == symbols.getPercent() ? 100
+								: 1000;
+					}
+					buffer.append((char) next);
+				}
+			}
+		}
+		if (quote)
+			throw new IllegalArgumentException(Msg.getString("K0019", pattern));
+		if (countGrouping && grouping == 0)
+			throw new IllegalArgumentException(Msg.getString("K001a", pattern));
+		if (!negative && exponent && minExponent == 0)
+			throw new IllegalArgumentException(Msg.getString("K0018", pattern));
+		if (minExponent > 0
+				&& intCount + minInt + minFraction + maxFraction == 0)
+			throw new IllegalArgumentException(Msg.getString("K001b", pattern));
+		if (inPrefix) {
+			if (negative)
+				negPrefix = buffer.toString();
+			else
+				prefix = buffer.toString();
+		}
+		if (inSuffix) {
+			if (negative)
+				negSuffix = buffer.toString();
+			else
+				suffix = buffer.toString();
+		}
 
-		dform.applyPattern(pattern);
+		maxFraction += minFraction;
+		if (fraction && minFraction == 0 && minInt == 0 && intCount > 0) {
+			minInt = 1;
+			intCount--;
+		} else if (maxFraction > 0 && minInt + intCount == 0
+				&& minFraction == 0)
+			minFraction = 1;
+		useExponentialNotation = minExponent > 0;
+		if (useExponentialNotation) {
+			setMaximumIntegerDigits(intCount + minInt);
+		} else
+			setMaximumIntegerDigits(Integer.MAX_VALUE);
+		setMinimumIntegerDigits(minInt);
+		setMaximumFractionDigits(maxFraction);
+		setMinimumFractionDigits(minFraction);
+		setGroupingSize(grouping);
+		setGroupingUsed(grouping > 0);
+		setPositivePrefix(prefix.toString());
+		setPositiveSuffix(suffix.toString());
+		posPrefixMonetary = positivePrefix.indexOf(CURRENCY_SYMBOL) > -1;
+		posPrefixPattern = expandAffix(positivePrefix);
+		posSuffixMonetary = positiveSuffix.indexOf(CURRENCY_SYMBOL) > -1;
+		posSuffixPattern = expandAffix(positiveSuffix);
+		minExponentDigits = minExponent > Byte.MAX_VALUE ? Byte.MAX_VALUE
+				: (byte) minExponent;
+		if (!negative) {
+			negPrefix = symbols.getMinusSign() + prefix;
+			negSuffix = suffix;
+		}
+		setNegativePrefix(negPrefix);
+		setNegativeSuffix(negSuffix);
+		negPrefixMonetary = negPrefix.indexOf(CURRENCY_SYMBOL) > -1;
+		negPrefixPattern = expandAffix(negPrefix);
+		negSuffixMonetary = negSuffix.indexOf(CURRENCY_SYMBOL) > -1;
+		negSuffixPattern = expandAffix(negSuffix);
+		setDecimalSeparatorAlwaysShown(fraction
+				&& (minInt + intCount == 0 || minFraction + maxFraction == 0));
+		setMultiplier(localMultiplier);
 	}
 
 	/**
@@ -159,11 +328,32 @@
 	 */
 	public Object clone() {
 		DecimalFormat clone = (DecimalFormat) super.clone();
-		clone.dform = (com.ibm.icu.text.DecimalFormat) dform.clone();
 		clone.symbols = (DecimalFormatSymbols) symbols.clone();
 		return clone;
 	}
 
+	private String convertCurrencySymbols(String value) {
+		StringBuffer output = null;
+		for (int i = 0; i < value.length(); i++) {
+			char next;
+			if ((next = value.charAt(i)) == CURRENCY_SYMBOL) {
+				if (output == null)
+					output = new StringBuffer(value.substring(0, i));
+				if (i + 1 < value.length()
+						&& value.charAt(i + 1) == CURRENCY_SYMBOL) {
+					i++;
+					output.append(symbols.getInternationalCurrencySymbol());
+				} else {
+					output.append(symbols.getCurrencySymbol());
+				}
+			} else if (output != null)
+				output.append(next);
+		}
+		if (output == null)
+			return value;
+		return output.toString();
+	}
+
 	/**
 	 * Compares the specified object to this DecimalFormat and answer if they
 	 * are equal. The object must be an instance of DecimalFormat with the same
@@ -177,15 +367,26 @@
 	 * @see #hashCode
 	 */
 	public boolean equals(Object object) {
-		if (this == object) {
+		if (this == object)
 			return true;
-		}
-		if (!(object instanceof DecimalFormat)) {
+		if (!(object instanceof DecimalFormat))
 			return false;
-		}
 		DecimalFormat format = (DecimalFormat) object;
-		return (this.dform == null ? format.dform == null : this.dform
-				.equals(format.dform));
+		return super.equals(object)
+				&& symbols.equals(format.symbols)
+				&& groupingSize == format.groupingSize
+				&& multiplier == format.multiplier
+				&& positivePrefix.equals(format.positivePrefix)
+				&& positiveSuffix.equals(format.positiveSuffix)
+				&& negativePrefix.equals(format.negativePrefix)
+				&& negativeSuffix.equals(format.negativeSuffix)
+				&& decimalSeparatorAlwaysShown == format.decimalSeparatorAlwaysShown
+				&& isCurrency() == format.isCurrency();
+	}
+
+	private Number error(ParsePosition position, int offset) {
+		position.setErrorIndex(offset);
+		return null;
 	}
 
 	/**
@@ -202,7 +403,33 @@
 	 *                when the object cannot be formatted by this Format
 	 */
 	public AttributedCharacterIterator formatToCharacterIterator(Object object) {
-		return dform.formatToCharacterIterator(object);
+		if (!(object instanceof Number))
+			throw new IllegalArgumentException();
+
+		StringBuffer buffer = new StringBuffer();
+		Vector fields = new Vector();
+
+		// format the number, and find fields
+		double dv = ((Number) object).doubleValue();
+		long lv = ((Number) object).longValue();
+		if (dv == lv)
+			formatImpl(lv, buffer, new FieldPosition(0), fields);
+		else
+			formatImpl(dv, buffer, new FieldPosition(0), fields);
+
+		// create an AttributedString with the formatted buffer
+		AttributedString as = new AttributedString(buffer.toString());
+
+		// add NumberFormat field attributes to the AttributedString
+		for (int i = 0; i < fields.size(); i++) {
+			FieldPosition pos = (FieldPosition) fields.elementAt(i);
+			Format.Field attribute = pos.getFieldAttribute();
+			as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos
+					.getEndIndex());
+		}
+
+		// return the CharacterIterator from AttributedString
+		return as.getIterator();
 	}
 
 	/**
@@ -221,9 +448,246 @@
 	 */
 	public StringBuffer format(double value, StringBuffer buffer,
 			FieldPosition position) {
-		return dform.format(value, buffer, position);
+		return formatImpl(value, buffer, position, null);
 	}
 
+	private StringBuffer formatImpl(double value, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		if (multiplier != 1)
+			value *= multiplier;
+
+		position.clear();
+		if (Double.isNaN(value))
+			return buffer.append(symbols.getNaN());
+
+		long bits = Double.doubleToLongBits(value);
+		// SIGN or CURRENCY fields
+		String prefix = (bits < 0) ? getNegativePrefix() : getPositivePrefix();
+		formatPrefixSuffix(prefix, buffer, position, fields);
+
+		// INTEGER field begins
+		FieldPosition positionInteger = null;
+		positionInteger = new FieldPosition(Field.INTEGER);
+		handleIntegerBegin(buffer.length(), position, fields, positionInteger);
+
+		if (Double.isInfinite(value)) {
+			buffer.append(symbols.getInfinity());
+
+			// INTEGER field ends
+			handleIntegerEnd(buffer.length(), position, fields, positionInteger);
+		} else {
+			double abs = value < 0 ? -value : value;
+
+			boolean fixed = false;
+			int scale = 0, exponent = 0;
+			int minFract = 0, maxFract = 0;
+			if (useExponentialNotation) {
+				exponent = scale(abs);
+				minFract = getMinimumIntegerDigits()
+						+ getMinimumFractionDigits();
+				fixed = getMinimumIntegerDigits() == getMaximumIntegerDigits();
+				if (fixed) {
+					minFract -= getMinimumIntegerDigits();
+					scale = getMinimumIntegerDigits() - 1;
+					if (value != 0)
+						exponent -= scale;
+				} else {
+					scale = exponent % getMaximumIntegerDigits();
+					if (exponent < -1
+							&& scale + getMaximumIntegerDigits() < getMaximumIntegerDigits())
+						scale += getMaximumIntegerDigits();
+					if (getMinimumIntegerDigits() == 0)
+						scale--;
+					if (value != 0)
+						exponent -= scale;
+					if (scale >= 0)
+						minFract -= scale + 1;
+				}
+				if (exponent != 0)
+					abs /= Math.pow(10.0, exponent);
+				maxFract = getMaximumIntegerDigits()
+						+ getMaximumFractionDigits();
+				if (scale >= 0)
+					maxFract -= scale + 1;
+			} else {
+				scale = scale(abs);
+				minFract = getMinimumFractionDigits();
+				maxFract = getMaximumFractionDigits();
+			}
+			if (-maxFract - 1 >= (scale - 16)) {
+				// Round decimal digits
+				abs += Math.pow(10.0, -maxFract - 1) * 5;
+			}
+
+			// In case rounding changed the scale
+			int checkScale = scale(abs);
+			if (checkScale > scale) {
+				// Rounding changed the scale
+				if (useExponentialNotation) {
+					if (fixed || getMinimumIntegerDigits() == 0) {
+						abs /= 10.0;
+						exponent++;
+					} else {
+						if (scale + 1 == getMaximumIntegerDigits()
+								||
+								// catch .1E0 instead of 100E-3 case
+								(exponent + getMaximumIntegerDigits() == 0 && scale + 2 == getMaximumIntegerDigits())) {
+							exponent += getMaximumIntegerDigits();
+							abs /= Math.pow(10.0, getMaximumIntegerDigits());
+							int adjust;
+							if (exponent == 0)
+								adjust = -1;
+							else
+								adjust = 0;
+							minFract += scale - adjust;
+							maxFract += scale - adjust;
+							scale = adjust;
+						} else {
+							scale++;
+							minFract--;
+							maxFract--;
+						}
+					}
+				} else
+					scale = checkScale;
+			}
+
+			long digits;
+			int shift = 0, dLength;
+			String sValue = Double.toString(abs);
+			dLength = sValue.lastIndexOf('E');
+			if (dLength > -1)
+				shift = Integer.parseInt(sValue.substring(dLength + 1));
+			else
+				dLength = sValue.length();
+			int index = sValue.indexOf('.');
+			if (index > -1) {
+				String fValue = sValue.substring(index + 1, dLength);
+				String iValue = sValue.substring(0, index);
+				if (fValue.equals("0")) {
+					sValue = iValue;
+					dLength -= 2;
+				} else {
+					shift -= fValue.length();
+					if (iValue.equals("0")) {
+						int i = 0;
+						while (fValue.charAt(i) == '0')
+							i++;
+						sValue = fValue.substring(i);
+						dLength -= i + 2;
+					} else {
+						sValue = iValue + fValue;
+						dLength--;
+					}
+				}
+			} else
+				sValue = sValue.substring(0, dLength);
+			digits = Long.parseLong(sValue);
+
+			int iLength = dLength;
+			long number = digits;
+			if (shift < 0) {
+				if (-shift < dLength) {
+					iLength = dLength + shift;
+					long pow = intPow(-shift);
+					number /= pow;
+					digits -= number * pow;
+					dLength = -shift;
+				} else {
+					number = 0;
+					iLength = 1;
+				}
+			} else {
+				iLength += shift;
+				digits = 0;
+				dLength = 0;
+			}
+			if (maxFract != 0 && maxFract < dLength) {
+				long pow = intPow(dLength - maxFract);
+				digits /= pow;
+				shift += dLength - maxFract;
+				dLength = maxFract;
+			}
+
+			int length = buffer.length();
+			StringBuffer output = new StringBuffer();
+
+			if (scale < 0 && !useExponentialNotation)
+				formatInteger("0", buffer, position, fields);
+			else {
+				output.append(Long.toString(number));
+				for (int i = output.length(); i < iLength; i++)
+					output.append('0');
+				if (useExponentialNotation) {
+					for (int i = 0; i <= scale; i++) {
+						if (i >= output.length())
+							buffer.append(zero);
+						else
+							buffer
+									.append((char) (zero + (output.charAt(i) - '0')));
+					}
+				} else
+					formatInteger(output.toString(), buffer, position, fields);
+			}
+
+			if (maxFract == 0) {
+				if (length == buffer.length())
+					buffer.append(zero);
+				// INTEGER field ends
+				handleIntegerEnd(buffer.length(), position, fields,
+						positionInteger);
+
+				// format DECIMAL_SEPARATOR field
+				formatFraction(new StringBuffer(), buffer, position, fields);
+			} else {
+				output.setLength(0);
+				int lastDigit = 0, leading = -shift - dLength;
+				if (digits > 0 && maxFract > leading) {
+					String print = Long.toString(digits);
+					if (dLength > print.length())
+						leading += dLength - print.length();
+					for (int i = 0; i < leading; i++)
+						output.append(zero);
+					for (int i = leading; i < maxFract; i++) {
+						int digit;
+						if (i - leading >= print.length())
+							digit = 0;
+						else
+							digit = print.charAt(i - leading) - '0';
+						output.append((char) (zero + digit));
+						if (digit > 0)
+							lastDigit = output.length();
+					}
+				}
+				if (output.length() < minFract) {
+					for (int i = output.length(); i < minFract; i++)
+						output.append(zero);
+				} else {
+					output.setLength(lastDigit < minFract ? minFract
+							: lastDigit);
+				}
+				if (output.length() == 0 && length == buffer.length())
+					buffer.append(zero);
+
+				// INTEGER Field ends
+				handleIntegerEnd(buffer.length(), position, fields,
+						positionInteger);
+
+				// format DECIMAL_SEPARATOR and FRACTION fields
+				formatFraction(output, buffer, position, fields);
+			}
+
+			if (useExponentialNotation)
+				formatExponent(exponent, buffer, position, fields);
+		}
+
+		// handle SIGN, CURRENCY, PERMILLE or PERCENT fields
+		String suffix = (bits < 0) ? getNegativeSuffix() : getPositiveSuffix();
+		formatPrefixSuffix(suffix, buffer, position, fields);
+
+		return buffer;
+}
+
 	/**
 	 * Formats the long value into the specified StringBuffer using the pattern
 	 * of this DecimalFormat. If the field specified by the FieldPosition is
@@ -240,21 +704,389 @@
 	 */
 	public StringBuffer format(long value, StringBuffer buffer,
 			FieldPosition position) {
-		return dform.format(value, buffer, position);
+		return formatImpl(value, buffer, position, null);
 	}
 
-	public final StringBuffer format(Object number, StringBuffer toAppendTo,
-			FieldPosition pos) {
-		if (!(number instanceof Number)) {
-			throw new IllegalArgumentException();
+	private StringBuffer formatImpl(long value, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		if (multiplier != 1) {
+			int sign = 1;
+			if (value < 0)
+				sign *= -1;
+			if (multiplier < 0)
+				sign *= -1;
+			long oldValue = value;
+			value *= multiplier;
+			if ((sign > 0 && oldValue >= value)
+					|| (sign < 0 && oldValue <= value))
+				return formatImpl((double) oldValue, buffer, position, fields);
+
+			// Check for large overflows missed by the previous check
+			double result = (double) value * multiplier;
+			if (result > Long.MAX_VALUE || result < Long.MIN_VALUE)
+				return formatImpl((double) value, buffer, position, fields);
+		}
+
+		// SIGN or CURRENCY fields
+		String prefix = (value < 0) ? getNegativePrefix() : getPositivePrefix();
+		formatPrefixSuffix(prefix, buffer, position, fields);
+
+		// INTEGER field begins
+		FieldPosition positionInteger = null;
+		positionInteger = new FieldPosition(Field.INTEGER);
+		handleIntegerBegin(buffer.length(), position, fields, positionInteger);
+
+		int outLength = buffer.length();
+		String digits = Long.toString(value);
+
+		int exponent = 0, scale = 0, minFract = 0;
+		if (useExponentialNotation) {
+			if (value < 0)
+				digits = digits.substring(1, digits.length());
+			int length = digits.length();
+			minFract = getMinimumIntegerDigits() + getMinimumFractionDigits();
+			exponent = length - 1;
+
+			boolean fixed = getMinimumIntegerDigits() == getMaximumIntegerDigits();
+			if (fixed) {
+				minFract -= getMinimumIntegerDigits();
+				scale = getMinimumIntegerDigits() - 1;
+				if (value != 0)
+					exponent -= scale;
+				scale++;
+			} else {
+				scale = exponent % getMaximumIntegerDigits();
+				if (value != 0)
+					exponent -= scale;
+				if (getMinimumIntegerDigits() > 0)
+					scale++;
+				else if (value != 0)
+					exponent++;
+				minFract -= scale;
+			}
+			if (getMaximumIntegerDigits() + getMaximumFractionDigits() < length) {
+				int chop = length
+						- (getMaximumIntegerDigits() + getMaximumFractionDigits())
+						- 1;
+				for (int i = chop; --i >= 0;)
+					value /= 10;
+				// Round decimal digits
+				if (value < 0)
+					value -= 5;
+				else
+					value += 5;
+				digits = Long.toString(value);
+				if (value < 0)
+					digits = digits.substring(1, digits.length());
+
+				int remove = 1;
+				if (digits.length() > (length - chop)) {
+					// Rounding changed the scale
+					if (fixed || getMinimumIntegerDigits() == 0) {
+						remove++;
+						exponent++;
+					} else {
+						if (scale == getMaximumIntegerDigits()) {
+							exponent += getMaximumIntegerDigits();
+							remove += getMaximumIntegerDigits();
+							minFract += scale - 1;
+							scale = 1;
+						} else {
+							scale++;
+							minFract--;
+						}
+					}
+				}
+				digits = digits.substring(0, digits.length() - remove);
+			}
+			for (int i = 0; i < scale; i++) {
+				if (i >= digits.length())
+					buffer.append(zero);
+				else
+					buffer.append((char) (zero + (digits.charAt(i) - '0')));
+			}
+		} else
+			formatInteger(digits, buffer, position, fields);
+
+		// Always print a digit
+		if (!useExponentialNotation && outLength == buffer.length())
+			buffer.append(zero);
+
+		// INTEGER Field ends
+		handleIntegerEnd(buffer.length(), position, fields, positionInteger);
+
+		if (useExponentialNotation) {
+			StringBuffer output = new StringBuffer();
+			int lastDigit = 0;
+			for (int i = 0; i < digits.length() - scale; i++) {
+				int digit = digits.charAt(scale + i) - '0';
+				if (digit > 0)
+					lastDigit = i + 1;
+				output.append((char) (zero + digit));
+			}
+			for (int i = output.length(); i < minFract; i++)
+				output.append(zero);
+			output.setLength(lastDigit < minFract ? minFract : lastDigit);
+			formatFraction(output, buffer, position, fields);
+		} else {
+			StringBuffer output = new StringBuffer();
+			for (int i = 0; i < getMinimumFractionDigits(); i++)
+				output.append(zero);
+			formatFraction(output, buffer, position, fields);
+		}
+
+		if (useExponentialNotation)
+			formatExponent(exponent, buffer, position, fields);
+
+		// handle SIGN, CURRENCY, PERMILLE or PERCENT fields
+		String suffix = (value < 0) ? getNegativeSuffix() : getPositiveSuffix();
+		formatPrefixSuffix(suffix, buffer, position, fields);
+
+		return buffer;
+	}
+
+	private void formatPrefixSuffix(String fix, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		int beginIndex = buffer.length();
+		buffer.append(fix);
+
+		if (fix.length() > 0) {
+			DecimalFormatSymbols formatSymbols = getDecimalFormatSymbols();
+			String curSymbol = formatSymbols.getCurrencySymbol();
+
+			int index;
+			if ((index = fix.indexOf(curSymbol)) > -1)
+				handleField(Field.CURRENCY, beginIndex + index, beginIndex
+						+ index + curSymbol.length(), position, fields);
+
+			if ((index = fix.indexOf(formatSymbols.getMinusSign())) > -1)
+				handleField(Field.SIGN, beginIndex + index, beginIndex + index
+						+ 1, position, fields);
+
+			if ((index = fix.indexOf(formatSymbols.getPercent())) > -1)
+				handleField(Field.PERCENT, beginIndex + index, beginIndex
+						+ index + 1, position, fields);
+
+			if ((index = fix.indexOf(formatSymbols.getPerMill())) > -1)
+				handleField(Field.PERMILLE, beginIndex + index, beginIndex
+						+ index + 1, position, fields);
+		}
+	}
+
+	private void formatInteger(String output, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		int offset = 0;
+		int total = output.length();
+
+		if (output.charAt(0) == '-') {
+			offset = 1;
+			total--;
+		}
+
+		boolean firstOccurrenceFound = false;
+		int groupSize = getGroupingSize();
+		if (!isGroupingUsed())
+			groupSize = 0;
+		if (getMinimumIntegerDigits() > total) {
+			int extra = getMinimumIntegerDigits() - total;
+			total = getMinimumIntegerDigits();
+			for (int i = 0; i < extra; i++) {
+				buffer.append(zero);
+				total--;
+				if (groupSize > 0 && total > 0 && total % groupSize == 0) {
+					buffer.append(symbols.getGroupingSeparator());
+					int index = buffer.length();
+					if (fields != null) {
+						addToFields(fields, Field.GROUPING_SEPARATOR,
+								index - 1, index);
+					} else {
+						if (!firstOccurrenceFound
+								&& position.getFieldAttribute() == Field.GROUPING_SEPARATOR) {
+							position.setBeginIndex(index - 1);
+							position.setEndIndex(index);
+							firstOccurrenceFound = true;
+						}
+					}
+				}
+
+			}
+		}
+
+		if (total > getMaximumIntegerDigits()) {
+			offset += total - getMaximumIntegerDigits();
+			total = getMaximumIntegerDigits();
 		}
-		if (toAppendTo == null || pos == null) {
-			throw new NullPointerException();
+
+		if (getMinimumIntegerDigits() == 0 && total == 1
+				&& output.charAt(offset) == '0')
+			return;
+
+		for (int i = offset; i < output.length(); i++) {
+			buffer.append((char) (zero + (output.charAt(i) - '0')));
+			total--;
+			if (groupSize > 0 && total > 0 && total % groupSize == 0) {
+				buffer.append(symbols.getGroupingSeparator());
+				int index = buffer.length();
+				if (fields != null) {
+					addToFields(fields, Field.GROUPING_SEPARATOR, index - 1,
+							index);
+				} else {
+					if (!firstOccurrenceFound
+							&& position.getFieldAttribute() == Field.GROUPING_SEPARATOR) {
+						position.setBeginIndex(index - 1);
+						position.setEndIndex(index);
+						firstOccurrenceFound = true;
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Appends decimal seperator and fraction fields to the buffer, and to the
+	 * fields vector if needed.
+	 * 
+	 * Sets the begin and end index of the position if fields vector is null,
+	 * and position has a DECIMAL_SEPARATOR or FRACTION field.
+	 * 
+	 * @param fraction
+	 * @param buffer
+	 * @param position
+	 * @param fields
+	 */
+	private void formatFraction(StringBuffer fraction, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		int index;
+		int len = fraction.length();
+		if (isDecimalSeparatorAlwaysShown() || len > 0) {
+			// DECIMAL_SEPERATOR field
+			buffer.append(getDecimalSeparator());
+			index = buffer.length();
+			handleField(Field.DECIMAL_SEPARATOR, index - 1, index, position,
+					fields);
+		}
+
+		if (len > 0) {
+			// FRACTION field
+			buffer.append(fraction);
+			index = buffer.length();
+			if (fields != null)
+				addToFields(fields, Field.FRACTION, index - len, index);
+			else {
+				if (position.getFieldAttribute() == Field.FRACTION
+						|| (position.getFieldAttribute() == null && position
+								.getField() == FRACTION_FIELD)) {
+					position.setBeginIndex(index - len);
+					position.setEndIndex(index);
+				}
+			}
+		}
+	}
+
+	private void formatExponent(int exponent, StringBuffer buffer,
+			FieldPosition position, Vector fields) {
+		String output = Integer.toString(exponent);
+		int offset = 0;
+		int total = output.length();
+
+		buffer.append(symbols.getExponential());
+
+		int currentIndex = buffer.length();
+		handleField(Field.EXPONENT_SYMBOL, currentIndex - 1, currentIndex,
+				position, fields);
+
+		if (exponent < 0) {
+			buffer.append(getNegativePrefix());
+			offset = 1;
+			total--;
+		} else
+			buffer.append(getPositivePrefix());
+
+		int prefixLen = (exponent < 0) ? getNegativePrefix().length()
+				: getPositivePrefix().length();
+		if (prefixLen > 0) {
+			currentIndex = buffer.length();
+			handleField(Field.EXPONENT_SIGN, currentIndex - prefixLen,
+					currentIndex, position, fields);
+		}
+
+		if (minExponentDigits > total) {
+			for (int i = minExponentDigits - total; --i >= 0;)
+				buffer.append(zero);
+		}
+
+		for (int i = offset; i < output.length(); i++)
+			buffer.append((char) (zero + (output.charAt(i) - '0')));
+
+		handleField(Field.EXPONENT, currentIndex, buffer.length(), position,
+				fields);
+
+		if (exponent < 0)
+			buffer.append(getNegativeSuffix());
+		else
+			buffer.append(getPositiveSuffix());
+
+		int suffixLen = (exponent < 0) ? getNegativeSuffix().length()
+				: getPositiveSuffix().length();
+		if (suffixLen > 0) {
+			currentIndex = buffer.length();
+			handleField(Field.EXPONENT_SIGN, currentIndex - suffixLen,
+					currentIndex, position, fields);
 		}
-		if (number instanceof BigInteger || number instanceof BigDecimal) {
-			return dform.format(number, toAppendTo, pos);
+	}
+
+	/**
+	 * Adds the field to the fields vector, or sets the <code>position</code>'s
+	 * begin and end index if it has the same field attribute as
+	 * <code>field</code>
+	 * 
+	 * @param field
+	 * @param begin
+	 * @param end
+	 * @param position
+	 * @param fields
+	 */
+	private void handleField(Field field, int begin, int end,
+			FieldPosition position, Vector fields) {
+		if (fields != null)
+			addToFields(fields, field, begin, end);
+		else {
+			if (position.getFieldAttribute() == field) {
+				position.setBeginIndex(begin);
+				position.setEndIndex(end);
+			}
+		}
+	}
+
+	private void addToFields(Vector fields, Field field, int begin, int end) {
+		FieldPosition pos = new FieldPosition(field);
+		pos.setBeginIndex(begin);
+		pos.setEndIndex(end);
+		fields.add(pos);
+	}
+
+	private void handleIntegerBegin(int index, FieldPosition position,
+			Vector fields, FieldPosition positionInteger) {
+		if (fields != null)
+			positionInteger.setBeginIndex(index);
+		else {
+			if (position.getFieldAttribute() == Field.INTEGER
+					|| (position.getFieldAttribute() == null && position
+							.getField() == INTEGER_FIELD))
+				position.setBeginIndex(index);
+		}
+	}
+
+	private void handleIntegerEnd(int index, FieldPosition position,
+			Vector fields, FieldPosition positionInteger) {
+		if (fields != null) {
+			positionInteger.setEndIndex(index);
+			fields.add(positionInteger);
 		} else {
-			return super.format(number, toAppendTo, pos);
+			if (position.getFieldAttribute() == Field.INTEGER
+					|| (position.getFieldAttribute() == null && position
+							.getField() == INTEGER_FIELD))
+				position.setEndIndex(index);
 		}
 	}
 
@@ -267,6 +1099,12 @@
 		return (DecimalFormatSymbols) symbols.clone();
 	}
 
+	private char getDecimalSeparator() {
+		if (isCurrency())
+			return symbols.getMonetaryDecimalSeparator();
+		return symbols.getDecimalSeparator();
+	}
+
 	/**
 	 * Answers the currency used by this decimal format.
 	 * 
@@ -274,7 +1112,7 @@
 	 * @see DecimalFormatSymbols#getCurrency()
 	 */
 	public Currency getCurrency() {
-		return Currency.getInstance(dform.getCurrency().getCurrencyCode());
+		return symbols.getCurrency();
 	}
 
 	/**
@@ -283,7 +1121,7 @@
 	 * @return the number of digits grouped together
 	 */
 	public int getGroupingSize() {
-		return dform.getGroupingSize();
+		return groupingSize;
 	}
 
 	/**
@@ -293,7 +1131,7 @@
 	 * @return the multiplier
 	 */
 	public int getMultiplier() {
-		return dform.getMultiplier();
+		return multiplier;
 	}
 
 	/**
@@ -302,7 +1140,7 @@
 	 * @return the negative prefix
 	 */
 	public String getNegativePrefix() {
-		return dform.getNegativePrefix();
+		return negPrefixPattern == null ? negativePrefix : negPrefixPattern;
 	}
 
 	/**
@@ -311,7 +1149,7 @@
 	 * @return the negative suffix
 	 */
 	public String getNegativeSuffix() {
-		return dform.getNegativeSuffix();
+		return negSuffixPattern == null ? negativeSuffix : negSuffixPattern;
 	}
 
 	/**
@@ -320,7 +1158,7 @@
 	 * @return the positive prefix
 	 */
 	public String getPositivePrefix() {
-		return dform.getPositivePrefix();
+		return posPrefixPattern == null ? positivePrefix : posPrefixPattern;
 	}
 
 	/**
@@ -329,7 +1167,7 @@
 	 * @return the positive suffix
 	 */
 	public String getPositiveSuffix() {
-		return dform.getPositiveSuffix();
+		return posSuffixPattern == null ? positiveSuffix : posSuffixPattern;
 	}
 
 	/**
@@ -341,7 +1179,17 @@
 	 * @see #equals
 	 */
 	public int hashCode() {
-		return dform.hashCode();
+		return super.hashCode() + symbols.hashCode() + groupingSize
+				+ multiplier + positivePrefix.hashCode()
+				+ positiveSuffix.hashCode() + negativePrefix.hashCode()
+				+ negativeSuffix.hashCode()
+				+ (decimalSeparatorAlwaysShown ? 1231 : 1237)
+				+ (isCurrency() ? 1231 : 1237);
+	}
+
+	private boolean isCurrency() {
+		return posPrefixMonetary || posSuffixMonetary || negPrefixMonetary
+				|| negSuffixMonetary;
 	}
 
 	/**
@@ -352,30 +1200,75 @@
 	 *         otherwise
 	 */
 	public boolean isDecimalSeparatorAlwaysShown() {
-		return dform.isDecimalSeparatorAlwaysShown();
+		return decimalSeparatorAlwaysShown;
 	}
 
-	/**
-	 * This value indicates whether the return object of the parse operation
-	 * will be of type BigDecimal. This value will default to false.
-	 * 
-	 * @return true and parse will always return BigDecimals, false and the type
-	 *         of the result will be Long or Double.
-	 */
-	public boolean isParseBigDecimal() {
-		return this.parseBigDecimal;
-	}
-	
-	public void setParseIntegerOnly(boolean value) {
-		dform.setParseIntegerOnly(value);
-	}
-	
-	public boolean isParseIntegerOnly() {
-		return dform.isParseIntegerOnly();
+	private int parseExponent(String string, ParsePosition position) {
+		int sign = 0;
+		int offset = position.getIndex();
+		position.setIndex(-1);
+		if (positivePrefix.length() != 0
+				&& string.startsWith(positivePrefix, offset)) {
+			sign = 1;
+			offset += positivePrefix.length();
+		} else {
+			if (negativePrefix.length() != 0
+					&& string.startsWith(negativePrefix, offset)) {
+				sign = -1;
+				offset += negativePrefix.length();
+			} else if (positivePrefix.length() != 0
+					&& negativePrefix.length() != 0)
+				return 0;
+		}
+
+		boolean overflow = false;
+		int number = 0, lastOffset = offset;
+		int length = string.length();
+		while (offset < length) {
+			char ch = string.charAt(offset);
+			int value = getDigit(ch);
+			if (value == -1)
+				break;
+			int next = number * 10 - value;
+			if (next > number)
+				overflow = true;
+			number = next;
+			offset++;
+		}
+		if (offset == lastOffset)
+			return 0;
+
+		if (sign >= 0) {
+			if (positiveSuffix.length() == 0) {
+				position.setIndex(offset);
+				sign = 1;
+			} else if (string.startsWith(positiveSuffix, offset)) {
+				position.setIndex(offset + positiveSuffix.length());
+				sign = 1;
+			} else if (sign == 1)
+				return 0;
+		}
+		if (sign <= 0) {
+			if (negativeSuffix.length() == 0) {
+				position.setIndex(offset);
+				sign = -1;
+			} else if (string.startsWith(negativeSuffix, offset)) {
+				position.setIndex(offset + negativeSuffix.length());
+				sign = -1;
+			} else
+				return 0;
+		}
+		if (sign != -1) {
+			number = -number;
+			// catch MIN_VALUE case
+			if (number < 0)
+				overflow = true;
+		}
+		if (overflow)
+			return 1024; // Return any overflow number
+		return number;
 	}
 
-	private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0);
-	
 	/**
 	 * Parse a Long or Double from the specified String starting at the index
 	 * specified by the ParsePosition. If the string is successfully parsed, the
@@ -393,39 +1286,261 @@
 	 *         integer in the range of a long, otherwise the result is a Double.
 	 */
 	public Number parse(String string, ParsePosition position) {
-		Number number = dform.parse(string, position);
-		if (null == number) {
-			return null;
+		int offset = position.getIndex();
+		if (offset < 0)
+			return error(position, offset);
+		if (string.startsWith(symbols.getNaN(), offset)) {
+			position.setIndex(offset + symbols.getNaN().length());
+			return new Double(Double.NaN);
+		}
+
+		int sign = 0;
+		boolean posPre = positivePrefix.length() > 0
+				&& string.startsWith(positivePrefix, offset);
+		if (positivePrefix.equals(negativePrefix)) {
+			if (positivePrefix.length() > 0 && !posPre)
+				return error(position, offset);
+			offset += positivePrefix.length();
+		} else {
+			boolean negPre = negativePrefix.length() > 0
+					&& string.startsWith(negativePrefix, offset);
+			if ((posPre || positivePrefix.length() == 0
+					&& negativePrefix.length() > 0)
+					&& !negPre) {
+				sign = 1;
+				offset += positivePrefix.length();
+			} else if ((negPre || negativePrefix.length() == 0
+					&& positivePrefix.length() > 0)
+					&& !posPre) {
+				sign = -1;
+				offset += negativePrefix.length();
+			} else if (positivePrefix.length() != 0
+					&& negativePrefix.length() != 0)
+				return error(position, offset);
 		}
-		if (this.isParseBigDecimal()) {
-			if (number instanceof Long) {
-				return new BigDecimal(number.longValue());
-			}
-			if ((number instanceof Double) && !((Double) number).isInfinite()
-					&& !((Double) number).isNaN()) {
 
-				return new BigDecimal(number.doubleValue());
+		double dnumber = 0;
+		long max = Long.MIN_VALUE / 10;
+		boolean overflow = false, useFloat = false;
+		long number = 0, fraction = 0;
+		int length = string.length(), lastValid = -1, decimalDigits = 0, fractionDigits = 0, exponent = 0;
+		if (string.startsWith(symbols.getInfinity(), offset)) {
+			lastValid = (offset += symbols.getInfinity().length());
+			dnumber = Double.POSITIVE_INFINITY;
+		} else {
+			boolean digits = false;
+			while (offset < length) {
+				char ch = string.charAt(offset);
+				if (ch == getDecimalSeparator()) {
+					if (!isParseIntegerOnly()) {
+						offset++;
+						lastValid = offset;
+						StringBuffer fractDigits = new StringBuffer();
+						while (offset < length) {
+							ch = string.charAt(offset);
+							if (getDigit(ch) == -1)
+								break;
+							fractDigits.append(ch);
+							offset++;
+							lastValid = offset;
+						}
+						int len = fractDigits.length() - 1;
+						while (len >= 0
+								&& getDigit(fractDigits.charAt(len)) == 0) {
+							digits = true;
+							len--;
+						}
+						for (int i = 0; i <= len; i++) {
+							digits = true;
+							int value = getDigit(fractDigits.charAt(i));
+							if (!overflow) {
+								if (max > fraction) {
+									overflow = true;
+									break;
+								}
+								long next = fraction * 10 - value;
+								if (next <= fraction) {
+									fraction = next;
+									fractionDigits++;
+								} else {
+									overflow = true;
+									break;
+								}
+							}
+						}
+						if (ch == symbols.getExponential()) {
+							ParsePosition pos = new ParsePosition(offset + 1);
+							exponent = parseExponent(string, pos);
+							if (pos.getIndex() != -1)
+								lastValid = pos.getIndex();
+						}
+					}
+					break;
+				}
+				int value = getDigit(ch);
+				if (value != -1) {
+					digits = true;
+					if (number != 0 || value > 0) {
+						decimalDigits++;
+						if (useFloat)
+							dnumber = dnumber * 10 - value;
+						else {
+							if (max <= number) {
+								long next = number * 10 - value;
+								if (next > number) { // Overflow
+									dnumber = number * 10.0 - value;
+									useFloat = true;
+								} else
+									number = next;
+							} else { // Overflow
+								dnumber = number * 10.0 - value;
+								useFloat = true;
+							}
+						}
+					}
+					lastValid = offset + 1;
+				} else if (ch == symbols.getExponential()) {
+					ParsePosition pos = new ParsePosition(offset + 1);
+					exponent = parseExponent(string, pos);
+					if (pos.getIndex() != -1)
+						lastValid = pos.getIndex();
+					break;
+				} else if (ch != symbols.getGroupingSeparator()
+						|| !isGroupingUsed())
+					break;
+				offset++;
 			}
-			if (number instanceof BigInteger) {
-				return new BigDecimal(number.doubleValue());
+			if (!digits)
+				return error(position, position.getIndex());
+		}
+
+		if (sign == 0) {
+			boolean posSuf = positiveSuffix.length() > 0
+					&& string.startsWith(positiveSuffix, offset);
+			boolean negSuf = negativeSuffix.length() > 0
+					&& string.startsWith(negativeSuffix, offset);
+			if (posSuf != negSuf) {
+				if (posSuf)
+					sign = 1;
+				else
+					sign = -1;
+			} else if (positiveSuffix.equals(negativeSuffix))
+				return error(position, lastValid);
+		}
+		if (sign >= 0) {
+			if (positiveSuffix.length() == 0) {
+				position.setIndex(lastValid);
+				sign = 1;
+			} else if (offset == lastValid
+					&& string.startsWith(positiveSuffix, offset)) {
+				position.setIndex(offset + positiveSuffix.length());
+				sign = 1;
+			} else if (sign == 1)
+				return error(position, lastValid);
+		}
+		if (sign <= 0) {
+			if (negativeSuffix.length() == 0) {
+				position.setIndex(lastValid);
+				sign = -1;
+			} else if (offset == lastValid
+					&& string.startsWith(negativeSuffix, offset)) {
+				position.setIndex(offset + negativeSuffix.length());
+				sign = -1;
+			} else
+				return error(position, lastValid);
+		}
+
+		if (!useFloat
+				&& ((fraction != 0 && exponent == 0) || exponent < 0
+						|| exponent + decimalDigits - 1 > 19
+						|| exponent < fractionDigits || overflow)) {
+			dnumber = number;
+			useFloat = true;
+		}
+		if (!useFloat && number != 0) {
+			long next = number;
+			for (int i = exponent; --i >= 0;) {
+				if (max > next) { // Overflow
+					dnumber = number;
+					useFloat = true;
+					break;
+				}
+				next *= 10;
 			}
-			if (number instanceof com.ibm.icu.math.BigDecimal) {
-				return new BigDecimal(number.toString());
+			number = next;
+		}
+		if (fraction != 0 && !useFloat) {
+			long next = fraction;
+			for (int i = exponent - fractionDigits; --i >= 0;)
+				next *= 10;
+			long result = number + next;
+			if (next < number)
+				number = result;
+			else { // Overflow
+				dnumber = number;
+				exponent = 0;
+				fraction = next;
+				fractionDigits = 0;
+				useFloat = true;
 			}
-			return number;
-		} else {
-			if ((number instanceof com.ibm.icu.math.BigDecimal)
-					|| (number instanceof BigInteger)) {
-				return new Double(number.doubleValue());
+		}
+		if (useFloat) {
+			if (fraction != 0)
+				dnumber += fraction / Math.pow(10.0, fractionDigits);
+			if (exponent != 0)
+				dnumber *= Math.pow(10.0, exponent);
+		}
+		if (!useFloat && number == 0 && sign == -1 && !isParseIntegerOnly()) {
+			dnumber = -1.0 * 0;
+			useFloat = true;
+		}
+
+		if (multiplier != 1) {
+			if (dnumber != 0) {
+				dnumber /= multiplier;
+			} else {
+				long lResult = number / multiplier;
+				double dResult = (double) number / multiplier;
+				if (dResult == lResult)
+					number = lResult;
+				else {
+					dnumber = dResult;
+					useFloat = true;
+				}
 			}
+		}
+
+		if (number == Long.MIN_VALUE && sign == 1) {
+			dnumber = number;
+			useFloat = true;
+		}
 
-			if (this.isParseIntegerOnly() && number.equals(NEGATIVE_ZERO_DOUBLE)) {
-				return new Long(0);
-			} 
-			return number;
+		if (useFloat)
+			return new Double(sign < 0 ? dnumber : -dnumber);
+		return new Long(sign < 0 ? number : -number);
+	}
 
+	private String quote(String string, String special) {
+		for (int i = 0; i < special.length(); i++) {
+			char ch = special.charAt(i);
+			if (string.indexOf(ch) != -1
+					&& (i < 5 || ch != patternChars.charAt(i)))
+				return '\'' + string + '\'';
 		}
+		return string;
+	}
 
+	private int scale(double value) {
+		if (value == 0.0)
+			return 0;
+		int scale = (int) Math.floor(Math.log(value) / log10);
+		return Math.pow(10.0, scale) > value ? scale - 1 : scale;
+	}
+
+	private String expandAffix(String affix) {
+		String newAffix = convertPattern(affix, patternChars, new String(
+				symbols.patternChars), false);
+		return convertCurrencySymbols(newAffix);
 	}
 
 	/**
@@ -435,9 +1550,19 @@
 	 *            the DecimalFormatSymbols
 	 */
 	public void setDecimalFormatSymbols(DecimalFormatSymbols value) {
-		symbols = (DecimalFormatSymbols) value.clone();
-		icuSymbols = adapt2ICU(symbols);
-		dform.setDecimalFormatSymbols(icuSymbols);
+		if (value != null) {
+			symbols = (DecimalFormatSymbols) value.clone();
+			zero = symbols.getZeroDigit();
+			// Update localized affix
+			if (posPrefixPattern != null)
+				posPrefixPattern = expandAffix(positivePrefix);
+			if (posSuffixPattern != null)
+				posSuffixPattern = expandAffix(positiveSuffix);
+			if (negPrefixPattern != null)
+				negPrefixPattern = expandAffix(negativePrefix);
+			if (negSuffixPattern != null)
+				negSuffixPattern = expandAffix(negativeSuffix);
+		}
 	}
 
 	/**
@@ -448,8 +1573,6 @@
 	 * @see DecimalFormatSymbols#setCurrency(Currency)
 	 */
 	public void setCurrency(Currency currency) {
-		dform.setCurrency(com.ibm.icu.util.Currency.getInstance(currency
-				.getCurrencyCode()));
 		symbols.setCurrency(currency);
 	}
 
@@ -462,7 +1585,7 @@
 	 *            false otherwise
 	 */
 	public void setDecimalSeparatorAlwaysShown(boolean value) {
-		dform.setDecimalSeparatorAlwaysShown(value);
+		decimalSeparatorAlwaysShown = value;
 	}
 
 	/**
@@ -472,7 +1595,7 @@
 	 *            the number of digits grouped together
 	 */
 	public void setGroupingSize(int value) {
-		dform.setGroupingSize(value);
+		groupingSize = (byte) value;
 	}
 
 	/**
@@ -485,8 +1608,9 @@
 	 *            the maximum number of fraction digits
 	 */
 	public void setMaximumFractionDigits(int value) {
-		super.setMaximumFractionDigits(value);
-		dform.setMaximumFractionDigits(value);
+		super
+				.setMaximumFractionDigits(value > DOUBLE_FRACTION_DIGITS ? DOUBLE_FRACTION_DIGITS
+						: value);
 	}
 
 	/**
@@ -499,8 +1623,9 @@
 	 *            the maximum number of integer digits
 	 */
 	public void setMaximumIntegerDigits(int value) {
-		super.setMaximumIntegerDigits(value);
-		dform.setMaximumIntegerDigits(value);
+		super
+				.setMaximumIntegerDigits(value > DOUBLE_INTEGER_DIGITS ? DOUBLE_INTEGER_DIGITS
+						: value);
 	}
 
 	/**
@@ -511,8 +1636,9 @@
 	 *            the minimum number of fraction digits
 	 */
 	public void setMinimumFractionDigits(int value) {
-		super.setMinimumFractionDigits(value);
-		dform.setMinimumFractionDigits(value);
+		super
+				.setMinimumFractionDigits(value > DOUBLE_FRACTION_DIGITS ? DOUBLE_FRACTION_DIGITS
+						: value);
 	}
 
 	/**
@@ -523,8 +1649,9 @@
 	 *            the minimum number of integer digits
 	 */
 	public void setMinimumIntegerDigits(int value) {
-		super.setMinimumIntegerDigits(value);
-		dform.setMinimumIntegerDigits(value);
+		super
+				.setMinimumIntegerDigits(value > DOUBLE_INTEGER_DIGITS ? DOUBLE_INTEGER_DIGITS
+						: value);
 	}
 
 	/**
@@ -535,7 +1662,7 @@
 	 *            the multiplier
 	 */
 	public void setMultiplier(int value) {
-		dform.setMultiplier(value);
+		multiplier = value;
 	}
 
 	/**
@@ -545,7 +1672,9 @@
 	 *            the negative prefix
 	 */
 	public void setNegativePrefix(String value) {
-		dform.setNegativePrefix(value);
+		negativePrefix = value;
+		negPrefixMonetary = false;
+		negPrefixPattern = null;
 	}
 
 	/**
@@ -555,7 +1684,9 @@
 	 *            the negative suffix
 	 */
 	public void setNegativeSuffix(String value) {
-		dform.setNegativeSuffix(value);
+		negativeSuffix = value;
+		negSuffixMonetary = false;
+		negSuffixPattern = null;
 	}
 
 	/**
@@ -565,7 +1696,9 @@
 	 *            the positive prefix
 	 */
 	public void setPositivePrefix(String value) {
-		dform.setPositivePrefix(value);
+		positivePrefix = value;
+		posPrefixMonetary = false;
+		posPrefixPattern = null;
 	}
 
 	/**
@@ -575,15 +1708,9 @@
 	 *            the positive suffix
 	 */
 	public void setPositiveSuffix(String value) {
-		dform.setPositiveSuffix(value);
-	}
-
-	/**
-	 * Let users change the behavior of a DecimalFormat, If set to true all the
-	 * returned objects will be of type BigDecimal
-	 */
-	public void setParseBigDecimal(boolean newValue) {
-		this.parseBigDecimal = newValue;
+		positiveSuffix = value;
+		posSuffixMonetary = false;
+		posSuffixPattern = null;
 	}
 
 	/**
@@ -593,7 +1720,7 @@
 	 * @return the localized pattern
 	 */
 	public String toLocalizedPattern() {
-		return dform.toLocalizedPattern();
+		return toPatternString(symbols.getLocalPatternChars());
 	}
 
 	/**
@@ -603,18 +1730,105 @@
 	 * @return the non-localized pattern
 	 */
 	public String toPattern() {
-		return dform.toPattern();
+		return toPatternString(patternChars);
 	}
 
-	
-	private void writeObject(ObjectOutputStream stream) throws IOException,
-			ClassNotFoundException {
-		throw new NotYetImplementedException();
+	private String toPatternString(String localPatternChars) {
+		StringBuffer pattern = new StringBuffer();
+		boolean groupingUsed = isGroupingUsed() && getGroupingSize() > 0;
+		if (!groupingUsed || groupingSize > getMinimumIntegerDigits()) {
+			if (groupingUsed) {
+				if (useExponentialNotation) {
+					for (int i = 0; i < getMaximumIntegerDigits()
+							- groupingSize - 1; i++)
+						pattern.append('#');
+				}
+				pattern.append("#,");
+				for (int i = 0; i < groupingSize - getMinimumIntegerDigits(); i++)
+					pattern.append('#');
+			} else if (useExponentialNotation) {
+				for (int i = 0; i < getMaximumIntegerDigits()
+						- getMinimumIntegerDigits(); i++)
+					pattern.append('#');
+			} else
+				pattern.append('#');
+			for (int i = 0; i < getMinimumIntegerDigits(); i++)
+				pattern.append('0');
+		} else {
+			if (useExponentialNotation) {
+				for (int i = 0; i < getMaximumIntegerDigits()
+						- getMinimumIntegerDigits(); i++)
+					pattern.append('#');
+			} else
+				pattern.append('#');
+			for (int i = 0; i < getMinimumIntegerDigits() - groupingSize; i++)
+				pattern.append('0');
+			pattern.append(',');
+			for (int i = 0; i < groupingSize; i++)
+				pattern.append('0');
+		}
+		if (getMaximumFractionDigits() > 0 || isDecimalSeparatorAlwaysShown()) {
+			pattern.append('.');
+			for (int i = 0; i < getMinimumFractionDigits(); i++)
+				pattern.append('0');
+			for (int i = 0; i < getMaximumFractionDigits()
+					- getMinimumFractionDigits(); i++)
+				pattern.append('#');
+		}
+		if (useExponentialNotation) {
+			pattern.append('E');
+			for (int i = 0; i < minExponentDigits; i++)
+				pattern.append('0');
+		}
+
+		String localPattern = pattern.toString();
+		String result = quote(positivePrefix, localPatternChars) + localPattern
+				+ quote(positiveSuffix, localPatternChars);
+		if (!negativePrefix.equals(symbols.getMinusSign() + positivePrefix)
+				|| !negativeSuffix.equals(positiveSuffix)) {
+			result = result + ';' + quote(negativePrefix, localPatternChars)
+					+ localPattern + quote(negativeSuffix, localPatternChars);
+		}
+		if (localPatternChars != patternChars)
+			result = convertPattern(result, patternChars, localPatternChars,
+					false);
+		return result;
 	}
 
 	private void readObject(ObjectInputStream stream) throws IOException,
 			ClassNotFoundException {
-		throw new NotYetImplementedException();
+		stream.defaultReadObject();
+		if (serialVersionOnStream == 0)
+			useExponentialNotation = false;
+		zero = symbols.getZeroDigit();
+		serialVersionOnStream = 2;
+		if (posPrefixPattern != null)
+			posPrefixMonetary = positivePrefix.indexOf(CURRENCY_SYMBOL) > -1;
+		if (posSuffixPattern != null)
+			posSuffixMonetary = positiveSuffix.indexOf(CURRENCY_SYMBOL) > -1;
+		if (negPrefixPattern != null)
+			negPrefixMonetary = negativePrefix.indexOf(CURRENCY_SYMBOL) > -1;
+		if (negSuffixPattern != null)
+			negSuffixMonetary = negativeSuffix.indexOf(CURRENCY_SYMBOL) > -1;
+		if (getMinimumIntegerDigits() > DOUBLE_INTEGER_DIGITS
+				|| getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS
+				|| getMinimumFractionDigits() > DOUBLE_FRACTION_DIGITS
+				|| getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS)
+			throw new InvalidObjectException(org.apache.harmony.luni.util.Msg
+					.getString("K00f9"));
+	}
+
+	long intPow(int exp) {
+		long result = 1;
+		for (int i = 0; i < exp; i++)
+			result *= 10;
+		return result;
+	}
+
+	int getDigit(char ch) {
+		int diff = ch - zero;
+		if (diff >= 0 && diff <= 9)
+			return diff;
+		return Character.digit(ch, 10);
 	}
-
 }

Modified: incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/AllTests.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/AllTests.java?rev=393171&r1=393170&r2=393171&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/AllTests.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/text/src/test/java/org/apache/harmony/tests/java/text/AllTests.java Tue Apr 11 03:02:16 2006
@@ -36,7 +36,6 @@
 		suite.addTestSuite(MessageFormatTest.class);
 		suite.addTestSuite(ChoiceFormatTest.class);
 		suite.addTestSuite(DataFormatFieldTest.class);
-		suite.addTestSuite(DecimalFormatTest.class);
 		//$JUnit-END$
 		return suite;
 	}