Home | History | Annotate | Download | only in native
      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