1 /* 2 * Copyright (C) 2006 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 #define LOG_TAG "NativeDecimalFormat" 18 #include "JNIHelp.h" 19 #include "AndroidSystemNatives.h" 20 #include "cutils/log.h" 21 #include "unicode/unum.h" 22 #include "unicode/numfmt.h" 23 #include "unicode/decimfmt.h" 24 #include "unicode/fmtable.h" 25 #include "unicode/ustring.h" 26 #include "digitlst.h" 27 #include "ErrorCode.h" 28 #include "ScopedJavaUnicodeString.h" 29 #include <stdlib.h> 30 #include <string.h> 31 32 static DecimalFormat* toDecimalFormat(jint addr) { 33 return reinterpret_cast<DecimalFormat*>(static_cast<uintptr_t>(addr)); 34 } 35 36 static DecimalFormatSymbols* makeDecimalFormatSymbols(JNIEnv* env, 37 jstring currencySymbol0, jchar decimalSeparator, jchar digit, 38 jchar groupingSeparator0, jstring infinity0, 39 jstring internationalCurrencySymbol0, jchar minusSign, 40 jchar monetaryDecimalSeparator, jstring nan0, jchar patternSeparator, 41 jchar percent, jchar perMill, jchar zeroDigit) { 42 ScopedJavaUnicodeString currencySymbol(env, currencySymbol0); 43 ScopedJavaUnicodeString infinity(env, infinity0); 44 ScopedJavaUnicodeString internationalCurrencySymbol(env, internationalCurrencySymbol0); 45 ScopedJavaUnicodeString nan(env, nan0); 46 UnicodeString groupingSeparator(groupingSeparator0); 47 48 DecimalFormatSymbols* result = new DecimalFormatSymbols; 49 result->setSymbol(DecimalFormatSymbols::kCurrencySymbol, currencySymbol.unicodeString()); 50 result->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UnicodeString(decimalSeparator)); 51 result->setSymbol(DecimalFormatSymbols::kDigitSymbol, UnicodeString(digit)); 52 result->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, groupingSeparator); 53 result->setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, groupingSeparator); 54 result->setSymbol(DecimalFormatSymbols::kInfinitySymbol, infinity.unicodeString()); 55 result->setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, internationalCurrencySymbol.unicodeString()); 56 result->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, UnicodeString(minusSign)); 57 result->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, UnicodeString(monetaryDecimalSeparator)); 58 result->setSymbol(DecimalFormatSymbols::kNaNSymbol, nan.unicodeString()); 59 result->setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, UnicodeString(patternSeparator)); 60 result->setSymbol(DecimalFormatSymbols::kPercentSymbol, UnicodeString(percent)); 61 result->setSymbol(DecimalFormatSymbols::kPerMillSymbol, UnicodeString(perMill)); 62 result->setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, UnicodeString(zeroDigit)); 63 return result; 64 } 65 66 static void setDecimalFormatSymbols(JNIEnv* env, jclass, jint addr, 67 jstring currencySymbol, jchar decimalSeparator, jchar digit, 68 jchar groupingSeparator, jstring infinity, 69 jstring internationalCurrencySymbol, jchar minusSign, 70 jchar monetaryDecimalSeparator, jstring nan, jchar patternSeparator, 71 jchar percent, jchar perMill, jchar zeroDigit) { 72 DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env, 73 currencySymbol, decimalSeparator, digit, groupingSeparator, 74 infinity, internationalCurrencySymbol, minusSign, 75 monetaryDecimalSeparator, nan, patternSeparator, percent, perMill, 76 zeroDigit); 77 toDecimalFormat(addr)->adoptDecimalFormatSymbols(symbols); 78 } 79 80 static jint openDecimalFormatImpl(JNIEnv* env, jclass clazz, jstring pattern0, 81 jstring currencySymbol, jchar decimalSeparator, jchar digit, 82 jchar groupingSeparator, jstring infinity, 83 jstring internationalCurrencySymbol, jchar minusSign, 84 jchar monetaryDecimalSeparator, jstring nan, jchar patternSeparator, 85 jchar percent, jchar perMill, jchar zeroDigit) { 86 if (pattern0 == NULL) { 87 jniThrowNullPointerException(env, NULL); 88 return 0; 89 } 90 UErrorCode status = U_ZERO_ERROR; 91 UParseError parseError; 92 ScopedJavaUnicodeString pattern(env, pattern0); 93 DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env, 94 currencySymbol, decimalSeparator, digit, groupingSeparator, 95 infinity, internationalCurrencySymbol, minusSign, 96 monetaryDecimalSeparator, nan, patternSeparator, percent, perMill, 97 zeroDigit); 98 DecimalFormat* fmt = new DecimalFormat(pattern.unicodeString(), symbols, parseError, status); 99 if (fmt == NULL) { 100 delete symbols; 101 } 102 icu4jni_error(env, status); 103 return static_cast<jint>(reinterpret_cast<uintptr_t>(fmt)); 104 } 105 106 static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) { 107 delete toDecimalFormat(addr); 108 } 109 110 static void setSymbol(JNIEnv* env, jclass, jint addr, jint symbol, jstring s) { 111 const UChar* chars = env->GetStringChars(s, NULL); 112 const int32_t charCount = env->GetStringLength(s); 113 UErrorCode status = U_ZERO_ERROR; 114 UNumberFormat* fmt = reinterpret_cast<UNumberFormat*>(static_cast<uintptr_t>(addr)); 115 unum_setSymbol(fmt, static_cast<UNumberFormatSymbol>(symbol), chars, charCount, &status); 116 icu4jni_error(env, status); 117 env->ReleaseStringChars(s, chars); 118 } 119 120 static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, 121 jint value) { 122 123 UNumberFormat *fmt = (UNumberFormat *)(int)addr; 124 125 unum_setAttribute(fmt, (UNumberFormatAttribute) symbol, value); 126 } 127 128 static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) { 129 130 UNumberFormat *fmt = (UNumberFormat *)(int)addr; 131 132 int res = unum_getAttribute(fmt, (UNumberFormatAttribute) symbol); 133 134 return res; 135 } 136 137 static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, 138 jstring text) { 139 140 // the errorcode returned by unum_setTextAttribute 141 UErrorCode status = U_ZERO_ERROR; 142 143 // get the pointer to the number format 144 UNumberFormat *fmt = (UNumberFormat *)(int)addr; 145 146 const UChar *textChars = env->GetStringChars(text, NULL); 147 int textLen = env->GetStringLength(text); 148 149 unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars, 150 textLen, &status); 151 152 env->ReleaseStringChars(text, textChars); 153 154 icu4jni_error(env, status); 155 } 156 157 static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, 158 jint symbol) { 159 160 uint32_t resultlength, reslenneeded; 161 162 // the errorcode returned by unum_getTextAttribute 163 UErrorCode status = U_ZERO_ERROR; 164 165 // get the pointer to the number format 166 UNumberFormat *fmt = (UNumberFormat *)(int)addr; 167 168 UChar* result = NULL; 169 resultlength=0; 170 171 // find out how long the result will be 172 reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, 173 result, resultlength, &status); 174 175 result = NULL; 176 if(status==U_BUFFER_OVERFLOW_ERROR) { 177 status=U_ZERO_ERROR; 178 resultlength=reslenneeded+1; 179 result=(UChar*)malloc(sizeof(UChar) * resultlength); 180 reslenneeded=unum_getTextAttribute(fmt, 181 (UNumberFormatTextAttribute) symbol, result, resultlength, 182 &status); 183 } 184 if (icu4jni_error(env, status) != FALSE) { 185 return NULL; 186 } 187 188 jstring res = env->NewString(result, reslenneeded); 189 190 free(result); 191 192 return res; 193 } 194 195 static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, jboolean localized, jstring pattern0) { 196 if (pattern0 == NULL) { 197 jniThrowNullPointerException(env, NULL); 198 return; 199 } 200 ScopedJavaUnicodeString pattern(env, pattern0); 201 DecimalFormat* fmt = toDecimalFormat(addr); 202 UErrorCode status = U_ZERO_ERROR; 203 if (localized) { 204 fmt->applyLocalizedPattern(pattern.unicodeString(), status); 205 } else { 206 fmt->applyPattern(pattern.unicodeString(), status); 207 } 208 icu4jni_error(env, status); 209 } 210 211 static jstring toPatternImpl(JNIEnv *env, jclass, jint addr, jboolean localized) { 212 DecimalFormat* fmt = toDecimalFormat(addr); 213 UnicodeString pattern; 214 if (localized) { 215 fmt->toLocalizedPattern(pattern); 216 } else { 217 fmt->toPattern(pattern); 218 } 219 return env->NewString(pattern.getBuffer(), pattern.length()); 220 } 221 222 template <typename T> 223 static jstring format(JNIEnv *env, jint addr, jobject field, jstring fieldType, jobject attributes, T val) { 224 UErrorCode status = U_ZERO_ERROR; 225 226 DecimalFormat::AttributeBuffer attrBuffer; 227 attrBuffer.buffer = NULL; 228 DecimalFormat::AttributeBuffer* attrBufferPtr = NULL; 229 if (attributes != NULL || (fieldType != NULL && field != NULL)) { 230 attrBufferPtr = &attrBuffer; 231 // ICU requires that this is dynamically allocated and non-zero size. 232 // ICU grows it in chunks of 128 bytes, so that's a reasonable initial size. 233 attrBuffer.bufferSize = 128; 234 attrBuffer.buffer = new char[attrBuffer.bufferSize]; 235 attrBuffer.buffer[0] = '\0'; 236 } 237 238 FieldPosition fp; 239 fp.setField(FieldPosition::DONT_CARE); 240 241 UnicodeString str; 242 DecimalFormat* fmt = toDecimalFormat(addr); 243 fmt->format(val, str, fp, attrBufferPtr); 244 245 if (attrBufferPtr && strlen(attrBuffer.buffer) > 0) { 246 // check if we want to get all attributes 247 if (attributes != NULL) { 248 jstring attrString = env->NewStringUTF(attrBuffer.buffer + 1); // cut off the leading ';' 249 jclass stringBufferClass = env->FindClass("java/lang/StringBuffer"); 250 jmethodID appendMethodID = env->GetMethodID(stringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 251 env->CallObjectMethod(attributes, appendMethodID, attrString); 252 } 253 254 // check if we want one special attribute returned in the given FieldPos 255 if (fieldType != NULL && field != NULL) { 256 const char* fieldName = env->GetStringUTFChars(fieldType, NULL); 257 258 const char* delimiter = ";"; 259 char* context = NULL; 260 char* resattr = strtok_r(attrBuffer.buffer, delimiter, &context); 261 262 while (resattr != NULL && strcmp(resattr, fieldName) != 0) { 263 resattr = strtok_r(NULL, delimiter, &context); 264 } 265 266 if (resattr != NULL && strcmp(resattr, fieldName) == 0) { 267 resattr = strtok_r(NULL, delimiter, &context); 268 int begin = (int) strtol(resattr, NULL, 10); 269 resattr = strtok_r(NULL, delimiter, &context); 270 int end = (int) strtol(resattr, NULL, 10); 271 272 jclass fieldPositionClass = env->FindClass("java/text/FieldPosition"); 273 jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, "setBeginIndex", "(I)V"); 274 jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, "setEndIndex", "(I)V"); 275 env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin); 276 env->CallVoidMethod(field, setEndIndexMethodID, (jint) end); 277 } 278 env->ReleaseStringUTFChars(fieldType, fieldName); 279 } 280 } 281 282 jstring result = env->NewString(str.getBuffer(), str.length()); 283 delete[] attrBuffer.buffer; 284 return result; 285 } 286 287 static jstring formatLong(JNIEnv* env, jclass, jint addr, jlong value, 288 jobject field, jstring fieldType, jobject attributes) { 289 int64_t longValue = value; 290 return format(env, addr, field, fieldType, attributes, longValue); 291 } 292 293 static jstring formatDouble(JNIEnv* env, jclass, jint addr, jdouble value, 294 jobject field, jstring fieldType, jobject attributes) { 295 double doubleValue = value; 296 return format(env, addr, field, fieldType, attributes, doubleValue); 297 } 298 299 static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value, 300 jobject field, jstring fieldType, jobject attributes, jint scale) { 301 302 // const char * valueUTF = env->GetStringUTFChars(value, NULL); 303 // LOGI("ENTER formatDigitList: %s, scale: %d", valueUTF, scale); 304 // env->ReleaseStringUTFChars(value, valueUTF); 305 306 if (scale < 0) { 307 icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR); 308 return NULL; 309 } 310 311 const char * fieldName = NULL; 312 if(fieldType != NULL) { 313 fieldName = env->GetStringUTFChars(fieldType, NULL); 314 } 315 316 uint32_t reslenneeded; 317 318 // prepare digit list 319 320 const char *valueChars = env->GetStringUTFChars(value, NULL); 321 322 bool isInteger = (scale == 0); 323 bool isPositive = (*valueChars != '-'); 324 325 // skip the '-' if the number is negative 326 const char *digits = (isPositive ? valueChars : valueChars + 1); 327 int length = strlen(digits); 328 329 DecimalFormat* fmt = toDecimalFormat(addr); 330 331 // The length of our digit list buffer must be the actual string length + 3, 332 // because ICU will append some additional characters at the head and at the 333 // tail of the string, in order to keep strtod() happy: 334 // 335 // - The sign "+" or "-" is appended at the head 336 // - The exponent "e" and the "\0" terminator is appended at the tail 337 // 338 // In retrospect, the changes to ICU's DigitList that were necessary for 339 // big numbers look a bit hacky. It would make sense to rework all this 340 // once ICU 4.x has been integrated into Android. Ideally, big number 341 // support would make it into ICU itself, so we don't need our private 342 // fix anymore. 343 DigitList digitList(length + 3); 344 digitList.fCount = length; 345 strcpy(digitList.fDigits, digits); 346 env->ReleaseStringUTFChars(value, valueChars); 347 348 digitList.fDecimalAt = digitList.fCount - scale; 349 digitList.fIsPositive = isPositive; 350 digitList.fRoundingMode = fmt->getRoundingMode(); 351 digitList.round(fmt->getMaximumFractionDigits() + digitList.fDecimalAt); 352 353 UChar *result = NULL; 354 355 FieldPosition fp; 356 fp.setField(FieldPosition::DONT_CARE); 357 fp.setBeginIndex(0); 358 fp.setEndIndex(0); 359 360 UErrorCode status = U_ZERO_ERROR; 361 362 DecimalFormat::AttributeBuffer *attrBuffer = NULL; 363 attrBuffer = (DecimalFormat::AttributeBuffer *) calloc(sizeof(DecimalFormat::AttributeBuffer), 1); 364 attrBuffer->bufferSize = 128; 365 attrBuffer->buffer = (char *) calloc(129 * sizeof(char), 1); 366 367 UnicodeString res; 368 369 fmt->subformat(res, fp, attrBuffer, digitList, isInteger); 370 371 reslenneeded = res.extract(NULL, 0, status); 372 373 if(status==U_BUFFER_OVERFLOW_ERROR) { 374 status=U_ZERO_ERROR; 375 376 result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); 377 378 res.extract(result, reslenneeded + 1, status); 379 380 if (icu4jni_error(env, status) != FALSE) { 381 if(fieldType != NULL) { 382 env->ReleaseStringUTFChars(fieldType, fieldName); 383 } 384 free(result); 385 free(attrBuffer->buffer); 386 free(attrBuffer); 387 return NULL; 388 } 389 390 } else { 391 if(fieldType != NULL) { 392 env->ReleaseStringUTFChars(fieldType, fieldName); 393 } 394 free(attrBuffer->buffer); 395 free(attrBuffer); 396 return NULL; 397 } 398 399 int attrLength = (strlen(attrBuffer->buffer) + 1 ); 400 401 if(attrLength > 1) { 402 403 // check if we want to get all attributes 404 if(attributes != NULL) { 405 // prepare the classes and method ids 406 const char * stringBufferClassName = "java/lang/StringBuffer"; 407 jclass stringBufferClass = env->FindClass(stringBufferClassName); 408 jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 409 "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 410 411 jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1); // cut off the leading ';' 412 env->CallObjectMethod(attributes, appendMethodID, attrString); 413 } 414 415 // check if we want one special attribute returned in the given FieldPos 416 if(fieldName != NULL && field != NULL) { 417 const char *delimiter = ";"; 418 int begin; 419 int end; 420 char * resattr; 421 resattr = strtok(attrBuffer->buffer, delimiter); 422 423 while(resattr != NULL && strcmp(resattr, fieldName) != 0) { 424 resattr = strtok(NULL, delimiter); 425 } 426 427 if(resattr != NULL && strcmp(resattr, fieldName) == 0) { 428 429 // prepare the classes and method ids 430 const char * fieldPositionClassName = 431 "java/text/FieldPosition"; 432 jclass fieldPositionClass = env->FindClass( 433 fieldPositionClassName); 434 jmethodID setBeginIndexMethodID = env->GetMethodID( 435 fieldPositionClass, "setBeginIndex", "(I)V"); 436 jmethodID setEndIndexMethodID = env->GetMethodID( 437 fieldPositionClass, "setEndIndex", "(I)V"); 438 439 440 resattr = strtok(NULL, delimiter); 441 begin = (int) strtol(resattr, NULL, 10); 442 resattr = strtok(NULL, delimiter); 443 end = (int) strtol(resattr, NULL, 10); 444 445 env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin); 446 env->CallVoidMethod(field, setEndIndexMethodID, (jint) end); 447 } 448 } 449 } 450 451 if(fieldType != NULL) { 452 env->ReleaseStringUTFChars(fieldType, fieldName); 453 } 454 455 jstring resulting = env->NewString(result, reslenneeded); 456 457 free(attrBuffer->buffer); 458 free(attrBuffer); 459 free(result); 460 // const char * resultUTF = env->GetStringUTFChars(resulting, NULL); 461 // LOGI("RETURN formatDigitList: %s", resultUTF); 462 // env->ReleaseStringUTFChars(resulting, resultUTF); 463 464 return resulting; 465 } 466 467 static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, 468 jobject position) { 469 // TODO: cache these? 470 jclass parsePositionClass = env->FindClass("java/text/ParsePosition"); 471 jclass longClass = env->FindClass("java/lang/Long"); 472 jclass doubleClass = env->FindClass("java/lang/Double"); 473 jclass bigDecimalClass = env->FindClass("java/math/BigDecimal"); 474 jclass bigIntegerClass = env->FindClass("java/math/BigInteger"); 475 476 jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, 477 "getIndex", "()I"); 478 jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, 479 "setIndex", "(I)V"); 480 jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, 481 "setErrorIndex", "(I)V"); 482 483 jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V"); 484 jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V"); 485 jmethodID bigDecimalInitMethodID = env->GetMethodID(bigDecimalClass, "<init>", "(Ljava/math/BigInteger;I)V"); 486 jmethodID bigIntegerInitMethodID = env->GetMethodID(bigIntegerClass, "<init>", "(Ljava/lang/String;)V"); 487 jmethodID doubleValueMethodID = env->GetMethodID(bigDecimalClass, "doubleValue", "()D"); 488 489 // make sure the ParsePosition is valid. Actually icu4c would parse a number 490 // correctly even if the parsePosition is set to -1, but since the RI fails 491 // for that case we have to fail too 492 int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL); 493 const int strlength = env->GetStringLength(text); 494 if(parsePos < 0 || parsePos > strlength) { 495 return NULL; 496 } 497 498 ParsePosition pp; 499 pp.setIndex(parsePos); 500 501 DigitList digits; 502 503 UNumberFormat *fmt = (UNumberFormat *)(int)addr; 504 Formattable res; 505 bool resultAssigned; 506 jchar *str = (UChar *)env->GetStringChars(text, NULL); 507 const UnicodeString src((UChar*)str, strlength, strlength); 508 ((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits); 509 env->ReleaseStringChars(text, str); 510 511 if(pp.getErrorIndex() == -1) { 512 parsePos = pp.getIndex(); 513 } else { 514 env->CallVoidMethod(position, setErrorIndexMethodID, 515 (jint) pp.getErrorIndex()); 516 return NULL; 517 } 518 519 Formattable::Type numType = res.getType(); 520 UErrorCode fmtStatus; 521 522 double resultDouble; 523 long resultLong; 524 int64_t resultInt64; 525 jstring resultStr; 526 jobject resultObject1, resultObject2; 527 528 if (resultAssigned) 529 { 530 switch(numType) { 531 case Formattable::kDouble: 532 resultDouble = res.getDouble(); 533 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); 534 return env->NewObject(doubleClass, dblInitMethodID, 535 (jdouble) resultDouble); 536 case Formattable::kLong: 537 resultLong = res.getLong(); 538 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); 539 return env->NewObject(longClass, longInitMethodID, 540 (jlong) resultLong); 541 case Formattable::kInt64: 542 resultInt64 = res.getInt64(); 543 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); 544 return env->NewObject(longClass, longInitMethodID, 545 (jlong) resultInt64); 546 default: 547 return NULL; 548 } 549 } 550 else 551 { 552 int scale = digits.fCount - digits.fDecimalAt; 553 // ATTENTION: Abuse of Implementation Knowlegde! 554 digits.fDigits[digits.fCount] = 0; 555 if (digits.fIsPositive) { 556 resultStr = env->NewStringUTF(digits.fDigits); 557 } else { 558 if (digits.fCount == 0) { 559 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); 560 return env->NewObject(doubleClass, dblInitMethodID, (jdouble)-0); 561 } else { 562 // ATTENTION: Abuse of Implementation Knowlegde! 563 *(digits.fDigits - 1) = '-'; 564 resultStr = env->NewStringUTF(digits.fDigits - 1); 565 } 566 } 567 568 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); 569 570 resultObject1 = env->NewObject(bigIntegerClass, bigIntegerInitMethodID, resultStr); 571 resultObject2 = env->NewObject(bigDecimalClass, bigDecimalInitMethodID, resultObject1, scale); 572 return resultObject2; 573 } 574 } 575 576 static jint cloneDecimalFormatImpl(JNIEnv *env, jclass, jint addr) { 577 DecimalFormat* fmt = toDecimalFormat(addr); 578 return static_cast<jint>(reinterpret_cast<uintptr_t>(fmt->clone())); 579 } 580 581 static JNINativeMethod gMethods[] = { 582 /* name, signature, funcPtr */ 583 {"applyPatternImpl", "(IZLjava/lang/String;)V", (void*) applyPatternImpl}, 584 {"cloneDecimalFormatImpl", "(I)I", (void*) cloneDecimalFormatImpl}, 585 {"closeDecimalFormatImpl", "(I)V", (void*) closeDecimalFormatImpl}, 586 {"format", "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", (void*) formatDouble}, 587 {"format", "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", (void*) formatLong}, 588 {"format", "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;", (void*) formatDigitList}, 589 {"getAttribute", "(II)I", (void*) getAttribute}, 590 {"getTextAttribute", "(II)Ljava/lang/String;", (void*) getTextAttribute}, 591 {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;CCCLjava/lang/String;Ljava/lang/String;CCLjava/lang/String;CCCC)I", (void*) openDecimalFormatImpl}, 592 {"parse", "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;", (void*) parse}, 593 {"setAttribute", "(III)V", (void*) setAttribute}, 594 {"setDecimalFormatSymbols", "(ILjava/lang/String;CCCLjava/lang/String;Ljava/lang/String;CCLjava/lang/String;CCCC)V", (void*) setDecimalFormatSymbols}, 595 {"setSymbol", "(IILjava/lang/String;)V", (void*) setSymbol}, 596 {"setTextAttribute", "(IILjava/lang/String;)V", (void*) setTextAttribute}, 597 {"toPatternImpl", "(IZ)Ljava/lang/String;", (void*) toPatternImpl}, 598 }; 599 int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) { 600 return jniRegisterNativeMethods(env, 601 "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods, 602 NELEM(gMethods)); 603 } 604