1 /** 2 ******************************************************************************* 3 * Copyright (C) 1996-2005, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 * 7 ******************************************************************************* 8 */ 9 10 #include "JNIHelp.h" 11 #include "AndroidSystemNatives.h" 12 #include "ErrorCode.h" 13 #include "unicode/ucol.h" 14 #include "unicode/ucoleitr.h" 15 #include "ucol_imp.h" 16 17 18 /** 19 * Closing a C UCollator with the argument locale rules. 20 * Note determining if a collator currently exist for the caller is to be handled 21 * by the caller. Hence if the caller has a existing collator, it is his 22 * responsibility to delete first before calling this method. 23 * @param env JNI environment 24 * @param obj RuleBasedCollatorJNI object 25 * @param address of the C UCollator 26 */ 27 static void closeCollator(JNIEnv *env, jclass obj, 28 jint address) { 29 30 UCollator *collator = (UCollator *)(int)address; 31 ucol_close(collator); 32 } 33 34 35 /** 36 * Close a C collation element iterator. 37 * @param env JNI environment 38 * @param obj RuleBasedCollatorJNI object 39 * @param address of C collation element iterator to close. 40 */ 41 static void closeElements(JNIEnv *env, jclass obj, 42 jint address) { 43 44 UCollationElements *iterator = (UCollationElements *)(int)address; 45 ucol_closeElements(iterator); 46 } 47 48 /** 49 * Compare two strings. 50 * The strings will be compared using the normalization mode and options 51 * specified in openCollator or openCollatorFromRules 52 * @param env JNI environment 53 * @param obj RuleBasedCollatorJNI object 54 * @param address address of the c collator 55 * @param source The source string. 56 * @param target The target string. 57 * @return result of the comparison, UCOL_EQUAL, UCOL_GREATER or UCOL_LESS 58 */ 59 static jint compare(JNIEnv *env, jclass obj, jint address, 60 jstring source, jstring target) { 61 62 const UCollator *collator = (const UCollator *)(int)address; 63 jint result = -2; 64 if(collator){ 65 jsize srcLength = env->GetStringLength(source); 66 const UChar *chars = (const UChar *) env->GetStringCritical(source,0); 67 if(chars){ 68 jsize tgtlength = env->GetStringLength(target); 69 const UChar *tgtstr = (const UChar *) env->GetStringCritical(target,0); 70 if(tgtstr){ 71 result = ucol_strcoll(collator, chars, srcLength, tgtstr, tgtlength); 72 env->ReleaseStringCritical(source, chars); 73 env->ReleaseStringCritical(target, tgtstr); 74 return result; 75 }else{ 76 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 77 } 78 }else{ 79 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 80 } 81 }else{ 82 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 83 } 84 return result; 85 } 86 87 /** 88 * Universal attribute getter 89 * @param env JNI environment 90 * @param obj RuleBasedCollatorJNI object 91 * @param address address of the C collator 92 * @param type type of attribute to be set 93 * @return attribute value 94 * @exception thrown when error occurs while getting attribute value 95 */ 96 static jint getAttribute(JNIEnv *env, jclass obj, jint address, 97 jint type) { 98 99 const UCollator *collator = (const UCollator *)(int)address; 100 UErrorCode status = U_ZERO_ERROR; 101 if(collator){ 102 jint result = (jint)ucol_getAttribute(collator, (UColAttribute)type, 103 &status); 104 if (icu4jni_error(env, status) != FALSE){ 105 return (jint)UCOL_DEFAULT; 106 } 107 return result; 108 }else{ 109 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 110 } 111 return (jint)UCOL_DEFAULT; 112 } 113 114 /** 115 * Create a CollationElementIterator object that will iterator over the elements 116 * in a string, using the collation rules defined in this RuleBasedCollatorJNI 117 * @param env JNI environment 118 * @param obj RuleBasedCollatorJNI object 119 * @param address address of C collator 120 * @param source string to iterate over 121 * @return address of C collationelement 122 */ 123 static jint getCollationElementIterator(JNIEnv *env, 124 jclass obj, jint address, jstring source) { 125 126 UErrorCode status = U_ZERO_ERROR; 127 UCollator *collator = (UCollator *)(int)address; 128 jint result=0; 129 if(collator){ 130 jsize srcLength = env->GetStringLength(source); 131 const UChar *chars = (const UChar *) env->GetStringCritical(source,0); 132 if(chars){ 133 result = (jint)(ucol_openElements(collator, chars, srcLength, &status)); 134 135 env->ReleaseStringCritical(source, chars); 136 icu4jni_error(env, status); 137 }else{ 138 icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR); 139 } 140 }else{ 141 icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR); 142 } 143 return result; 144 } 145 146 /** 147 * Get the maximum length of any expansion sequences that end with the specified 148 * comparison order. 149 * @param env JNI environment 150 * @param obj RuleBasedCollatorJNI object 151 * @param address of the C collation element iterator containing the text. 152 * @param order collation order returned by previous or next. 153 * @return maximum length of any expansion sequences ending with the specified 154 * order or 1 if collation order does not occur at the end of any 155 * expansion sequence. 156 */ 157 static jint getMaxExpansion(JNIEnv *env, jclass obj, 158 jint address, jint order) { 159 160 UCollationElements *iterator = (UCollationElements *)(int)address; 161 return ucol_getMaxExpansion(iterator, order); 162 } 163 164 /** 165 * Get the normalization mode for this object. 166 * The normalization mode influences how strings are compared. 167 * @param env JNI environment 168 * @param obj RuleBasedCollatorJNI object 169 * @param address of C collator 170 * @return normalization mode; one of the values from NormalizerEnum 171 */ 172 static jint getNormalization(JNIEnv *env, jclass obj, 173 jint address) { 174 175 const UCollator* collator = (const UCollator*) address; 176 UErrorCode status = U_ZERO_ERROR; 177 jint result = ucol_getAttribute(collator, UCOL_NORMALIZATION_MODE, &status); 178 icu4jni_error(env, status); 179 return result; 180 } 181 182 /** 183 * Set the normalization mode for this object. 184 * The normalization mode influences how strings are compared. 185 * @param env JNI environment 186 * @param obj RuleBasedCollatorJNI object 187 * @param address of C collator 188 * @param mode the normalization mode 189 */ 190 static void setNormalization(JNIEnv *env, jclass, jint address, jint mode) { 191 UCollator* collator = reinterpret_cast<UCollator*>(static_cast<uintptr_t>(address)); 192 UErrorCode status = U_ZERO_ERROR; 193 ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UColAttributeValue(mode), &status); 194 icu4jni_error(env, status); 195 } 196 197 198 /** 199 * Get the offset of the current source character. 200 * This is an offset into the text of the character containing the current 201 * collation elements. 202 * @param env JNI environment 203 * @param obj RuleBasedCollatorJNI object 204 * @param addresss of the C collation elements iterator to query. 205 * @return offset of the current source character. 206 */ 207 static jint getOffset(JNIEnv *env, jclass obj, jint address) { 208 209 UCollationElements *iterator = (UCollationElements *)(int)address; 210 return ucol_getOffset(iterator); 211 } 212 213 /** 214 * Get the collation rules from a UCollator. 215 * The rules will follow the rule syntax. 216 * @param env JNI environment 217 * @param obj RuleBasedCollatorJNI object 218 * @param address the address of the C collator 219 * @return collation rules. 220 */ 221 static jstring getRules(JNIEnv *env, jclass obj, 222 jint address) { 223 224 const UCollator *collator = (const UCollator *)(int)address; 225 int32_t length=0; 226 const UChar *rules = ucol_getRules(collator, &length); 227 return env->NewString(rules, length); 228 } 229 230 /** 231 * Get a sort key for the argument string 232 * Sort keys may be compared using java.util.Arrays.equals 233 * @param env JNI environment 234 * @param obj RuleBasedCollatorJNI object 235 * @param address address of the C collator 236 * @param source string for key to be generated 237 * @return sort key 238 */ 239 static jbyteArray getSortKey(JNIEnv *env, jclass obj, 240 jint address, jstring source) { 241 242 const UCollator *collator = (const UCollator *)(int)address; 243 jbyteArray result = NULL; 244 if(collator && source){ 245 // BEGIN android-added 246 if(!source) { 247 return NULL; 248 } 249 // END android-added 250 jsize srcLength = env->GetStringLength(source); 251 const UChar *chars = (const UChar *) env->GetStringCritical(source, 0); 252 if (chars){ 253 // BEGIN android-changed 254 uint8_t byteArray[UCOL_MAX_BUFFER * 2]; 255 uint8_t *largerByteArray = NULL; 256 uint8_t *usedByteArray = byteArray; 257 258 size_t byteArraySize = ucol_getSortKey(collator, chars, srcLength, byteArray, 259 sizeof(byteArray) - 1); 260 261 if (byteArraySize > sizeof(byteArray) - 1) { 262 // didn't fit, try again with a larger buffer. 263 largerByteArray = new uint8_t[byteArraySize + 1]; 264 usedByteArray = largerByteArray; 265 byteArraySize = ucol_getSortKey(collator, chars, srcLength, largerByteArray, 266 byteArraySize); 267 } 268 269 env->ReleaseStringCritical(source, chars); 270 271 if (byteArraySize == 0) { 272 delete[] largerByteArray; 273 return NULL; 274 } 275 276 /* no problem converting uint8_t to int8_t, gives back the correct value 277 * tried and tested 278 */ 279 result = env->NewByteArray(byteArraySize); 280 env->SetByteArrayRegion(result, 0, byteArraySize, reinterpret_cast<jbyte*>(usedByteArray)); 281 delete[] largerByteArray; 282 // END android-changed 283 }else{ 284 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 285 } 286 }else{ 287 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 288 } 289 return result; 290 } 291 292 /** 293 * Returns a hash of this collation object 294 * Note this method is not complete, it only returns 0 at the moment. 295 * @param env JNI environment 296 * @param obj RuleBasedCollatorJNI object 297 * @param address address of C collator 298 * @return hash of this collation object 299 */ 300 static jint hashCode(JNIEnv *env, jclass obj, jint address) { 301 302 UCollator *collator = (UCollator *)(int)address; 303 int32_t length=0; 304 const UChar *rules = ucol_getRules(collator, &length); 305 /* temporary commented out 306 * return uhash_hashUCharsN(rules, length); 307 */ 308 return 0; 309 } 310 311 /** 312 * Get the ordering priority of the next collation element in the text. 313 * A single character may contain more than one collation element. 314 * @param env JNI environment 315 * @param obj RuleBasedCollatorJNI object 316 * @param address if C collation elements containing the text. 317 * @return next collation elements ordering, otherwise returns NULLORDER if an 318 * error has occured or if the end of string has been reached 319 */ 320 static jint next(JNIEnv *env, jclass obj, jint address) { 321 UCollationElements *iterator = (UCollationElements *) address; 322 UErrorCode status = U_ZERO_ERROR; 323 jint result = ucol_next(iterator, &status); 324 icu4jni_error(env, status); 325 return result; 326 } 327 328 /** 329 * Opening a new C UCollator with the default locale. 330 * Note determining if a collator currently exist for the caller is to be handled 331 * by the caller. Hence if the caller has a existing collator, it is his 332 * responsibility to delete first before calling this method. 333 * @param env JNI environment 334 * @param obj RuleBasedCollatorJNI object 335 * @return address of the new C UCollator 336 * @exception thrown if creation of the UCollator fails 337 */ 338 static jint openCollator__(JNIEnv *env, jclass obj) { 339 UErrorCode status = U_ZERO_ERROR; 340 UCollator* result = ucol_open(NULL, &status); 341 icu4jni_error(env, status); 342 return reinterpret_cast<uintptr_t>(result); 343 } 344 345 346 /** 347 * Opening a new C UCollator with the argument locale rules. 348 * Note determining if a collator currently exist for the caller is to be handled 349 * by the caller. Hence if the caller has a existing collator, it is his 350 * responsibility to delete first before calling this method. 351 * @param env JNI environment 352 * @param obj RuleBasedCollatorJNI object 353 * @param locale name 354 * @return address of the new C UCollator 355 * @exception thrown if creation of the UCollator fails 356 */ 357 static jint openCollator__Ljava_lang_String_2(JNIEnv *env, 358 jclass obj, jstring locale) { 359 360 /* this will be null terminated */ 361 const char* localeStr = env->GetStringUTFChars(locale, NULL); 362 if (localeStr == NULL) { 363 icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR); 364 return 0; 365 } 366 367 UErrorCode status = U_ZERO_ERROR; 368 UCollator* result = ucol_open(localeStr, &status); 369 env->ReleaseStringUTFChars(locale, localeStr); 370 icu4jni_error(env, status); 371 return reinterpret_cast<uintptr_t>(result); 372 } 373 374 /** 375 * Opening a new C UCollator with the argument locale rules. 376 * Note determining if a collator currently exist for the caller is to be 377 * handled by the caller. Hence if the caller has a existing collator, it is his 378 * responsibility to delete first before calling this method. 379 * @param env JNI environment 380 * @param obj RuleBasedCollatorJNI object 381 * @param rules set of collation rules 382 * @param normalizationmode normalization mode 383 * @param strength collation strength 384 * @return address of the new C UCollator 385 * @exception thrown if creation of the UCollator fails 386 */ 387 static jint openCollatorFromRules(JNIEnv *env, jclass obj, 388 jstring rules, jint normalizationmode, jint strength) { 389 390 jsize ruleslength = env->GetStringLength(rules); 391 const UChar *rulestr = (const UChar *) env->GetStringCritical(rules, 0); 392 UErrorCode status = U_ZERO_ERROR; 393 jint result = 0; 394 if(rulestr){ 395 result = (jint)ucol_openRules(rulestr, ruleslength, 396 (UColAttributeValue)normalizationmode, 397 (UCollationStrength)strength, NULL, &status); 398 399 env->ReleaseStringCritical(rules, rulestr); 400 icu4jni_error(env, status); 401 }else{ 402 icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR); 403 } 404 405 return result; 406 } 407 408 /** 409 * Get the ordering priority of the previous collation element in the text. 410 * A single character may contain more than one collation element. 411 * @param env JNI environment 412 * @param obj RuleBasedCollatorJNI object 413 * @param address of the C collation element iterator containing the text. 414 * @return previous collation element ordering, otherwise returns NULLORDER if 415 * an error has occured or if the start of string has been reached 416 * @exception thrown when retrieval of previous collation element fails. 417 */ 418 static jint previous(JNIEnv *env, jclass obj, jint address) { 419 420 UCollationElements *iterator = (UCollationElements *)(int)address; 421 UErrorCode status = U_ZERO_ERROR; 422 jint result = ucol_previous(iterator, &status); 423 424 icu4jni_error(env, status); 425 return result; 426 } 427 428 429 /** 430 * Reset the collation elements to their initial state. 431 * This will move the 'cursor' to the beginning of the text. 432 * @param env JNI environment 433 * @param obj RuleBasedCollatorJNI object 434 * @param address of C collation element iterator to reset. 435 */ 436 static void reset(JNIEnv *env, jclass obj, jint address) { 437 438 UCollationElements *iterator = (UCollationElements *)(int)address; 439 ucol_reset(iterator); 440 } 441 442 /** 443 * Thread safe cloning operation 444 * @param env JNI environment 445 * @param obj RuleBasedCollatorJNI object 446 * @param address address of C collator to be cloned 447 * @return address of the new clone 448 * @exception thrown when error occurs while cloning 449 */ 450 static jint safeClone(JNIEnv *env, jclass obj, jint address) { 451 452 const UCollator *collator = (const UCollator *)(int)address; 453 UErrorCode status = U_ZERO_ERROR; 454 jint result; 455 jint buffersize = U_COL_SAFECLONE_BUFFERSIZE; 456 457 result = (jint)ucol_safeClone(collator, NULL, &buffersize, &status); 458 459 if ( icu4jni_error(env, status) != FALSE) { 460 return 0; 461 } 462 463 return result; 464 } 465 466 /** 467 * Universal attribute setter. 468 * @param env JNI environment 469 * @param obj RuleBasedCollatorJNI object 470 * @param address address of the C collator 471 * @param type type of attribute to be set 472 * @param value attribute value 473 * @exception thrown when error occurs while setting attribute value 474 */ 475 static void setAttribute(JNIEnv *env, jclass obj, jint address, 476 jint type, jint value) { 477 478 UCollator *collator = (UCollator *)(int)address; 479 UErrorCode status = U_ZERO_ERROR; 480 ucol_setAttribute(collator, (UColAttribute)type, (UColAttributeValue)value, 481 &status); 482 icu4jni_error(env, status); 483 } 484 485 /** 486 * Set the offset of the current source character. 487 * This is an offset into the text of the character to be processed. 488 * @param env JNI environment 489 * @param obj RuleBasedCollatorJNI object 490 * @param address of the C collation element iterator to set. 491 * @param offset The desired character offset. 492 * @exception thrown when offset setting fails 493 */ 494 static void setOffset(JNIEnv *env, jclass obj, jint address, 495 jint offset) { 496 497 UCollationElements *iterator = (UCollationElements *)(int)address; 498 UErrorCode status = U_ZERO_ERROR; 499 500 ucol_setOffset(iterator, offset, &status); 501 icu4jni_error(env, status); 502 } 503 504 /** 505 * Set the text containing the collation elements. 506 * @param env JNI environment 507 * @param obj RuleBasedCollatorJNI object 508 * @param address of the C collation element iterator to be set 509 * @param source text containing the collation elements. 510 * @exception thrown when error occurs while setting offset 511 */ 512 static void setText(JNIEnv *env, jclass obj, jint address, 513 jstring source) { 514 515 UCollationElements *iterator = (UCollationElements *)(int)address; 516 UErrorCode status = U_ZERO_ERROR; 517 int strlength = env->GetStringLength(source); 518 const UChar *str = (const UChar *) env->GetStringCritical(source, 0); 519 520 ucol_setText(iterator, str, strlength, &status); 521 env->ReleaseStringCritical(source, str); 522 523 icu4jni_error(env, status); 524 } 525 526 static jobjectArray getAvailableLocalesImpl(JNIEnv *env, jclass clazz) { 527 jclass stringClass = env->FindClass("java/lang/String"); 528 if (stringClass == NULL) { 529 return NULL; 530 } 531 size_t count = ucol_countAvailable(); 532 jobjectArray result = env->NewObjectArray(count, stringClass, NULL); 533 for (size_t i = 0; i < count; ++i) { 534 jstring s = env->NewStringUTF(ucol_getAvailable(i)); 535 env->SetObjectArrayElement(result, i, s); 536 env->DeleteLocalRef(s); 537 } 538 return result; 539 } 540 541 static JNINativeMethod gMethods[] = { 542 /* name, signature, funcPtr */ 543 { "getAvailableLocalesImpl", "()[Ljava/lang/String;", (void*) getAvailableLocalesImpl }, 544 { "openCollator", "()I", (void*) openCollator__ }, 545 { "openCollator", "(Ljava/lang/String;)I", (void*) openCollator__Ljava_lang_String_2 }, 546 { "openCollatorFromRules", "(Ljava/lang/String;II)I", (void*) openCollatorFromRules }, 547 { "closeCollator", "(I)V", (void*) closeCollator }, 548 { "compare", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) compare }, 549 { "getNormalization", "(I)I", (void*) getNormalization }, 550 { "setNormalization", "(II)V", (void*) setNormalization }, 551 { "getRules", "(I)Ljava/lang/String;", (void*) getRules }, 552 { "getSortKey", "(ILjava/lang/String;)[B", (void*) getSortKey }, 553 { "setAttribute", "(III)V", (void*) setAttribute }, 554 { "getAttribute", "(II)I", (void*) getAttribute }, 555 { "safeClone", "(I)I", (void*) safeClone }, 556 { "getCollationElementIterator", "(ILjava/lang/String;)I", (void*) getCollationElementIterator }, 557 { "hashCode", "(I)I", (void*) hashCode }, 558 { "closeElements", "(I)V", (void*) closeElements }, 559 { "reset", "(I)V", (void*) reset }, 560 { "next", "(I)I", (void*) next }, 561 { "previous", "(I)I", (void*) previous }, 562 { "getMaxExpansion", "(II)I", (void*) getMaxExpansion }, 563 { "setText", "(ILjava/lang/String;)V", (void*) setText }, 564 { "getOffset", "(I)I", (void*) getOffset }, 565 { "setOffset", "(II)V", (void*) setOffset } 566 }; 567 568 int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv *_env) { 569 return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/text/NativeCollation", 570 gMethods, NELEM(gMethods)); 571 } 572