blob: c6696498d3c6dd25d384f87b5bdca2a72c738f7e [file] [log] [blame]
/**
*******************************************************************************
* Copyright (C) 1996-2005, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
*******************************************************************************
*/
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
#include "ErrorCode.h"
#include "unicode/ucol.h"
#include "unicode/ucoleitr.h"
#include "ucol_imp.h"
/**
* Closing a C UCollator with the argument locale rules.
* Note determining if a collator currently exist for the caller is to be handled
* by the caller. Hence if the caller has a existing collator, it is his
* responsibility to delete first before calling this method.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of the C UCollator
*/
static void closeCollator(JNIEnv *env, jclass obj,
jint address) {
UCollator *collator = (UCollator *)(int)address;
ucol_close(collator);
}
/**
* Close a C collation element iterator.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of C collation element iterator to close.
*/
static void closeElements(JNIEnv *env, jclass obj,
jint address) {
UCollationElements *iterator = (UCollationElements *)(int)address;
ucol_closeElements(iterator);
}
/**
* Compare two strings.
* The strings will be compared using the normalization mode and options
* specified in openCollator or openCollatorFromRules
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of the c collator
* @param source The source string.
* @param target The target string.
* @return result of the comparison, UCOL_EQUAL, UCOL_GREATER or UCOL_LESS
*/
static jint compare(JNIEnv *env, jclass obj, jint address,
jstring source, jstring target) {
const UCollator *collator = (const UCollator *)(int)address;
jint result = -2;
if(collator){
jsize srclength = (*env)->GetStringLength(env, source);
const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
if(srcstr){
jsize tgtlength = (*env)->GetStringLength(env, target);
const UChar *tgtstr = (const UChar *)(*env)->GetStringCritical(env,target,0);
if(tgtstr){
result = ucol_strcoll(collator, srcstr, srclength, tgtstr, tgtlength);
(*env)->ReleaseStringCritical(env, source, srcstr);
(*env)->ReleaseStringCritical(env, target, tgtstr);
return result;
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
return result;
}
/**
* Universal attribute getter
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of the C collator
* @param type type of attribute to be set
* @return attribute value
* @exception thrown when error occurs while getting attribute value
*/
static jint getAttribute(JNIEnv *env, jclass obj, jint address,
jint type) {
const UCollator *collator = (const UCollator *)(int)address;
UErrorCode status = U_ZERO_ERROR;
if(collator){
jint result = (jint)ucol_getAttribute(collator, (UColAttribute)type,
&status);
if (icu4jni_error(env, status) != FALSE){
return (jint)UCOL_DEFAULT;
}
return result;
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
return (jint)UCOL_DEFAULT;
}
/**
* Create a CollationElementIterator object that will iterator over the elements
* in a string, using the collation rules defined in this RuleBasedCollatorJNI
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of C collator
* @param source string to iterate over
* @return address of C collationelement
*/
static jint getCollationElementIterator(JNIEnv *env,
jclass obj, jint address, jstring source) {
UErrorCode status = U_ZERO_ERROR;
UCollator *collator = (UCollator *)(int)address;
jint result=0;
if(collator){
jsize srclength = (*env)->GetStringLength(env, source);
const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
if(srcstr){
result = (jint)(ucol_openElements(collator, srcstr, srclength, &status));
(*env)->ReleaseStringCritical(env, source, srcstr);
icu4jni_error(env, status);
}else{
icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
}
}else{
icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
}
return result;
}
/**
* Get the maximum length of any expansion sequences that end with the specified
* comparison order.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of the C collation element iterator containing the text.
* @param order collation order returned by previous or next.
* @return maximum length of any expansion sequences ending with the specified
* order or 1 if collation order does not occur at the end of any
* expansion sequence.
*/
static jint getMaxExpansion(JNIEnv *env, jclass obj,
jint address, jint order) {
UCollationElements *iterator = (UCollationElements *)(int)address;
return ucol_getMaxExpansion(iterator, order);
}
/**
* Get the normalization mode for this object.
* The normalization mode influences how strings are compared.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of C collator
* @return normalization mode; one of the values from NormalizerEnum
*/
static jint getNormalization(JNIEnv *env, jclass obj,
jint address) {
const UCollator* collator = (const UCollator*) address;
UErrorCode status = U_ZERO_ERROR;
jint result = ucol_getAttribute(collator, UCOL_NORMALIZATION_MODE, &status);
icu4jni_error(env, status);
return result;
}
/**
* Set the normalization mode for this object.
* The normalization mode influences how strings are compared.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of C collator
* @param mode the normalization mode
*/
static void setNormalization(JNIEnv *env, jclass obj, jint address,
jint mode) {
const UCollator* collator = (const UCollator*) address;
UErrorCode status = U_ZERO_ERROR;
ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, mode, &status);
icu4jni_error(env, status);
}
/**
* Get the offset of the current source character.
* This is an offset into the text of the character containing the current
* collation elements.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param addresss of the C collation elements iterator to query.
* @return offset of the current source character.
*/
static jint getOffset(JNIEnv *env, jclass obj, jint address) {
UCollationElements *iterator = (UCollationElements *)(int)address;
return ucol_getOffset(iterator);
}
/**
* Get the collation rules from a UCollator.
* The rules will follow the rule syntax.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address the address of the C collator
* @return collation rules.
*/
static jstring getRules(JNIEnv *env, jclass obj,
jint address) {
const UCollator *collator = (const UCollator *)(int)address;
int32_t length=0;
const UChar *rules = ucol_getRules(collator, &length);
return (*env)->NewString(env, rules, length);
}
/**
* Get a sort key for the argument string
* Sort keys may be compared using java.util.Arrays.equals
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of the C collator
* @param source string for key to be generated
* @return sort key
*/
static jbyteArray getSortKey(JNIEnv *env, jclass obj,
jint address, jstring source) {
const UCollator *collator = (const UCollator *)(int)address;
jbyteArray result;
if(collator && source){
// BEGIN android-added
if(!source) {
return NULL;
}
// END android-added
jsize srclength = (*env)->GetStringLength(env, source);
const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source, 0);
if(srcstr){
// BEGIN android-changed
uint8_t bytearray[UCOL_MAX_BUFFER * 2];
uint8_t *largerbytearray = NULL;
uint8_t *usedbytearray = bytearray;
jint bytearraysize = ucol_getSortKey(collator, srcstr, srclength, bytearray,
sizeof(bytearray) - 1);
if (bytearraysize > sizeof(bytearray) - 1) {
// didn't fit, try again with a larger buffer.
largerbytearray = malloc(bytearraysize + 1);
usedbytearray = largerbytearray;
bytearraysize = ucol_getSortKey(collator, srcstr, srclength, largerbytearray,
bytearraysize);
}
(*env)->ReleaseStringCritical(env, source, srcstr);
if (bytearraysize == 0) {
free(largerbytearray);
return NULL;
}
/* no problem converting uint8_t to int8_t, gives back the correct value
* tried and tested
*/
result = (*env)->NewByteArray(env, bytearraysize);
(*env)->SetByteArrayRegion(env, result, 0, bytearraysize, usedbytearray);
free(largerbytearray);
// END android-changed
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
return result;
}
/**
* Returns a hash of this collation object
* Note this method is not complete, it only returns 0 at the moment.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of C collator
* @return hash of this collation object
*/
static jint hashCode(JNIEnv *env, jclass obj, jint address) {
UCollator *collator = (UCollator *)(int)address;
int32_t length=0;
const UChar *rules = ucol_getRules(collator, &length);
/* temporary commented out
* return uhash_hashUCharsN(rules, length);
*/
return 0;
}
/**
* Get the ordering priority of the next collation element in the text.
* A single character may contain more than one collation element.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address if C collation elements containing the text.
* @return next collation elements ordering, otherwise returns NULLORDER if an
* error has occured or if the end of string has been reached
*/
static jint next(JNIEnv *env, jclass obj, jint address) {
UCollationElements *iterator = (UCollationElements *) address;
UErrorCode status = U_ZERO_ERROR;
jint result = ucol_next(iterator, &status);
icu4jni_error(env, status);
return result;
}
/**
* Opening a new C UCollator with the default locale.
* Note determining if a collator currently exist for the caller is to be handled
* by the caller. Hence if the caller has a existing collator, it is his
* responsibility to delete first before calling this method.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @return address of the new C UCollator
* @exception thrown if creation of the UCollator fails
*/
static jint openCollator__(JNIEnv *env, jclass obj) {
UErrorCode status = U_ZERO_ERROR;
jint result = ucol_open(NULL, &status);
icu4jni_error(env, status);
return result;
}
/**
* Opening a new C UCollator with the argument locale rules.
* Note determining if a collator currently exist for the caller is to be handled
* by the caller. Hence if the caller has a existing collator, it is his
* responsibility to delete first before calling this method.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param locale name
* @return address of the new C UCollator
* @exception thrown if creation of the UCollator fails
*/
static jint openCollator__Ljava_lang_String_2(JNIEnv *env,
jclass obj, jstring locale) {
/* this will be null terminated */
const char* localeStr = (*env)->GetStringUTFChars(env, locale, NULL);
if (localeStr == NULL) {
icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
return 0;
}
UErrorCode status = U_ZERO_ERROR;
jint result = ucol_open(localeStr, &status);
(*env)->ReleaseStringUTFChars(env, locale, localeStr);
icu4jni_error(env, status);
return result;
}
/**
* Opening a new C UCollator with the argument locale rules.
* Note determining if a collator currently exist for the caller is to be
* handled by the caller. Hence if the caller has a existing collator, it is his
* responsibility to delete first before calling this method.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param rules set of collation rules
* @param normalizationmode normalization mode
* @param strength collation strength
* @return address of the new C UCollator
* @exception thrown if creation of the UCollator fails
*/
static jint openCollatorFromRules(JNIEnv *env, jclass obj,
jstring rules, jint normalizationmode, jint strength) {
jsize ruleslength = (*env)->GetStringLength(env, rules);
const UChar *rulestr = (const UChar *)(*env)->GetStringCritical(env,rules, 0);
UErrorCode status = U_ZERO_ERROR;
jint result = 0;
if(rulestr){
result = (jint)ucol_openRules(rulestr, ruleslength,
(UColAttributeValue)normalizationmode,
(UCollationStrength)strength, NULL, &status);
(*env)->ReleaseStringCritical(env, rules, rulestr);
icu4jni_error(env, status);
}else{
icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
}
return result;
}
/**
* Get the ordering priority of the previous collation element in the text.
* A single character may contain more than one collation element.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of the C collation element iterator containing the text.
* @return previous collation element ordering, otherwise returns NULLORDER if
* an error has occured or if the start of string has been reached
* @exception thrown when retrieval of previous collation element fails.
*/
static jint previous(JNIEnv *env, jclass obj, jint address) {
UCollationElements *iterator = (UCollationElements *)(int)address;
UErrorCode status = U_ZERO_ERROR;
jint result = ucol_previous(iterator, &status);
icu4jni_error(env, status);
return result;
}
/**
* Reset the collation elements to their initial state.
* This will move the 'cursor' to the beginning of the text.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of C collation element iterator to reset.
*/
static void reset(JNIEnv *env, jclass obj, jint address) {
UCollationElements *iterator = (UCollationElements *)(int)address;
ucol_reset(iterator);
}
/**
* Thread safe cloning operation
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of C collator to be cloned
* @return address of the new clone
* @exception thrown when error occurs while cloning
*/
static jint safeClone(JNIEnv *env, jclass obj, jint address) {
const UCollator *collator = (const UCollator *)(int)address;
UErrorCode status = U_ZERO_ERROR;
jint result;
jint buffersize = U_COL_SAFECLONE_BUFFERSIZE;
result = (jint)ucol_safeClone(collator, NULL, &buffersize, &status);
if ( icu4jni_error(env, status) != FALSE) {
return 0;
}
return result;
}
/**
* Universal attribute setter.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address address of the C collator
* @param type type of attribute to be set
* @param value attribute value
* @exception thrown when error occurs while setting attribute value
*/
static void setAttribute(JNIEnv *env, jclass obj, jint address,
jint type, jint value) {
UCollator *collator = (UCollator *)(int)address;
UErrorCode status = U_ZERO_ERROR;
ucol_setAttribute(collator, (UColAttribute)type, (UColAttributeValue)value,
&status);
icu4jni_error(env, status);
}
/**
* Set the offset of the current source character.
* This is an offset into the text of the character to be processed.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of the C collation element iterator to set.
* @param offset The desired character offset.
* @exception thrown when offset setting fails
*/
static void setOffset(JNIEnv *env, jclass obj, jint address,
jint offset) {
UCollationElements *iterator = (UCollationElements *)(int)address;
UErrorCode status = U_ZERO_ERROR;
ucol_setOffset(iterator, offset, &status);
icu4jni_error(env, status);
}
/**
* Set the text containing the collation elements.
* @param env JNI environment
* @param obj RuleBasedCollatorJNI object
* @param address of the C collation element iterator to be set
* @param source text containing the collation elements.
* @exception thrown when error occurs while setting offset
*/
static void setText(JNIEnv *env, jclass obj, jint address,
jstring source) {
UCollationElements *iterator = (UCollationElements *)(int)address;
UErrorCode status = U_ZERO_ERROR;
int strlength = (*env)->GetStringLength(env, source);
const UChar *str = (const UChar *)(*env)->GetStringCritical(env, source, 0);
ucol_setText(iterator, str, strlength, &status);
(*env)->ReleaseStringCritical(env, source, str);
icu4jni_error(env, status);
}
// BEGIN android-added
static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
const char * locale = ucol_getAvailable(index);
return (*env)->NewStringUTF(env, locale);
}
static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
return ucol_countAvailable();
}
// END android-added
/*
* JNI registratio
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// BEGIN android-added
{ "getAvailableLocalesImpl", "(I)Ljava/lang/String;", (void*) getAvailableLocalesImpl },
{ "getAvailableLocalesCountImpl", "()I", (void*) getAvailableLocalesCountImpl },
// END android-added
{ "openCollator", "()I", (void*) openCollator__ },
{ "openCollator", "(Ljava/lang/String;)I", (void*) openCollator__Ljava_lang_String_2 },
{ "openCollatorFromRules", "(Ljava/lang/String;II)I", (void*) openCollatorFromRules },
{ "closeCollator", "(I)V", (void*) closeCollator },
{ "compare", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) compare },
{ "getNormalization", "(I)I", (void*) getNormalization },
{ "setNormalization", "(II)V", (void*) setNormalization },
{ "getRules", "(I)Ljava/lang/String;", (void*) getRules },
{ "getSortKey", "(ILjava/lang/String;)[B", (void*) getSortKey },
{ "setAttribute", "(III)V", (void*) setAttribute },
{ "getAttribute", "(II)I", (void*) getAttribute },
{ "safeClone", "(I)I", (void*) safeClone },
{ "getCollationElementIterator", "(ILjava/lang/String;)I", (void*) getCollationElementIterator },
{ "hashCode", "(I)I", (void*) hashCode },
{ "closeElements", "(I)V", (void*) closeElements },
{ "reset", "(I)V", (void*) reset },
{ "next", "(I)I", (void*) next },
{ "previous", "(I)I", (void*) previous },
{ "getMaxExpansion", "(II)I", (void*) getMaxExpansion },
{ "setText", "(ILjava/lang/String;)V", (void*) setText },
{ "getOffset", "(I)I", (void*) getOffset },
{ "setOffset", "(II)V", (void*) setOffset }
};
int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv *_env) {
return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/text/NativeCollation",
gMethods, NELEM(gMethods));
}