1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.icu; 18 19 import java.math.BigDecimal; 20 import java.math.BigInteger; 21 import java.math.RoundingMode; 22 import java.text.AttributedCharacterIterator; 23 import java.text.AttributedString; 24 import java.text.DecimalFormatSymbols; 25 import java.text.FieldPosition; 26 import java.text.Format; 27 import java.text.NumberFormat; 28 import java.text.ParsePosition; 29 import java.util.Currency; 30 31 public final class NativeDecimalFormat implements Cloneable { 32 /** 33 * Constants corresponding to the native type UNumberFormatSymbol, for setSymbol. 34 */ 35 private static final int UNUM_DECIMAL_SEPARATOR_SYMBOL = 0; 36 private static final int UNUM_GROUPING_SEPARATOR_SYMBOL = 1; 37 private static final int UNUM_PATTERN_SEPARATOR_SYMBOL = 2; 38 private static final int UNUM_PERCENT_SYMBOL = 3; 39 private static final int UNUM_ZERO_DIGIT_SYMBOL = 4; 40 private static final int UNUM_DIGIT_SYMBOL = 5; 41 private static final int UNUM_MINUS_SIGN_SYMBOL = 6; 42 private static final int UNUM_PLUS_SIGN_SYMBOL = 7; 43 private static final int UNUM_CURRENCY_SYMBOL = 8; 44 private static final int UNUM_INTL_CURRENCY_SYMBOL = 9; 45 private static final int UNUM_MONETARY_SEPARATOR_SYMBOL = 10; 46 private static final int UNUM_EXPONENTIAL_SYMBOL = 11; 47 private static final int UNUM_PERMILL_SYMBOL = 12; 48 private static final int UNUM_PAD_ESCAPE_SYMBOL = 13; 49 private static final int UNUM_INFINITY_SYMBOL = 14; 50 private static final int UNUM_NAN_SYMBOL = 15; 51 private static final int UNUM_SIGNIFICANT_DIGIT_SYMBOL = 16; 52 private static final int UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL = 17; 53 private static final int UNUM_FORMAT_SYMBOL_COUNT = 18; 54 55 /** 56 * Constants corresponding to the native type UNumberFormatAttribute, for 57 * getAttribute/setAttribute. 58 */ 59 private static final int UNUM_PARSE_INT_ONLY = 0; 60 private static final int UNUM_GROUPING_USED = 1; 61 private static final int UNUM_DECIMAL_ALWAYS_SHOWN = 2; 62 private static final int UNUM_MAX_INTEGER_DIGITS = 3; 63 private static final int UNUM_MIN_INTEGER_DIGITS = 4; 64 private static final int UNUM_INTEGER_DIGITS = 5; 65 private static final int UNUM_MAX_FRACTION_DIGITS = 6; 66 private static final int UNUM_MIN_FRACTION_DIGITS = 7; 67 private static final int UNUM_FRACTION_DIGITS = 8; 68 private static final int UNUM_MULTIPLIER = 9; 69 private static final int UNUM_GROUPING_SIZE = 10; 70 private static final int UNUM_ROUNDING_MODE = 11; 71 private static final int UNUM_ROUNDING_INCREMENT = 12; 72 private static final int UNUM_FORMAT_WIDTH = 13; 73 private static final int UNUM_PADDING_POSITION = 14; 74 private static final int UNUM_SECONDARY_GROUPING_SIZE = 15; 75 private static final int UNUM_SIGNIFICANT_DIGITS_USED = 16; 76 private static final int UNUM_MIN_SIGNIFICANT_DIGITS = 17; 77 private static final int UNUM_MAX_SIGNIFICANT_DIGITS = 18; 78 private static final int UNUM_LENIENT_PARSE = 19; 79 80 /** 81 * Constants corresponding to the native type UNumberFormatTextAttribute, for 82 * getTextAttribute/setTextAttribute. 83 */ 84 private static final int UNUM_POSITIVE_PREFIX = 0; 85 private static final int UNUM_POSITIVE_SUFFIX = 1; 86 private static final int UNUM_NEGATIVE_PREFIX = 2; 87 private static final int UNUM_NEGATIVE_SUFFIX = 3; 88 private static final int UNUM_PADDING_CHARACTER = 4; 89 private static final int UNUM_CURRENCY_CODE = 5; 90 private static final int UNUM_DEFAULT_RULESET = 6; 91 private static final int UNUM_PUBLIC_RULESETS = 7; 92 93 /** 94 * A table for translating between NumberFormat.Field instances 95 * and icu4c UNUM_x_FIELD constants. 96 */ 97 private static final Format.Field[] ICU4C_FIELD_IDS = { 98 // The old java field values were 0 for integer and 1 for fraction. 99 // The new java field attributes are all objects. ICU assigns the values 100 // starting from 0 in the following order; note that integer and 101 // fraction positions match the old field values. 102 NumberFormat.Field.INTEGER, // 0 UNUM_INTEGER_FIELD 103 NumberFormat.Field.FRACTION, // 1 UNUM_FRACTION_FIELD 104 NumberFormat.Field.DECIMAL_SEPARATOR, // 2 UNUM_DECIMAL_SEPARATOR_FIELD 105 NumberFormat.Field.EXPONENT_SYMBOL, // 3 UNUM_EXPONENT_SYMBOL_FIELD 106 NumberFormat.Field.EXPONENT_SIGN, // 4 UNUM_EXPONENT_SIGN_FIELD 107 NumberFormat.Field.EXPONENT, // 5 UNUM_EXPONENT_FIELD 108 NumberFormat.Field.GROUPING_SEPARATOR, // 6 UNUM_GROUPING_SEPARATOR_FIELD 109 NumberFormat.Field.CURRENCY, // 7 UNUM_CURRENCY_FIELD 110 NumberFormat.Field.PERCENT, // 8 UNUM_PERCENT_FIELD 111 NumberFormat.Field.PERMILLE, // 9 UNUM_PERMILL_FIELD 112 NumberFormat.Field.SIGN, // 10 UNUM_SIGN_FIELD 113 }; 114 115 private static int translateFieldId(FieldPosition fp) { 116 int id = fp.getField(); 117 if (id < -1 || id > 1) { 118 id = -1; 119 } 120 if (id == -1) { 121 Format.Field attr = fp.getFieldAttribute(); 122 if (attr != null) { 123 for (int i = 0; i < ICU4C_FIELD_IDS.length; ++i) { 124 if (ICU4C_FIELD_IDS[i].equals(attr)) { 125 id = i; 126 break; 127 } 128 } 129 } 130 } 131 return id; 132 } 133 134 /** 135 * The address of the ICU DecimalFormat* on the native heap. 136 */ 137 private long address; 138 139 /** 140 * The last pattern we gave to ICU, so we can make repeated applications cheap. 141 * This helps in cases like String.format("%.2f,%.2f\n", x, y) where the DecimalFormat is 142 * reused. 143 */ 144 private String lastPattern; 145 146 // TODO: store all these in DecimalFormat instead! 147 private boolean negPrefNull; 148 private boolean negSuffNull; 149 private boolean posPrefNull; 150 private boolean posSuffNull; 151 152 private transient boolean parseBigDecimal; 153 154 public NativeDecimalFormat(String pattern, DecimalFormatSymbols dfs) { 155 try { 156 this.address = open(pattern, dfs.getCurrencySymbol(), 157 dfs.getDecimalSeparator(), dfs.getDigit(), dfs.getExponentSeparator(), 158 dfs.getGroupingSeparator(), dfs.getInfinity(), 159 dfs.getInternationalCurrencySymbol(), dfs.getMinusSignString(), 160 dfs.getMonetaryDecimalSeparator(), dfs.getNaN(), dfs.getPatternSeparator(), 161 dfs.getPercent(), dfs.getPerMill(), dfs.getZeroDigit()); 162 this.lastPattern = pattern; 163 } catch (NullPointerException npe) { 164 throw npe; 165 } catch (RuntimeException re) { 166 throw new IllegalArgumentException("syntax error: " + re.getMessage() + ": " + pattern); 167 } 168 } 169 170 // Used so java.util.Formatter doesn't need to allocate DecimalFormatSymbols instances. 171 public NativeDecimalFormat(String pattern, LocaleData data) { 172 this.address = open(pattern, data.currencySymbol, 173 data.decimalSeparator, '#', data.exponentSeparator, data.groupingSeparator, 174 data.infinity, data.internationalCurrencySymbol, data.minusSign, 175 data.monetarySeparator, data.NaN, data.patternSeparator, 176 data.percent, data.perMill, data.zeroDigit); 177 this.lastPattern = pattern; 178 } 179 180 public synchronized void close() { 181 if (address != 0) { 182 close(address); 183 address = 0; 184 } 185 } 186 187 @Override protected void finalize() throws Throwable { 188 try { 189 close(); 190 } finally { 191 super.finalize(); 192 } 193 } 194 195 @Override public Object clone() { 196 try { 197 NativeDecimalFormat clone = (NativeDecimalFormat) super.clone(); 198 clone.address = cloneImpl(address); 199 clone.lastPattern = lastPattern; 200 clone.negPrefNull = negPrefNull; 201 clone.negSuffNull = negSuffNull; 202 clone.posPrefNull = posPrefNull; 203 clone.posSuffNull = posSuffNull; 204 return clone; 205 } catch (CloneNotSupportedException unexpected) { 206 throw new AssertionError(unexpected); 207 } 208 } 209 210 /** 211 * Note: this doesn't check that the underlying native DecimalFormat objects' configured 212 * native DecimalFormatSymbols objects are equal. It is assumed that the 213 * caller (DecimalFormat) will check the DecimalFormatSymbols objects 214 * instead, for performance. 215 * 216 * This is also unreasonably expensive, calling down to JNI multiple times. 217 * 218 * TODO: remove this and just have DecimalFormat.equals do the right thing itself. 219 */ 220 @Override 221 public boolean equals(Object object) { 222 if (object == this) { 223 return true; 224 } 225 if (!(object instanceof NativeDecimalFormat)) { 226 return false; 227 } 228 NativeDecimalFormat obj = (NativeDecimalFormat) object; 229 if (obj.address == this.address) { 230 return true; 231 } 232 return obj.toPattern().equals(this.toPattern()) && 233 obj.isDecimalSeparatorAlwaysShown() == this.isDecimalSeparatorAlwaysShown() && 234 obj.getGroupingSize() == this.getGroupingSize() && 235 obj.getMultiplier() == this.getMultiplier() && 236 obj.getNegativePrefix().equals(this.getNegativePrefix()) && 237 obj.getNegativeSuffix().equals(this.getNegativeSuffix()) && 238 obj.getPositivePrefix().equals(this.getPositivePrefix()) && 239 obj.getPositiveSuffix().equals(this.getPositiveSuffix()) && 240 obj.getMaximumIntegerDigits() == this.getMaximumIntegerDigits() && 241 obj.getMaximumFractionDigits() == this.getMaximumFractionDigits() && 242 obj.getMinimumIntegerDigits() == this.getMinimumIntegerDigits() && 243 obj.getMinimumFractionDigits() == this.getMinimumFractionDigits() && 244 obj.isGroupingUsed() == this.isGroupingUsed(); 245 } 246 247 public String toString() { 248 return getClass().getName() + "[\"" + toPattern() + "\"" + 249 ",isDecimalSeparatorAlwaysShown=" + isDecimalSeparatorAlwaysShown() + 250 ",groupingSize=" + getGroupingSize() + 251 ",multiplier=" + getMultiplier() + 252 ",negativePrefix=" + getNegativePrefix() + 253 ",negativeSuffix=" + getNegativeSuffix() + 254 ",positivePrefix=" + getPositivePrefix() + 255 ",positiveSuffix=" + getPositiveSuffix() + 256 ",maxIntegerDigits=" + getMaximumIntegerDigits() + 257 ",maxFractionDigits=" + getMaximumFractionDigits() + 258 ",minIntegerDigits=" + getMinimumIntegerDigits() + 259 ",minFractionDigits=" + getMinimumFractionDigits() + 260 ",grouping=" + isGroupingUsed() + 261 "]"; 262 } 263 264 /** 265 * Copies the DecimalFormatSymbols settings into our native peer in bulk. 266 */ 267 public void setDecimalFormatSymbols(final DecimalFormatSymbols dfs) { 268 setDecimalFormatSymbols(this.address, dfs.getCurrencySymbol(), dfs.getDecimalSeparator(), 269 dfs.getDigit(), dfs.getExponentSeparator(), dfs.getGroupingSeparator(), 270 dfs.getInfinity(), dfs.getInternationalCurrencySymbol(), dfs.getMinusSignString(), 271 dfs.getMonetaryDecimalSeparator(), dfs.getNaN(), dfs.getPatternSeparator(), 272 dfs.getPercent(), dfs.getPerMill(), dfs.getZeroDigit()); 273 } 274 275 public void setDecimalFormatSymbols(final LocaleData localeData) { 276 setDecimalFormatSymbols(this.address, localeData.currencySymbol, localeData.decimalSeparator, 277 '#', localeData.exponentSeparator, localeData.groupingSeparator, 278 localeData.infinity, localeData.internationalCurrencySymbol, localeData.minusSign, 279 localeData.monetarySeparator, localeData.NaN, localeData.patternSeparator, 280 localeData.percent, localeData.perMill, localeData.zeroDigit); 281 } 282 283 public char[] formatBigDecimal(BigDecimal value, FieldPosition field) { 284 FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); 285 char[] result = formatDigitList(this.address, value.toString(), fpi); 286 if (fpi != null && field != null) { 287 updateFieldPosition(field, fpi); 288 } 289 return result; 290 } 291 292 public char[] formatBigInteger(BigInteger value, FieldPosition field) { 293 FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); 294 char[] result = formatDigitList(this.address, value.toString(10), fpi); 295 if (fpi != null && field != null) { 296 updateFieldPosition(field, fpi); 297 } 298 return result; 299 } 300 301 public char[] formatLong(long value, FieldPosition field) { 302 FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); 303 char[] result = formatLong(this.address, value, fpi); 304 if (fpi != null && field != null) { 305 updateFieldPosition(field, fpi); 306 } 307 return result; 308 } 309 310 public char[] formatDouble(double value, FieldPosition field) { 311 FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); 312 char[] result = formatDouble(this.address, value, fpi); 313 if (fpi != null && field != null) { 314 updateFieldPosition(field, fpi); 315 } 316 return result; 317 } 318 319 private static void updateFieldPosition(FieldPosition fp, FieldPositionIterator fpi) { 320 int field = translateFieldId(fp); 321 if (field != -1) { 322 while (fpi.next()) { 323 if (fpi.fieldId() == field) { 324 fp.setBeginIndex(fpi.start()); 325 fp.setEndIndex(fpi.limit()); 326 return; 327 } 328 } 329 } 330 } 331 332 public void applyLocalizedPattern(String pattern) { 333 applyPattern(this.address, true, pattern); 334 lastPattern = null; 335 } 336 337 public void applyPattern(String pattern) { 338 if (lastPattern != null && pattern.equals(lastPattern)) { 339 return; 340 } 341 applyPattern(this.address, false, pattern); 342 lastPattern = pattern; 343 } 344 345 public AttributedCharacterIterator formatToCharacterIterator(Object object) { 346 if (object == null) { 347 throw new NullPointerException("object == null"); 348 } 349 if (!(object instanceof Number)) { 350 throw new IllegalArgumentException("object not a Number: " + object.getClass()); 351 } 352 Number number = (Number) object; 353 FieldPositionIterator fpIter = new FieldPositionIterator(); 354 String text; 355 if (number instanceof BigInteger || number instanceof BigDecimal) { 356 text = new String(formatDigitList(this.address, number.toString(), fpIter)); 357 } else if (number instanceof Double || number instanceof Float) { 358 double dv = number.doubleValue(); 359 text = new String(formatDouble(this.address, dv, fpIter)); 360 } else { 361 long lv = number.longValue(); 362 text = new String(formatLong(this.address, lv, fpIter)); 363 } 364 365 AttributedString as = new AttributedString(text); 366 367 while (fpIter.next()) { 368 Format.Field field = fpIter.field(); 369 as.addAttribute(field, field, fpIter.start(), fpIter.limit()); 370 } 371 372 // return the CharacterIterator from AttributedString 373 return as.getIterator(); 374 } 375 376 private int makeScalePositive(int scale, StringBuilder val) { 377 if (scale < 0) { 378 scale = -scale; 379 for (int i = scale; i > 0; i--) { 380 val.append('0'); 381 } 382 scale = 0; 383 } 384 return scale; 385 } 386 387 public String toLocalizedPattern() { 388 return toPatternImpl(this.address, true); 389 } 390 391 public String toPattern() { 392 return toPatternImpl(this.address, false); 393 } 394 395 public Number parse(String string, ParsePosition position) { 396 return parse(address, string, position, parseBigDecimal); 397 } 398 399 // start getter and setter 400 401 public int getMaximumFractionDigits() { 402 return getAttribute(this.address, UNUM_MAX_FRACTION_DIGITS); 403 } 404 405 public int getMaximumIntegerDigits() { 406 return getAttribute(this.address, UNUM_MAX_INTEGER_DIGITS); 407 } 408 409 public int getMinimumFractionDigits() { 410 return getAttribute(this.address, UNUM_MIN_FRACTION_DIGITS); 411 } 412 413 public int getMinimumIntegerDigits() { 414 return getAttribute(this.address, UNUM_MIN_INTEGER_DIGITS); 415 } 416 417 public int getGroupingSize() { 418 // Work around http://bugs.icu-project.org/trac/ticket/10864 in icu4c 53. 419 if (!isGroupingUsed()) { 420 return 0; 421 } 422 return getAttribute(this.address, UNUM_GROUPING_SIZE); 423 } 424 425 public int getMultiplier() { 426 return getAttribute(this.address, UNUM_MULTIPLIER); 427 } 428 429 public String getNegativePrefix() { 430 if (negPrefNull) { 431 return null; 432 } 433 return getTextAttribute(this.address, UNUM_NEGATIVE_PREFIX); 434 } 435 436 public String getNegativeSuffix() { 437 if (negSuffNull) { 438 return null; 439 } 440 return getTextAttribute(this.address, UNUM_NEGATIVE_SUFFIX); 441 } 442 443 public String getPositivePrefix() { 444 if (posPrefNull) { 445 return null; 446 } 447 return getTextAttribute(this.address, UNUM_POSITIVE_PREFIX); 448 } 449 450 public String getPositiveSuffix() { 451 if (posSuffNull) { 452 return null; 453 } 454 return getTextAttribute(this.address, UNUM_POSITIVE_SUFFIX); 455 } 456 457 public boolean isDecimalSeparatorAlwaysShown() { 458 return getAttribute(this.address, UNUM_DECIMAL_ALWAYS_SHOWN) != 0; 459 } 460 461 public boolean isParseBigDecimal() { 462 return parseBigDecimal; 463 } 464 465 public boolean isParseIntegerOnly() { 466 return getAttribute(this.address, UNUM_PARSE_INT_ONLY) != 0; 467 } 468 469 public boolean isGroupingUsed() { 470 return getAttribute(this.address, UNUM_GROUPING_USED) != 0; 471 } 472 473 public void setDecimalSeparatorAlwaysShown(boolean value) { 474 int i = value ? -1 : 0; 475 setAttribute(this.address, UNUM_DECIMAL_ALWAYS_SHOWN, i); 476 } 477 478 public void setCurrency(String currencySymbol, String currencyCode) { 479 setSymbol(this.address, UNUM_CURRENCY_SYMBOL, currencySymbol); 480 setSymbol(this.address, UNUM_INTL_CURRENCY_SYMBOL, currencyCode); 481 } 482 483 public void setGroupingSize(int value) { 484 setAttribute(this.address, UNUM_GROUPING_SIZE, value); 485 } 486 487 public void setGroupingUsed(boolean value) { 488 int i = value ? -1 : 0; 489 setAttribute(this.address, UNUM_GROUPING_USED, i); 490 } 491 492 public void setMaximumFractionDigits(int value) { 493 setAttribute(this.address, UNUM_MAX_FRACTION_DIGITS, value); 494 } 495 496 public void setMaximumIntegerDigits(int value) { 497 setAttribute(this.address, UNUM_MAX_INTEGER_DIGITS, value); 498 } 499 500 public void setMinimumFractionDigits(int value) { 501 setAttribute(this.address, UNUM_MIN_FRACTION_DIGITS, value); 502 } 503 504 public void setMinimumIntegerDigits(int value) { 505 setAttribute(this.address, UNUM_MIN_INTEGER_DIGITS, value); 506 } 507 508 public void setMultiplier(int value) { 509 setAttribute(this.address, UNUM_MULTIPLIER, value); 510 } 511 512 public void setNegativePrefix(String value) { 513 negPrefNull = value == null; 514 if (!negPrefNull) { 515 setTextAttribute(this.address, UNUM_NEGATIVE_PREFIX, value); 516 } 517 } 518 519 public void setNegativeSuffix(String value) { 520 negSuffNull = value == null; 521 if (!negSuffNull) { 522 setTextAttribute(this.address, UNUM_NEGATIVE_SUFFIX, value); 523 } 524 } 525 526 public void setPositivePrefix(String value) { 527 posPrefNull = value == null; 528 if (!posPrefNull) { 529 setTextAttribute(this.address, UNUM_POSITIVE_PREFIX, value); 530 } 531 } 532 533 public void setPositiveSuffix(String value) { 534 posSuffNull = value == null; 535 if (!posSuffNull) { 536 setTextAttribute(this.address, UNUM_POSITIVE_SUFFIX, value); 537 } 538 } 539 540 public void setParseBigDecimal(boolean value) { 541 parseBigDecimal = value; 542 } 543 544 public void setParseIntegerOnly(boolean value) { 545 int i = value ? -1 : 0; 546 setAttribute(this.address, UNUM_PARSE_INT_ONLY, i); 547 } 548 549 private static void applyPattern(long addr, boolean localized, String pattern) { 550 try { 551 applyPatternImpl(addr, localized, pattern); 552 } catch (NullPointerException npe) { 553 throw npe; 554 } catch (RuntimeException re) { 555 throw new IllegalArgumentException("syntax error: " + re.getMessage() + ": " + pattern); 556 } 557 } 558 559 public void setRoundingMode(RoundingMode roundingMode, double roundingIncrement) { 560 final int nativeRoundingMode; 561 switch (roundingMode) { 562 case CEILING: nativeRoundingMode = 0; break; 563 case FLOOR: nativeRoundingMode = 1; break; 564 case DOWN: nativeRoundingMode = 2; break; 565 case UP: nativeRoundingMode = 3; break; 566 case HALF_EVEN: nativeRoundingMode = 4; break; 567 case HALF_DOWN: nativeRoundingMode = 5; break; 568 case HALF_UP: nativeRoundingMode = 6; break; 569 case UNNECESSARY: nativeRoundingMode = 7; break; 570 default: throw new AssertionError(); 571 } 572 setRoundingMode(address, nativeRoundingMode, roundingIncrement); 573 } 574 575 // Utility to get information about field positions from native (ICU) code. 576 private static class FieldPositionIterator { 577 private int[] data; 578 private int pos = -3; // so first call to next() leaves pos at 0 579 580 private FieldPositionIterator() { 581 } 582 583 public static FieldPositionIterator forFieldPosition(FieldPosition fp) { 584 return (fp != null) ? new FieldPositionIterator() : null; 585 } 586 587 public boolean next() { 588 if (data == null) { 589 return false; 590 } 591 pos += 3; 592 return pos < data.length; 593 } 594 595 public int fieldId() { 596 return data[pos]; 597 } 598 599 public Format.Field field() { 600 return ICU4C_FIELD_IDS[data[pos]]; 601 } 602 603 public int start() { 604 return data[pos + 1]; 605 } 606 607 public int limit() { 608 return data[pos + 2]; 609 } 610 611 // called by native 612 private void setData(int[] data) { 613 this.data = data; 614 this.pos = -3; 615 } 616 } 617 618 private static native void applyPatternImpl(long addr, boolean localized, String pattern); 619 private static native long cloneImpl(long addr); 620 private static native void close(long addr); 621 private static native char[] formatLong(long addr, long value, FieldPositionIterator iter); 622 private static native char[] formatDouble(long addr, double value, FieldPositionIterator iter); 623 private static native char[] formatDigitList(long addr, String value, FieldPositionIterator iter); 624 private static native int getAttribute(long addr, int symbol); 625 private static native String getTextAttribute(long addr, int symbol); 626 private static native long open(String pattern, String currencySymbol, 627 char decimalSeparator, char digit, String exponentSeparator, char groupingSeparator, 628 String infinity, String internationalCurrencySymbol, String minusSign, 629 char monetaryDecimalSeparator, String nan, char patternSeparator, char percent, 630 char perMill, char zeroDigit); 631 private static native Number parse(long addr, String string, ParsePosition position, boolean parseBigDecimal); 632 private static native void setDecimalFormatSymbols(long addr, String currencySymbol, 633 char decimalSeparator, char digit, String exponentSeparator, char groupingSeparator, 634 String infinity, String internationalCurrencySymbol, String minusSign, 635 char monetaryDecimalSeparator, String nan, char patternSeparator, char percent, 636 char perMill, char zeroDigit); 637 private static native void setSymbol(long addr, int symbol, String str); 638 private static native void setAttribute(long addr, int symbol, int i); 639 private static native void setRoundingMode(long addr, int roundingMode, double roundingIncrement); 640 private static native void setTextAttribute(long addr, int symbol, String str); 641 private static native String toPatternImpl(long addr, boolean localized); 642 } 643