1:
37:
38:
43:
44: package ;
45:
46: import ;
47:
48: import ;
49: import ;
50:
51: import ;
52: import ;
53: import ;
54:
55:
69:
70:
80: public class DecimalFormat extends NumberFormat
81: {
82:
83: private static final long serialVersionUID = 864413376551465018L;
84:
85:
86: private static final int DEFAULT_INTEGER_DIGITS = 309;
87:
88:
92: private static final int DEFAULT_FRACTION_DIGITS = 340;
93:
94:
97:
98: private static final DecimalFormatSymbols nonLocalizedSymbols
99: = new DecimalFormatSymbols (Locale.US);
100:
101:
104: private boolean parseBigDecimal;
105:
106:
110: private boolean useCurrencySeparator;
111:
112:
113: private boolean decimalSeparatorAlwaysShown;
114:
115:
121: private boolean showDecimalSeparator;
122:
123:
128: private boolean groupingSeparatorInPattern;
129:
130:
131: private byte groupingSize;
132:
133:
138: private byte minExponentDigits;
139:
140:
141: private int exponentRound;
142:
143:
144: private int multiplier;
145:
146:
147: private int negativePatternMultiplier;
148:
149:
150: private String negativePrefix;
151:
152:
153: private String negativeSuffix;
154:
155:
156: private String positivePrefix;
157:
158:
159: private String positiveSuffix;
160:
161:
162: private DecimalFormatSymbols symbols;
163:
164:
165: private boolean useExponentialNotation;
166:
167:
171: private int maxIntegerDigitsExponent;
172:
173:
174: private boolean hasNegativePrefix;
175:
176:
177: private boolean hasFractionalPattern;
178:
179:
180: private ArrayList<FieldPosition> attributes = new ArrayList<FieldPosition>();
181:
182:
186: public DecimalFormat()
187: {
188: this ("#,##0.###");
189: }
190:
191:
199: public DecimalFormat(String pattern)
200: {
201: this (pattern, new DecimalFormatSymbols());
202: }
203:
204:
214: public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
215: {
216: this.symbols = (DecimalFormatSymbols) symbols.clone();
217: applyPatternWithSymbols(pattern, nonLocalizedSymbols);
218: }
219:
220:
227: public void applyLocalizedPattern (String pattern)
228: {
229: applyPatternWithSymbols(pattern, this.symbols);
230: }
231:
232:
239: public void applyPattern(String pattern)
240: {
241: applyPatternWithSymbols(pattern, nonLocalizedSymbols);
242: }
243:
244: public Object clone()
245: {
246: DecimalFormat c = (DecimalFormat) super.clone();
247: c.symbols = (DecimalFormatSymbols) symbols.clone();
248: return c;
249: }
250:
251:
264: public boolean equals(Object obj)
265: {
266: if (! (obj instanceof DecimalFormat))
267: return false;
268: DecimalFormat dup = (DecimalFormat) obj;
269: return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
270: && groupingUsed == dup.groupingUsed
271: && groupingSeparatorInPattern == dup.groupingSeparatorInPattern
272: && groupingSize == dup.groupingSize
273: && multiplier == dup.multiplier
274: && useExponentialNotation == dup.useExponentialNotation
275: && minExponentDigits == dup.minExponentDigits
276: && minimumIntegerDigits == dup.minimumIntegerDigits
277: && maximumIntegerDigits == dup.maximumIntegerDigits
278: && minimumFractionDigits == dup.minimumFractionDigits
279: && maximumFractionDigits == dup.maximumFractionDigits
280: && parseBigDecimal == dup.parseBigDecimal
281: && useCurrencySeparator == dup.useCurrencySeparator
282: && showDecimalSeparator == dup.showDecimalSeparator
283: && exponentRound == dup.exponentRound
284: && negativePatternMultiplier == dup.negativePatternMultiplier
285: && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent
286:
287:
288: && equals(negativePrefix, dup.negativePrefix)
289: && equals(negativeSuffix, dup.negativeSuffix)
290: && equals(positivePrefix, dup.positivePrefix)
291: && equals(positiveSuffix, dup.positiveSuffix)
292: && symbols.equals(dup.symbols));
293: }
294:
295:
300: public int hashCode()
301: {
302: return toPattern().hashCode();
303: }
304:
305:
315: public final StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos)
316: {
317: if (obj instanceof BigInteger)
318: {
319: BigDecimal decimal = new BigDecimal((BigInteger) obj);
320: formatInternal(decimal, true, sbuf, pos);
321: return sbuf;
322: }
323: else if (obj instanceof BigDecimal)
324: {
325: formatInternal((BigDecimal) obj, true, sbuf, pos);
326: return sbuf;
327: }
328:
329: return super.format(obj, sbuf, pos);
330: }
331:
332:
342: public StringBuffer format(double number, StringBuffer dest,
343: FieldPosition fieldPos)
344: {
345:
346: if (Double.isNaN(number))
347: {
348:
349: String nan = symbols.getNaN();
350: dest.append(nan);
351:
352:
353: if ((fieldPos.getField() == INTEGER_FIELD ||
354: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
355: {
356: int index = dest.length();
357: fieldPos.setBeginIndex(index - nan.length());
358: fieldPos.setEndIndex(index);
359: }
360: }
361: else if (Double.isInfinite(number))
362: {
363:
364: if (number < 0)
365: dest.append(this.negativePrefix);
366: else
367: dest.append(this.positivePrefix);
368:
369: dest.append(symbols.getInfinity());
370:
371: if (number < 0)
372: dest.append(this.negativeSuffix);
373: else
374: dest.append(this.positiveSuffix);
375:
376: if ((fieldPos.getField() == INTEGER_FIELD ||
377: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
378: {
379: fieldPos.setBeginIndex(dest.length());
380: fieldPos.setEndIndex(0);
381: }
382: }
383: else
384: {
385:
386: BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
387: formatInternal(bigDecimal, false, dest, fieldPos);
388: }
389:
390: return dest;
391: }
392:
393:
402: public StringBuffer format(long number, StringBuffer dest,
403: FieldPosition fieldPos)
404: {
405: BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
406: formatInternal(bigDecimal, true, dest, fieldPos);
407: return dest;
408: }
409:
410:
419: public AttributedCharacterIterator formatToCharacterIterator(Object value)
420: {
421:
425:
426: if (value == null)
427: throw new NullPointerException("Passed Object is null");
428:
429: if (!(value instanceof Number)) throw new
430: IllegalArgumentException("Cannot format given Object as a Number");
431:
432: StringBuffer text = new StringBuffer();
433: attributes.clear();
434: super.format(value, text, new FieldPosition(0));
435:
436: AttributedString as = new AttributedString(text.toString());
437:
438:
439: for (int i = 0; i < attributes.size(); i++)
440: {
441: FieldPosition pos = attributes.get(i);
442: Format.Field attribute = pos.getFieldAttribute();
443:
444: as.addAttribute(attribute, attribute, pos.getBeginIndex(),
445: pos.getEndIndex());
446: }
447:
448:
449: return as.getIterator();
450: }
451:
452:
460: public Currency getCurrency()
461: {
462: return symbols.getCurrency();
463: }
464:
465:
470: public DecimalFormatSymbols getDecimalFormatSymbols()
471: {
472: return (DecimalFormatSymbols) symbols.clone();
473: }
474:
475:
485: public int getGroupingSize()
486: {
487: return groupingSize;
488: }
489:
490:
495: public int getMultiplier()
496: {
497: return multiplier;
498: }
499:
500:
505: public String getNegativePrefix()
506: {
507: return negativePrefix;
508: }
509:
510:
515: public String getNegativeSuffix()
516: {
517: return negativeSuffix;
518: }
519:
520:
525: public String getPositivePrefix()
526: {
527: return positivePrefix;
528: }
529:
530:
535: public String getPositiveSuffix()
536: {
537: return positiveSuffix;
538: }
539:
540: public boolean isDecimalSeparatorAlwaysShown()
541: {
542: return decimalSeparatorAlwaysShown;
543: }
544:
545:
551: public void setParseBigDecimal(boolean newValue)
552: {
553: this.parseBigDecimal = newValue;
554: }
555:
556:
567: public boolean isParseBigDecimal()
568: {
569: return this.parseBigDecimal;
570: }
571:
572:
585: public Number parse(String str, ParsePosition pos)
586: {
587:
588:
589: if (str.contains(this.symbols.getNaN()))
590: return Double.valueOf(Double.NaN);
591:
592:
593: CPStringBuilder number = new CPStringBuilder();
594:
595:
596: char minus = symbols.getMinusSign();
597:
598:
599: int start = pos.getIndex();
600:
601:
602:
603: String _negativePrefix = (this.negativePrefix.compareTo("") == 0
604: ? minus + positivePrefix
605: : this.negativePrefix);
606:
607:
608:
609: int positiveLen = positivePrefix.length();
610: int negativeLen = _negativePrefix.length();
611:
612: boolean isNegative = str.startsWith(_negativePrefix);
613: boolean isPositive = str.startsWith(positivePrefix);
614:
615: if (isPositive && isNegative)
616: {
617:
618:
619: if (negativeLen > positiveLen)
620: {
621: start += _negativePrefix.length();
622: isNegative = true;
623: }
624: else
625: {
626: start += positivePrefix.length();
627: isPositive = true;
628: if (negativeLen < positiveLen)
629: isNegative = false;
630: }
631: }
632: else if (isNegative)
633: {
634: start += _negativePrefix.length();
635: isPositive = false;
636: }
637: else if (isPositive)
638: {
639: start += positivePrefix.length();
640: isNegative = false;
641: }
642: else
643: {
644: pos.setErrorIndex(start);
645: return null;
646: }
647:
648:
649: char decimalSeparator = symbols.getDecimalSeparator();
650: char zero = symbols.getZeroDigit();
651: char exponent = symbols.getExponential();
652:
653:
654: int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2;
655:
656: if (useExponentialNotation)
657: stop += minExponentDigits + 1;
658:
659: boolean inExponent = false;
660:
661:
662: int len = str.length();
663: if (len < stop) stop = len;
664: char groupingSeparator = symbols.getGroupingSeparator();
665:
666: int i = start;
667: while (i < stop)
668: {
669: char ch = str.charAt(i);
670: i++;
671:
672: if (ch >= zero && ch <= (zero + 9))
673: {
674: number.append(ch);
675: }
676: else if (this.parseIntegerOnly)
677: {
678: i--;
679: break;
680: }
681: else if (ch == decimalSeparator)
682: {
683: number.append('.');
684: }
685: else if (ch == exponent)
686: {
687: number.append(ch);
688: inExponent = !inExponent;
689: }
690: else if ((ch == '+' || ch == '-' || ch == minus))
691: {
692: if (inExponent)
693: number.append(ch);
694: else
695: {
696: i--;
697: break;
698: }
699: }
700: else
701: {
702: if (!groupingUsed || ch != groupingSeparator)
703: {
704: i--;
705: break;
706: }
707: }
708: }
709:
710:
711:
712: if (str.contains(symbols.getInfinity()))
713: {
714: int inf = str.indexOf(symbols.getInfinity());
715: pos.setIndex(inf);
716:
717:
718: if (this.parseBigDecimal)
719: {
720: if (isNegative)
721: return BigDecimal.valueOf(Double.NEGATIVE_INFINITY);
722:
723: return BigDecimal.valueOf(Double.POSITIVE_INFINITY);
724: }
725:
726: if (isNegative)
727: return Double.valueOf(Double.NEGATIVE_INFINITY);
728:
729: return Double.valueOf(Double.POSITIVE_INFINITY);
730: }
731:
732:
733: if (i == start || number.length() == 0)
734: {
735: pos.setErrorIndex(i);
736: return null;
737: }
738:
739:
740:
741: boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
742: boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
743: boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
744:
745: positiveLen = positiveSuffix.length();
746: negativeLen = negativeSuffix.length();
747:
748: if (isNegative && !hasNegativeSuffix)
749: {
750: pos.setErrorIndex(i);
751: return null;
752: }
753: else if (hasNegativeSuffix &&
754: !positiveEqualsNegative &&
755: (negativeLen > positiveLen))
756: {
757: isNegative = true;
758: }
759: else if (!hasPositiveSuffix)
760: {
761: pos.setErrorIndex(i);
762: return null;
763: }
764:
765: if (isNegative) number.insert(0, '-');
766:
767: pos.setIndex(i);
768:
769:
770: BigDecimal bigDecimal = new BigDecimal(number.toString());
771: if (this.parseBigDecimal)
772: return bigDecimal;
773:
774:
775: if (this.parseIntegerOnly)
776: return Long.valueOf(bigDecimal.longValue());
777:
778:
779: if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0))
780: return Double.valueOf(-0.0);
781:
782: try
783: {
784: BigDecimal integer
785: = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY);
786: return Long.valueOf(integer.longValue());
787: }
788: catch (ArithmeticException e)
789: {
790: return Double.valueOf(bigDecimal.doubleValue());
791: }
792: }
793:
794:
802: public void setCurrency(Currency currency)
803: {
804: Currency current = symbols.getCurrency();
805: if (current != currency)
806: {
807: String oldSymbol = symbols.getCurrencySymbol();
808: int len = oldSymbol.length();
809: symbols.setCurrency(currency);
810: String newSymbol = symbols.getCurrencySymbol();
811: int posPre = positivePrefix.indexOf(oldSymbol);
812: if (posPre != -1)
813: positivePrefix = positivePrefix.substring(0, posPre) +
814: newSymbol + positivePrefix.substring(posPre+len);
815: int negPre = negativePrefix.indexOf(oldSymbol);
816: if (negPre != -1)
817: negativePrefix = negativePrefix.substring(0, negPre) +
818: newSymbol + negativePrefix.substring(negPre+len);
819: int posSuf = positiveSuffix.indexOf(oldSymbol);
820: if (posSuf != -1)
821: positiveSuffix = positiveSuffix.substring(0, posSuf) +
822: newSymbol + positiveSuffix.substring(posSuf+len);
823: int negSuf = negativeSuffix.indexOf(oldSymbol);
824: if (negSuf != -1)
825: negativeSuffix = negativeSuffix.substring(0, negSuf) +
826: newSymbol + negativeSuffix.substring(negSuf+len);
827: }
828: }
829:
830:
836: public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
837: {
838: symbols = (DecimalFormatSymbols) newSymbols.clone();
839: }
840:
841:
850: public void setDecimalSeparatorAlwaysShown(boolean newValue)
851: {
852: decimalSeparatorAlwaysShown = newValue;
853: }
854:
855:
863: public void setGroupingSize(int groupSize)
864: {
865: groupingSize = (byte) groupSize;
866: }
867:
868:
877: public void setMaximumIntegerDigits(int newValue)
878: {
879: newValue = (newValue > 0) ? newValue : 0;
880: super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
881: }
882:
883:
892: public void setMinimumIntegerDigits(int newValue)
893: {
894: newValue = (newValue > 0) ? newValue : 0;
895: super.setMinimumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
896: }
897:
898:
907: public void setMaximumFractionDigits(int newValue)
908: {
909: newValue = (newValue > 0) ? newValue : 0;
910: super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
911: }
912:
913:
922: public void setMinimumFractionDigits(int newValue)
923: {
924: newValue = (newValue > 0) ? newValue : 0;
925: super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
926: }
927:
928:
935: public void setMultiplier(int newValue)
936: {
937: multiplier = newValue;
938: }
939:
940:
945: public void setNegativePrefix(String newValue)
946: {
947: negativePrefix = newValue;
948: }
949:
950:
955: public void setNegativeSuffix(String newValue)
956: {
957: negativeSuffix = newValue;
958: }
959:
960:
965: public void setPositivePrefix(String newValue)
966: {
967: positivePrefix = newValue;
968: }
969:
970:
975: public void setPositiveSuffix(String newValue)
976: {
977: positiveSuffix = newValue;
978: }
979:
980:
987: public String toLocalizedPattern()
988: {
989: return computePattern(this.symbols);
990: }
991:
992:
999: public String toPattern()
1000: {
1001: return computePattern(nonLocalizedSymbols);
1002: }
1003:
1004:
1005:
1006:
1015: private boolean equals(String s1, String s2)
1016: {
1017: if (s1 == null || s2 == null)
1018: return s1 == s2;
1019: return s1.equals(s2);
1020: }
1021:
1022:
1023:
1024:
1025:
1029: private String patternChars (DecimalFormatSymbols syms)
1030: {
1031: CPStringBuilder buf = new CPStringBuilder ();
1032:
1033: buf.append(syms.getDecimalSeparator());
1034: buf.append(syms.getDigit());
1035: buf.append(syms.getExponential());
1036: buf.append(syms.getGroupingSeparator());
1037: buf.append(syms.getMinusSign());
1038: buf.append(syms.getPatternSeparator());
1039: buf.append(syms.getPercent());
1040: buf.append(syms.getPerMill());
1041: buf.append(syms.getZeroDigit());
1042: buf.append('\'');
1043: buf.append('\u00a4');
1044:
1045: return buf.toString();
1046: }
1047:
1048:
1056: private CPStringBuilder quoteFix(String text, String patChars)
1057: {
1058: CPStringBuilder buf = new CPStringBuilder();
1059:
1060: int len = text.length();
1061: char ch;
1062: for (int index = 0; index < len; ++index)
1063: {
1064: ch = text.charAt(index);
1065: if (patChars.indexOf(ch) != -1)
1066: {
1067: buf.append('\'');
1068: buf.append(ch);
1069: if (ch != '\'') buf.append('\'');
1070: }
1071: else
1072: {
1073: buf.append(ch);
1074: }
1075: }
1076:
1077: return buf;
1078: }
1079:
1080:
1084: private String computePattern(DecimalFormatSymbols symbols)
1085: {
1086: StringBuilder mainPattern = new StringBuilder();
1087:
1088:
1089:
1090:
1091: int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize;
1092: int totalDigits = Math.max(minimumIntegerDigits, _groupingSize);
1093:
1094:
1095:
1096: if (!useExponentialNotation) mainPattern.append(symbols.getDigit());
1097:
1098: for (int i = 1; i < totalDigits - minimumIntegerDigits; i++)
1099: mainPattern.append(symbols.getDigit());
1100:
1101: for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++)
1102: mainPattern.append(symbols.getZeroDigit());
1103:
1104: if (groupingUsed)
1105: {
1106: mainPattern.insert(mainPattern.length() - groupingSize,
1107: symbols.getGroupingSeparator());
1108: }
1109:
1110:
1111: if (minimumFractionDigits > 0 || maximumFractionDigits > 0 ||
1112: decimalSeparatorAlwaysShown)
1113: {
1114: mainPattern.append(symbols.getDecimalSeparator());
1115: }
1116:
1117: for (int i = 0; i < minimumFractionDigits; ++i)
1118: mainPattern.append(symbols.getZeroDigit());
1119:
1120: for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
1121: mainPattern.append(symbols.getDigit());
1122:
1123: if (useExponentialNotation)
1124: {
1125: mainPattern.append(symbols.getExponential());
1126:
1127: for (int i = 0; i < minExponentDigits; ++i)
1128: mainPattern.append(symbols.getZeroDigit());
1129:
1130: if (minExponentDigits == 0)
1131: mainPattern.append(symbols.getDigit());
1132: }
1133:
1134:
1135: String pattern = mainPattern.toString();
1136:
1137:
1138:
1139: String patternChars = patternChars(symbols);
1140: mainPattern.insert(0, quoteFix(positivePrefix, patternChars));
1141: mainPattern.append(quoteFix(positiveSuffix, patternChars));
1142:
1143: if (hasNegativePrefix)
1144: {
1145: mainPattern.append(symbols.getPatternSeparator());
1146: mainPattern.append(quoteFix(negativePrefix, patternChars));
1147: mainPattern.append(pattern);
1148: mainPattern.append(quoteFix(negativeSuffix, patternChars));
1149: }
1150:
1151:
1152: return mainPattern.toString();
1153: }
1154:
1155:
1156:
1157:
1164: private void applyPatternWithSymbols(String pattern,
1165: DecimalFormatSymbols symbols)
1166: {
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181: setDefaultValues();
1182:
1183: int len = pattern.length();
1184: if (len == 0)
1185: {
1186:
1187: this.minimumIntegerDigits = 1;
1188: this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
1189: this.minimumFractionDigits = 0;
1190: this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
1191:
1192:
1193: this.minExponentDigits = 0;
1194: this.showDecimalSeparator = true;
1195: this.groupingUsed = true;
1196: this.groupingSize = 3;
1197:
1198: return;
1199: }
1200:
1201: int start = scanFix(pattern, symbols, 0, true);
1202: if (start < len) start = scanNumberInteger(pattern, symbols, start);
1203: if (start < len)
1204: {
1205: start = scanFractionalPortion(pattern, symbols, start);
1206: }
1207: else
1208: {
1209:
1210:
1211: this.minimumFractionDigits = 0;
1212: this.maximumFractionDigits = 0;
1213:
1214:
1215: }
1216:
1217:
1218:
1219:
1220:
1221:
1222: if (start < len) start = scanExponent(pattern, symbols, start);
1223: if (start < len) start = scanFix(pattern, symbols, start, false);
1224: if (start < len) scanNegativePattern(pattern, symbols, start);
1225:
1226: if (useExponentialNotation &&
1227: (maxIntegerDigitsExponent > minimumIntegerDigits) &&
1228: (maxIntegerDigitsExponent > 1))
1229: {
1230: minimumIntegerDigits = 1;
1231: exponentRound = maxIntegerDigitsExponent;
1232: }
1233:
1234: if (useExponentialNotation)
1235: maximumIntegerDigits = maxIntegerDigitsExponent;
1236:
1237: if (!this.hasFractionalPattern && this.showDecimalSeparator == true)
1238: {
1239: this.decimalSeparatorAlwaysShown = true;
1240: }
1241: }
1242:
1243:
1250: private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols,
1251: int start, boolean prefix)
1252: {
1253: CPStringBuilder buffer = new CPStringBuilder();
1254:
1255:
1256:
1257: char decimalSeparator = sourceSymbols.getDecimalSeparator();
1258: char patternSeparator = sourceSymbols.getPatternSeparator();
1259: char groupingSeparator = sourceSymbols.getGroupingSeparator();
1260: char digit = sourceSymbols.getDigit();
1261: char zero = sourceSymbols.getZeroDigit();
1262: char minus = sourceSymbols.getMinusSign();
1263:
1264:
1265: char percent = sourceSymbols.getPercent();
1266: char permille = sourceSymbols.getPerMill();
1267:
1268: String currencySymbol = this.symbols.getCurrencySymbol();
1269:
1270: boolean quote = false;
1271:
1272: char ch = pattern.charAt(start);
1273: if (ch == patternSeparator)
1274: {
1275:
1276: this.hasNegativePrefix = true;
1277: ++start;
1278: return start;
1279: }
1280:
1281: int len = pattern.length();
1282: int i;
1283: for (i = start; i < len; i++)
1284: {
1285: ch = pattern.charAt(i);
1286:
1287:
1288: if (!quote && ch == patternSeparator)
1289: {
1290: if (this.hasNegativePrefix)
1291: {
1292: throw new IllegalArgumentException("Invalid pattern found: "
1293: + start);
1294: }
1295:
1296: this.hasNegativePrefix = true;
1297: ++i;
1298: break;
1299: }
1300:
1301:
1302: if (!quote &&
1303: (ch == minus || ch == digit || ch == zero ||
1304: ch == groupingSeparator))
1305: break;
1306:
1307: if (!quote && ch == decimalSeparator)
1308: {
1309: this.showDecimalSeparator = true;
1310: break;
1311: }
1312: else if (quote && ch != '\'')
1313: {
1314: buffer.append(ch);
1315: continue;
1316: }
1317:
1318: if (ch == '\u00A4')
1319: {
1320:
1321: currencySymbol = this.symbols.getCurrencySymbol();
1322:
1323:
1324: if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1325: {
1326: currencySymbol = this.symbols.getInternationalCurrencySymbol();
1327: i++;
1328: }
1329:
1330: this.useCurrencySeparator = true;
1331: buffer.append(currencySymbol);
1332: }
1333: else if (ch == percent)
1334: {
1335:
1336: this.multiplier = 100;
1337: buffer.append(this.symbols.getPercent());
1338: }
1339: else if (ch == permille)
1340: {
1341:
1342: this.multiplier = 1000;
1343: buffer.append(this.symbols.getPerMill());
1344: }
1345: else if (ch == '\'')
1346: {
1347:
1348: if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
1349: {
1350:
1351: buffer.append(ch);
1352: i++;
1353: }
1354: else
1355: {
1356: quote = !quote;
1357: continue;
1358: }
1359: }
1360: else
1361: {
1362: buffer.append(ch);
1363: }
1364: }
1365:
1366: if (prefix)
1367: {
1368: this.positivePrefix = buffer.toString();
1369: this.negativePrefix = minus + "" + positivePrefix;
1370: }
1371: else
1372: {
1373: this.positiveSuffix = buffer.toString();
1374: }
1375:
1376: return i;
1377: }
1378:
1379:
1389: private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols,
1390: int start)
1391: {
1392: char digit = symbols.getDigit();
1393: char zero = symbols.getZeroDigit();
1394: char groupingSeparator = symbols.getGroupingSeparator();
1395: char decimalSeparator = symbols.getDecimalSeparator();
1396: char exponent = symbols.getExponential();
1397: char patternSeparator = symbols.getPatternSeparator();
1398:
1399:
1400:
1401: int zeros = 0;
1402:
1403:
1404: int _groupingSize = 0;
1405:
1406: this.maxIntegerDigitsExponent = 0;
1407:
1408: boolean intPartTouched = false;
1409:
1410: char ch;
1411: int len = pattern.length();
1412: int i;
1413: for (i = start; i < len; i++)
1414: {
1415: ch = pattern.charAt(i);
1416:
1417:
1418: if (ch == decimalSeparator || ch == exponent)
1419: break;
1420:
1421: if (this.hasNegativePrefix && ch == patternSeparator)
1422: throw new IllegalArgumentException("Invalid pattern found: "
1423: + start);
1424:
1425: if (ch == digit)
1426: {
1427:
1428:
1429:
1430: if (zeros > 0) throw new
1431: IllegalArgumentException("digit mark following zero in " +
1432: "positive subpattern, not allowed. Position: " + i);
1433:
1434: _groupingSize++;
1435: intPartTouched = true;
1436: this.maxIntegerDigitsExponent++;
1437: }
1438: else if (ch == zero)
1439: {
1440: zeros++;
1441: _groupingSize++;
1442: this.maxIntegerDigitsExponent++;
1443: }
1444: else if (ch == groupingSeparator)
1445: {
1446: this.groupingSeparatorInPattern = true;
1447: this.groupingUsed = true;
1448: _groupingSize = 0;
1449: }
1450: else
1451: {
1452:
1453:
1454: break;
1455: }
1456: }
1457:
1458: if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize;
1459: this.minimumIntegerDigits = zeros;
1460:
1461:
1462:
1463: if (intPartTouched && this.maximumIntegerDigits > 0 &&
1464: this.minimumIntegerDigits == 0)
1465: this.minimumIntegerDigits = 1;
1466:
1467: return i;
1468: }
1469:
1470:
1480: private int scanFractionalPortion(String pattern,
1481: DecimalFormatSymbols symbols,
1482: int start)
1483: {
1484: char digit = symbols.getDigit();
1485: char zero = symbols.getZeroDigit();
1486: char groupingSeparator = symbols.getGroupingSeparator();
1487: char decimalSeparator = symbols.getDecimalSeparator();
1488: char exponent = symbols.getExponential();
1489: char patternSeparator = symbols.getPatternSeparator();
1490:
1491:
1492:
1493: char ch = pattern.charAt(start);
1494: if (ch != decimalSeparator)
1495: {
1496: this.minimumFractionDigits = 0;
1497: this.maximumFractionDigits = 0;
1498: return start;
1499: }
1500:
1501: ++start;
1502:
1503: this.hasFractionalPattern = true;
1504:
1505: this.minimumFractionDigits = 0;
1506: int digits = 0;
1507:
1508: int len = pattern.length();
1509: int i;
1510: for (i = start; i < len; i++)
1511: {
1512: ch = pattern.charAt(i);
1513:
1514:
1515: if (ch == exponent || ch == patternSeparator)
1516: break;
1517:
1518:
1519: if (ch == groupingSeparator || ch == decimalSeparator) throw new
1520: IllegalArgumentException("unexpected character '" + ch + "' " +
1521: "in fractional subpattern. Position: " + i);
1522:
1523: if (ch == digit)
1524: {
1525: digits++;
1526: }
1527: else if (ch == zero)
1528: {
1529: if (digits > 0) throw new
1530: IllegalArgumentException("digit mark following zero in " +
1531: "positive subpattern, not allowed. Position: " + i);
1532:
1533: this.minimumFractionDigits++;
1534: }
1535: else
1536: {
1537:
1538: break;
1539: }
1540: }
1541:
1542: if (i == start) this.hasFractionalPattern = false;
1543:
1544: this.maximumFractionDigits = this.minimumFractionDigits + digits;
1545: this.showDecimalSeparator = true;
1546:
1547: return i;
1548: }
1549:
1550:
1560: private int scanExponent(String pattern, DecimalFormatSymbols symbols,
1561: int start)
1562: {
1563: char digit = symbols.getDigit();
1564: char zero = symbols.getZeroDigit();
1565: char groupingSeparator = symbols.getGroupingSeparator();
1566: char decimalSeparator = symbols.getDecimalSeparator();
1567: char exponent = symbols.getExponential();
1568:
1569: char ch = pattern.charAt(start);
1570:
1571: if (ch == decimalSeparator)
1572: {
1573:
1574: ++start;
1575: }
1576:
1577: if (ch != exponent)
1578: {
1579: this.useExponentialNotation = false;
1580: return start;
1581: }
1582:
1583: ++start;
1584:
1585: this.minExponentDigits = 0;
1586:
1587: int len = pattern.length();
1588: int i;
1589: for (i = start; i < len; i++)
1590: {
1591: ch = pattern.charAt(i);
1592:
1593: if (ch == groupingSeparator || ch == decimalSeparator ||
1594: ch == digit || ch == exponent) throw new
1595: IllegalArgumentException("unexpected character '" + ch + "' " +
1596: "in exponential subpattern. Position: " + i);
1597:
1598: if (ch == zero)
1599: {
1600: this.minExponentDigits++;
1601: }
1602: else
1603: {
1604:
1605: break;
1606: }
1607: }
1608:
1609: this.useExponentialNotation = true;
1610:
1611: return i;
1612: }
1613:
1614:
1623: private void scanNegativePattern(String pattern,
1624: DecimalFormatSymbols sourceSymbols,
1625: int start)
1626: {
1627: StringBuilder buffer = new StringBuilder();
1628:
1629:
1630:
1631: char decimalSeparator = sourceSymbols.getDecimalSeparator();
1632: char patternSeparator = sourceSymbols.getPatternSeparator();
1633: char groupingSeparator = sourceSymbols.getGroupingSeparator();
1634: char digit = sourceSymbols.getDigit();
1635: char zero = sourceSymbols.getZeroDigit();
1636: char minus = sourceSymbols.getMinusSign();
1637:
1638:
1639: char percent = sourceSymbols.getPercent();
1640: char permille = sourceSymbols.getPerMill();
1641:
1642: String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol();
1643: String currencySymbol = CURRENCY_SYMBOL;
1644:
1645: boolean quote = false;
1646: boolean prefixDone = false;
1647:
1648: int len = pattern.length();
1649: if (len > 0) this.hasNegativePrefix = true;
1650:
1651: char ch = pattern.charAt(start);
1652: if (ch == patternSeparator)
1653: {
1654:
1655: if ((start + 1) > len) throw new
1656: IllegalArgumentException("unexpected character '" + ch + "' " +
1657: "in negative subpattern.");
1658: start++;
1659: }
1660:
1661: int i;
1662: for (i = start; i < len; i++)
1663: {
1664: ch = pattern.charAt(i);
1665:
1666:
1667: if (!quote &&
1668: (ch == digit || ch == zero || ch == decimalSeparator ||
1669: ch == patternSeparator || ch == groupingSeparator))
1670: {
1671: if (!prefixDone)
1672: {
1673: this.negativePrefix = buffer.toString();
1674: buffer.delete(0, buffer.length());
1675: prefixDone = true;
1676: }
1677: }
1678: else if (ch == minus)
1679: {
1680: buffer.append(this.symbols.getMinusSign());
1681: }
1682: else if (quote && ch != '\'')
1683: {
1684: buffer.append(ch);
1685: }
1686: else if (ch == '\u00A4')
1687: {
1688:
1689: currencySymbol = CURRENCY_SYMBOL;
1690:
1691:
1692: if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1693: {
1694: currencySymbol = this.symbols.getInternationalCurrencySymbol();
1695: i = i + 2;
1696: }
1697:
1698:
1699:
1700:
1701:
1702:
1703: buffer.append(currencySymbol);
1704: }
1705: else if (ch == percent)
1706: {
1707:
1708: this.negativePatternMultiplier = 100;
1709: buffer.append(this.symbols.getPercent());
1710: }
1711: else if (ch == permille)
1712: {
1713:
1714: this.negativePatternMultiplier = 1000;
1715: buffer.append(this.symbols.getPerMill());
1716: }
1717: else if (ch == '\'')
1718: {
1719:
1720: if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
1721: {
1722:
1723: buffer.append(ch);
1724: i++;
1725: }
1726: else
1727: {
1728: quote = !quote;
1729: }
1730: }
1731: else if (ch == patternSeparator)
1732: {
1733:
1734: throw new IllegalArgumentException("unexpected character '" + ch +
1735: "' in negative subpattern.");
1736: }
1737: else
1738: {
1739: buffer.append(ch);
1740: }
1741: }
1742:
1743: if (prefixDone)
1744: this.negativeSuffix = buffer.toString();
1745: else
1746: this.negativePrefix = buffer.toString();
1747: }
1748:
1749:
1750:
1751:
1767: private void formatInternal(BigDecimal number, boolean isLong,
1768: StringBuffer dest, FieldPosition fieldPos)
1769: {
1770:
1771:
1772:
1773:
1774:
1775:
1776:
1777: if (fieldPos == null) fieldPos = new FieldPosition(0);
1778:
1779: int _multiplier = this.multiplier;
1780:
1781:
1782: int attributeStart = -1;
1783:
1784:
1785:
1786: boolean isNegative = (number.signum() < 0) ? true : false;
1787: if (isNegative)
1788: {
1789: attributeStart = dest.length();
1790:
1791:
1792: dest.append(negativePrefix);
1793:
1794:
1795:
1796: number = number.abs();
1797:
1798: _multiplier = negativePatternMultiplier;
1799:
1800: addAttribute(Field.SIGN, attributeStart, dest.length());
1801: }
1802: else
1803: {
1804:
1805: dest.append(positivePrefix);
1806: }
1807:
1808:
1809: int beginIndexInt = dest.length();
1810: int endIndexInt = 0;
1811: int beginIndexFract = 0;
1812: int endIndexFract = 0;
1813:
1814:
1815: number = number.multiply(BigDecimal.valueOf(_multiplier));
1816:
1817:
1818:
1819:
1820: if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0)
1821: {
1822: number = BigDecimal.ZERO;
1823: this.maximumIntegerDigits = 1;
1824: this.minimumIntegerDigits = 1;
1825: }
1826:
1827:
1828: number = number.abs();
1829:
1830:
1831: int scale = this.maximumFractionDigits;
1832:
1833:
1834:
1835:
1836: long exponent = 0;
1837:
1838:
1839: if (this.useExponentialNotation)
1840: {
1841: exponent = getExponent(number);
1842: number = number.movePointLeft((int) exponent);
1843:
1844:
1845:
1846:
1847:
1848:
1849: }
1850:
1851:
1852: number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
1853:
1854:
1855:
1856: String plain = number.toPlainString();
1857:
1858: String intPart = null;
1859: String fractPart = null;
1860:
1861:
1862:
1863:
1864: int minusIndex = plain.lastIndexOf('-', 0);
1865: if (minusIndex > -1) plain = plain.substring(minusIndex + 1);
1866:
1867:
1868: int dot = plain.indexOf('.');
1869: if (dot > -1)
1870: {
1871: intPart = plain.substring(0, dot);
1872: dot++;
1873:
1874: if (useExponentialNotation)
1875: fractPart = plain.substring(dot, dot + scale);
1876: else
1877: fractPart = plain.substring(dot);
1878: }
1879: else
1880: {
1881: intPart = plain;
1882: }
1883:
1884:
1885: int intPartLen = intPart.length();
1886: endIndexInt = intPartLen;
1887:
1888:
1889:
1890:
1891: int zeroes = minimumIntegerDigits - intPartLen;
1892: if (zeroes > 0)
1893: {
1894: attributeStart = Math.max(dest.length() - 1, 0);
1895: appendZero(dest, zeroes, minimumIntegerDigits);
1896: }
1897:
1898: if (this.useExponentialNotation)
1899: {
1900:
1901:
1902:
1903:
1904:
1905: if (attributeStart < 0)
1906: attributeStart = Math.max(dest.length() - 1, 0);
1907: appendDigit(intPart, dest, this.groupingUsed);
1908: }
1909: else
1910: {
1911:
1912: intPartLen = intPart.length();
1913: int canary = Math.min(intPartLen, this.maximumIntegerDigits);
1914:
1915:
1916:
1917: intPart = intPart.substring(intPartLen - canary);
1918: endIndexInt = intPart.length() + 1;
1919:
1920:
1921: if (maximumIntegerDigits > 0 &&
1922: !(this.minimumIntegerDigits == 0 &&
1923: intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0))
1924: {
1925: if (attributeStart < 0)
1926: attributeStart = Math.max(dest.length() - 1, 0);
1927: appendDigit(intPart, dest, this.groupingUsed);
1928: }
1929: }
1930:
1931:
1932: addAttribute(Field.INTEGER, attributeStart, dest.length());
1933:
1934:
1935: if ((fieldPos.getField() == INTEGER_FIELD ||
1936: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
1937: {
1938: fieldPos.setBeginIndex(beginIndexInt);
1939: fieldPos.setEndIndex(endIndexInt);
1940: }
1941:
1942: handleFractionalPart(dest, fractPart, fieldPos, isLong);
1943:
1944:
1945: if (this.useExponentialNotation)
1946: {
1947: attributeStart = dest.length();
1948:
1949: dest.append(symbols.getExponential());
1950:
1951: addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
1952: attributeStart = dest.length();
1953:
1954: if (exponent < 0)
1955: {
1956: dest.append(symbols.getMinusSign());
1957: exponent = -exponent;
1958:
1959: addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
1960: }
1961:
1962: attributeStart = dest.length();
1963:
1964: String exponentString = String.valueOf(exponent);
1965: int exponentLength = exponentString.length();
1966:
1967: for (int i = 0; i < minExponentDigits - exponentLength; i++)
1968: dest.append(symbols.getZeroDigit());
1969:
1970: for (int i = 0; i < exponentLength; ++i)
1971: dest.append(exponentString.charAt(i));
1972:
1973: addAttribute(Field.EXPONENT, attributeStart, dest.length());
1974: }
1975:
1976:
1977: if (isNegative)
1978: {
1979: dest.append(negativeSuffix);
1980: }
1981: else
1982: {
1983: dest.append(positiveSuffix);
1984: }
1985: }
1986:
1987:
1996: private void handleFractionalPart(StringBuffer dest, String fractPart,
1997: FieldPosition fieldPos, boolean isLong)
1998: {
1999: int dotStart = 0;
2000: int dotEnd = 0;
2001: boolean addDecimal = false;
2002:
2003: if (this.decimalSeparatorAlwaysShown ||
2004: ((!isLong || this.useExponentialNotation) &&
2005: this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
2006: this.minimumFractionDigits > 0)
2007: {
2008: dotStart = dest.length();
2009:
2010: if (this.useCurrencySeparator)
2011: dest.append(symbols.getMonetaryDecimalSeparator());
2012: else
2013: dest.append(symbols.getDecimalSeparator());
2014:
2015: dotEnd = dest.length();
2016: addDecimal = true;
2017: }
2018:
2019:
2020: int fractStart = 0;
2021: int fractEnd = 0;
2022: boolean addFractional = false;
2023:
2024: if ((!isLong || this.useExponentialNotation)
2025: && this.maximumFractionDigits > 0
2026: || this.minimumFractionDigits > 0)
2027: {
2028: fractStart = dest.length();
2029: fractEnd = fractStart;
2030:
2031: int digits = this.minimumFractionDigits;
2032:
2033: if (this.useExponentialNotation)
2034: {
2035: digits = (this.minimumIntegerDigits + this.minimumFractionDigits)
2036: - dest.length();
2037: if (digits < 0) digits = 0;
2038: }
2039:
2040: fractPart = adjustTrailingZeros(fractPart, digits);
2041:
2042:
2043:
2044:
2045: boolean allZeros = true;
2046: char fracts[] = fractPart.toCharArray();
2047: for (int i = 0; i < fracts.length; i++)
2048: {
2049: if (fracts[i] != '0')
2050: allZeros = false;
2051: }
2052:
2053: if (!allZeros || (minimumFractionDigits > 0))
2054: {
2055: appendDigit(fractPart, dest, false);
2056: fractEnd = dest.length();
2057:
2058: addDecimal = true;
2059: addFractional = true;
2060: }
2061: else if (!this.decimalSeparatorAlwaysShown)
2062: {
2063: dest.deleteCharAt(dest.length() - 1);
2064: addDecimal = false;
2065: }
2066: else
2067: {
2068: fractEnd = dest.length();
2069: addFractional = true;
2070: }
2071: }
2072:
2073: if (addDecimal)
2074: addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
2075:
2076: if (addFractional)
2077: addAttribute(Field.FRACTION, fractStart, fractEnd);
2078:
2079: if ((fieldPos.getField() == FRACTION_FIELD ||
2080: fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
2081: {
2082: fieldPos.setBeginIndex(fractStart);
2083: fieldPos.setEndIndex(fractEnd);
2084: }
2085: }
2086:
2087:
2093: private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount)
2094: {
2095: char ch = symbols.getZeroDigit();
2096: char gSeparator = symbols.getGroupingSeparator();
2097:
2098: int i = 0;
2099: int gPos = totalDigitCount;
2100: for (i = 0; i < zeroes; i++, gPos--)
2101: {
2102: if (this.groupingSeparatorInPattern &&
2103: (this.groupingUsed && this.groupingSize != 0) &&
2104: (gPos % groupingSize == 0 && i > 0))
2105: dest.append(gSeparator);
2106:
2107: dest.append(ch);
2108: }
2109:
2110:
2111: if (this.groupingSeparatorInPattern &&
2112: (this.groupingUsed && this.groupingSize != 0) &&
2113: (gPos % groupingSize == 0))
2114: dest.append(gSeparator);
2115: }
2116:
2117:
2123: private void appendDigit(String src, StringBuffer dest,
2124: boolean groupingUsed)
2125: {
2126: int zero = symbols.getZeroDigit() - '0';
2127:
2128: int ch;
2129: char gSeparator = symbols.getGroupingSeparator();
2130:
2131: int len = src.length();
2132: for (int i = 0, gPos = len; i < len; i++, gPos--)
2133: {
2134: ch = src.charAt(i);
2135: if (groupingUsed && this.groupingSize != 0 &&
2136: gPos % groupingSize == 0 && i > 0)
2137: dest.append(gSeparator);
2138:
2139: dest.append((char) (zero + ch));
2140: }
2141: }
2142:
2143:
2149: private long getExponent(BigDecimal number)
2150: {
2151: long exponent = 0;
2152:
2153: if (number.signum() > 0)
2154: {
2155: double _number = number.doubleValue();
2156: exponent = (long) Math.floor (Math.log10(_number));
2157:
2158:
2159: exponent = exponent - (exponent % this.exponentRound);
2160:
2161:
2162:
2163:
2164:
2165:
2166:
2167:
2168: if (minimumIntegerDigits > 0)
2169: exponent -= minimumIntegerDigits - 1;
2170: }
2171:
2172: return exponent;
2173: }
2174:
2175:
2187: private String adjustTrailingZeros(String src, int minimumDigits)
2188: {
2189: int len = src.length();
2190: String result;
2191:
2192:
2193: if (len > minimumDigits)
2194: {
2195: int zeros = 0;
2196: for (int i = len - 1; i > minimumDigits; i--)
2197: {
2198: if (src.charAt(i) == '0')
2199: ++zeros;
2200: else
2201: break;
2202: }
2203: result = src.substring(0, len - zeros);
2204: }
2205: else
2206: {
2207: char zero = symbols.getZeroDigit();
2208: CPStringBuilder _result = new CPStringBuilder(src);
2209: for (int i = len; i < minimumDigits; i++)
2210: {
2211: _result.append(zero);
2212: }
2213: result = _result.toString();
2214: }
2215:
2216: return result;
2217: }
2218:
2219:
2226: private void addAttribute(Field field, int begin, int end)
2227: {
2228:
2232:
2233: FieldPosition pos = new FieldPosition(field);
2234: pos.setBeginIndex(begin);
2235: pos.setEndIndex(end);
2236: attributes.add(pos);
2237: }
2238:
2239:
2242: private void setDefaultValues()
2243: {
2244:
2245:
2246:
2247:
2248:
2249: this.negativePrefix = String.valueOf(symbols.getMinusSign());
2250: this.negativeSuffix = "";
2251: this.positivePrefix = "";
2252: this.positiveSuffix = "";
2253:
2254: this.multiplier = 1;
2255: this.negativePatternMultiplier = 1;
2256: this.exponentRound = 1;
2257:
2258: this.hasNegativePrefix = false;
2259:
2260: this.minimumIntegerDigits = 1;
2261: this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
2262: this.minimumFractionDigits = 0;
2263: this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
2264: this.minExponentDigits = 0;
2265:
2266: this.groupingSize = 0;
2267:
2268: this.decimalSeparatorAlwaysShown = false;
2269: this.showDecimalSeparator = false;
2270: this.useExponentialNotation = false;
2271: this.groupingUsed = false;
2272: this.groupingSeparatorInPattern = false;
2273:
2274: this.useCurrencySeparator = false;
2275:
2276: this.hasFractionalPattern = false;
2277: }
2278: }