• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
closeCollator(JNIEnv * env,jclass obj,jint address)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 */
closeElements(JNIEnv * env,jclass obj,jint address)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 */
compare(JNIEnv * env,jclass obj,jint address,jstring source,jstring target)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(env, source);
66         const UChar *srcstr   = (const UChar *)(*env)->GetStringCritical(env,source,0);
67         if(srcstr){
68             jsize       tgtlength = (*env)->GetStringLength(env, target);
69             const UChar *tgtstr    = (const UChar *)(*env)->GetStringCritical(env,target,0);
70             if(tgtstr){
71                   result = ucol_strcoll(collator, srcstr, srclength, tgtstr, tgtlength);
72                   (*env)->ReleaseStringCritical(env, source, srcstr);
73                   (*env)->ReleaseStringCritical(env, 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 */
getAttribute(JNIEnv * env,jclass obj,jint address,jint type)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 */
getCollationElementIterator(JNIEnv * env,jclass obj,jint address,jstring source)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(env, source);
131         const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
132         if(srcstr){
133             result = (jint)(ucol_openElements(collator, srcstr, srclength, &status));
134 
135             (*env)->ReleaseStringCritical(env, source, srcstr);
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 */
getMaxExpansion(JNIEnv * env,jclass obj,jint address,jint order)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 */
getNormalization(JNIEnv * env,jclass obj,jint address)172 static jint getNormalization(JNIEnv *env, jclass obj,
173         jint address) {
174 
175   UErrorCode status = U_ZERO_ERROR;
176   const UCollator *collator = (const UCollator *)(int)address;
177   if(U_FAILURE(status)){
178        icu4jni_error(env, status);
179   }
180   return (jint)ucol_getAttribute(collator,UCOL_NORMALIZATION_MODE,&status);
181 
182 }
183 
184 /**
185 * Set the normalization mode for this object.
186 * The normalization mode influences how strings are compared.
187 * @param env JNI environment
188 * @param obj RuleBasedCollatorJNI object
189 * @param address of C collator
190 * @param mode the normalization mode
191 */
setNormalization(JNIEnv * env,jclass obj,jint address,jint mode)192 static void setNormalization(JNIEnv *env, jclass obj, jint address,
193         jint mode) {
194 
195     UErrorCode status = U_ZERO_ERROR;
196     const UCollator *collator = (const UCollator *)(int)address;
197     if(U_FAILURE(status)){
198         icu4jni_error(env, status);
199     }
200     ucol_setAttribute(collator,UCOL_NORMALIZATION_MODE,mode,&status);
201 }
202 
203 
204 /**
205 * Get the offset of the current source character.
206 * This is an offset into the text of the character containing the current
207 * collation elements.
208 * @param env JNI environment
209 * @param obj RuleBasedCollatorJNI object
210 * @param addresss of the C collation elements iterator to query.
211 * @return offset of the current source character.
212 */
getOffset(JNIEnv * env,jclass obj,jint address)213 static jint getOffset(JNIEnv *env, jclass obj, jint address) {
214 
215   UCollationElements *iterator = (UCollationElements *)(int)address;
216   return ucol_getOffset(iterator);
217 }
218 
219 /**
220 * Get the collation rules from a UCollator.
221 * The rules will follow the rule syntax.
222 * @param env JNI environment
223 * @param obj RuleBasedCollatorJNI object
224 * @param address the address of the C collator
225 * @return collation rules.
226 */
getRules(JNIEnv * env,jclass obj,jint address)227 static jstring getRules(JNIEnv *env, jclass obj,
228         jint address) {
229 
230   const UCollator *collator = (const UCollator *)(int)address;
231   int32_t length=0;
232   const UChar *rules = ucol_getRules(collator, &length);
233   return (*env)->NewString(env, rules, length);
234 }
235 
236 /**
237 * Get a sort key for the argument string
238 * Sort keys may be compared using java.util.Arrays.equals
239 * @param env JNI environment
240 * @param obj RuleBasedCollatorJNI object
241 * @param address address of the C collator
242 * @param source string for key to be generated
243 * @return sort key
244 */
getSortKey(JNIEnv * env,jclass obj,jint address,jstring source)245 static jbyteArray getSortKey(JNIEnv *env, jclass obj,
246         jint address, jstring source) {
247 
248   const UCollator *collator  = (const UCollator *)(int)address;
249   jbyteArray result;
250   if(collator && source){
251       // BEGIN android-added
252       if(!source) {
253           return NULL;
254       }
255       // END android-added
256       jsize srclength            = (*env)->GetStringLength(env, source);
257       const UChar *srcstr        = (const UChar *)(*env)->GetStringCritical(env,source, 0);
258       if(srcstr){
259 // BEGIN android-changed
260           uint8_t bytearray[UCOL_MAX_BUFFER * 2];
261           uint8_t *largerbytearray = NULL;
262           uint8_t *usedbytearray = bytearray;
263 
264           jint bytearraysize = ucol_getSortKey(collator, srcstr, srclength, bytearray,
265                                                sizeof(bytearray) - 1);
266 
267           if (bytearraysize > sizeof(bytearray) - 1) {
268             // didn't fit, try again with a larger buffer.
269             largerbytearray = malloc(bytearraysize + 1);
270             usedbytearray = largerbytearray;
271             bytearraysize = ucol_getSortKey(collator, srcstr, srclength, largerbytearray,
272                                                bytearraysize);
273           }
274 
275           (*env)->ReleaseStringCritical(env, source, srcstr);
276 
277           if (bytearraysize == 0) {
278             free(largerbytearray);
279             return NULL;
280           }
281 
282           /* no problem converting uint8_t to int8_t, gives back the correct value
283            * tried and tested
284            */
285           result = (*env)->NewByteArray(env, bytearraysize);
286           (*env)->SetByteArrayRegion(env, result, 0, bytearraysize, usedbytearray);
287           free(largerbytearray);
288 // END android-changed
289       }else{
290           icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
291       }
292   }else{
293     icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
294   }
295   return result;
296 }
297 
298 /**
299 * Returns a hash of this collation object
300 * Note this method is not complete, it only returns 0 at the moment.
301 * @param env JNI environment
302 * @param obj RuleBasedCollatorJNI object
303 * @param address address of C collator
304 * @return hash of this collation object
305 */
hashCode(JNIEnv * env,jclass obj,jint address)306 static jint hashCode(JNIEnv *env, jclass obj, jint address) {
307 
308   UCollator *collator = (UCollator *)(int)address;
309   int32_t length=0;
310   const UChar *rules = ucol_getRules(collator, &length);
311   /* temporary commented out
312    * return uhash_hashUCharsN(rules, length);
313    */
314   return 0;
315 }
316 
317 /**
318 * Get the ordering priority of the next collation element in the text.
319 * A single character may contain more than one collation element.
320 * @param env JNI environment
321 * @param obj RuleBasedCollatorJNI object
322 * @param address if C collation elements containing the text.
323 * @return next collation elements ordering, otherwise returns NULLORDER if an
324 *         error has occured or if the end of string has been reached
325 */
next(JNIEnv * env,jclass obj,jint address)326 static jint next(JNIEnv *env, jclass obj, jint address) {
327   UCollationElements *iterator = (UCollationElements *)(int)address;
328   UErrorCode status = U_ZERO_ERROR;
329   jint result = ucol_next(iterator, &status);
330 
331    icu4jni_error(env, status);
332   return result;
333 }
334 
335 /**
336 * Opening a new C UCollator with the default locale.
337 * Note determining if a collator currently exist for the caller is to be handled
338 * by the caller. Hence if the caller has a existing collator, it is his
339 * responsibility to delete first before calling this method.
340 * @param env JNI environment
341 * @param obj RuleBasedCollatorJNI object
342 * @return address of the new C UCollator
343 * @exception thrown if creation of the UCollator fails
344 */
openCollator__(JNIEnv * env,jclass obj)345 static jint openCollator__(JNIEnv *env, jclass obj) {
346   jint result;
347   UErrorCode status = U_ZERO_ERROR;
348 
349   result = (jint)ucol_open(NULL, &status);
350   if ( icu4jni_error(env, status) != FALSE)
351     return 0;
352 
353   return result;
354 }
355 
356 
357 /**
358 * Opening a new C UCollator with the argument locale rules.
359 * Note determining if a collator currently exist for the caller is to be handled
360 * by the caller. Hence if the caller has a existing collator, it is his
361 * responsibility to delete first before calling this method.
362 * @param env JNI environment
363 * @param obj RuleBasedCollatorJNI object
364 * @param locale name
365 * @return address of the new C UCollator
366 * @exception thrown if creation of the UCollator fails
367 */
openCollator__Ljava_lang_String_2(JNIEnv * env,jclass obj,jstring locale)368 static jint openCollator__Ljava_lang_String_2(JNIEnv *env,
369         jclass obj, jstring locale) {
370 
371   /* this will be null terminated */
372   const char *localestr = (*env)->GetStringUTFChars(env, locale, 0);
373   jint result=0;
374   UErrorCode status = U_ZERO_ERROR;
375 
376   if(localestr){
377       result = (jint)ucol_open(localestr, &status);
378       (*env)->ReleaseStringUTFChars(env, locale, localestr);
379       icu4jni_error(env, status);
380   }else{
381       icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
382   }
383   return result;
384 }
385 
386 /**
387 * Opening a new C UCollator with the argument locale rules.
388 * Note determining if a collator currently exist for the caller is to be
389 * handled by the caller. Hence if the caller has a existing collator, it is his
390 * responsibility to delete first before calling this method.
391 * @param env JNI environment
392 * @param obj RuleBasedCollatorJNI object
393 * @param rules set of collation rules
394 * @param normalizationmode normalization mode
395 * @param strength collation strength
396 * @return address of the new C UCollator
397 * @exception thrown if creation of the UCollator fails
398 */
openCollatorFromRules(JNIEnv * env,jclass obj,jstring rules,jint normalizationmode,jint strength)399 static jint openCollatorFromRules(JNIEnv *env, jclass obj,
400         jstring rules, jint normalizationmode, jint strength) {
401 
402   jsize  ruleslength    = (*env)->GetStringLength(env, rules);
403   const UChar *rulestr  = (const UChar *)(*env)->GetStringCritical(env,rules, 0);
404   UErrorCode status     = U_ZERO_ERROR;
405   jint   result        = 0;
406   if(rulestr){
407       result = (jint)ucol_openRules(rulestr, ruleslength,
408                                    (UColAttributeValue)normalizationmode,
409                                    (UCollationStrength)strength, NULL, &status);
410 
411       (*env)->ReleaseStringCritical(env, rules, rulestr);
412       icu4jni_error(env, status);
413   }else{
414       icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
415   }
416 
417   return result;
418 }
419 
420 /**
421 * Get the ordering priority of the previous collation element in the text.
422 * A single character may contain more than one collation element.
423 * @param env JNI environment
424 * @param obj RuleBasedCollatorJNI object
425 * @param address of the C collation element iterator containing the text.
426 * @return previous collation element ordering, otherwise returns NULLORDER if
427 *         an error has occured or if the start of string has been reached
428 * @exception thrown when retrieval of previous collation element fails.
429 */
previous(JNIEnv * env,jclass obj,jint address)430 static jint previous(JNIEnv *env, jclass obj, jint address) {
431 
432   UCollationElements *iterator = (UCollationElements *)(int)address;
433   UErrorCode status = U_ZERO_ERROR;
434   jint result = ucol_previous(iterator, &status);
435 
436    icu4jni_error(env, status);
437   return result;
438 }
439 
440 
441 /**
442 * Reset the collation elements to their initial state.
443 * This will move the 'cursor' to the beginning of the text.
444 * @param env JNI environment
445 * @param obj RuleBasedCollatorJNI object
446 * @param address of C collation element iterator to reset.
447 */
reset(JNIEnv * env,jclass obj,jint address)448 static void reset(JNIEnv *env, jclass obj, jint address) {
449 
450   UCollationElements *iterator = (UCollationElements *)(int)address;
451   ucol_reset(iterator);
452 }
453 
454 /**
455 * Thread safe cloning operation
456 * @param env JNI environment
457 * @param obj RuleBasedCollatorJNI object
458 * @param address address of C collator to be cloned
459 * @return address of the new clone
460 * @exception thrown when error occurs while cloning
461 */
safeClone(JNIEnv * env,jclass obj,jint address)462 static jint safeClone(JNIEnv *env, jclass obj, jint address) {
463 
464   const UCollator *collator = (const UCollator *)(int)address;
465   UErrorCode status = U_ZERO_ERROR;
466   jint result;
467   jint buffersize = U_COL_SAFECLONE_BUFFERSIZE;
468 
469   result = (jint)ucol_safeClone(collator, NULL, &buffersize, &status);
470 
471   if ( icu4jni_error(env, status) != FALSE) {
472     return 0;
473   }
474 
475   return result;
476 }
477 
478 /**
479 * Universal attribute setter.
480 * @param env JNI environment
481 * @param obj RuleBasedCollatorJNI object
482 * @param address address of the C collator
483 * @param type type of attribute to be set
484 * @param value attribute value
485 * @exception thrown when error occurs while setting attribute value
486 */
setAttribute(JNIEnv * env,jclass obj,jint address,jint type,jint value)487 static void setAttribute(JNIEnv *env, jclass obj, jint address,
488         jint type, jint value) {
489 
490   UCollator *collator = (UCollator *)(int)address;
491   UErrorCode status = U_ZERO_ERROR;
492   ucol_setAttribute(collator, (UColAttribute)type, (UColAttributeValue)value,
493                     &status);
494    icu4jni_error(env, status);
495 }
496 
497 /**
498 * Set the offset of the current source character.
499 * This is an offset into the text of the character to be processed.
500 * @param env JNI environment
501 * @param obj RuleBasedCollatorJNI object
502 * @param address of the C collation element iterator to set.
503 * @param offset The desired character offset.
504 * @exception thrown when offset setting fails
505 */
setOffset(JNIEnv * env,jclass obj,jint address,jint offset)506 static void setOffset(JNIEnv *env, jclass obj, jint address,
507         jint offset) {
508 
509   UCollationElements *iterator = (UCollationElements *)(int)address;
510   UErrorCode status = U_ZERO_ERROR;
511 
512   ucol_setOffset(iterator, offset, &status);
513    icu4jni_error(env, status);
514 }
515 
516 /**
517 * Set the text containing the collation elements.
518 * @param env JNI environment
519 * @param obj RuleBasedCollatorJNI object
520 * @param address of the C collation element iterator to be set
521 * @param source text containing the collation elements.
522 * @exception thrown when error occurs while setting offset
523 */
setText(JNIEnv * env,jclass obj,jint address,jstring source)524 static void setText(JNIEnv *env, jclass obj, jint address,
525         jstring source) {
526 
527   UCollationElements *iterator = (UCollationElements *)(int)address;
528   UErrorCode status = U_ZERO_ERROR;
529   int strlength = (*env)->GetStringLength(env, source);
530   const UChar *str = (const UChar *)(*env)->GetStringCritical(env, source, 0);
531 
532   ucol_setText(iterator, str, strlength, &status);
533   (*env)->ReleaseStringCritical(env, source, str);
534 
535    icu4jni_error(env, status);
536 }
537 
538 // BEGIN android-added
getAvailableLocalesImpl(JNIEnv * env,jclass clazz,jint index)539 static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
540 
541     const char * locale = ucol_getAvailable(index);
542 
543     return (*env)->NewStringUTF(env, locale);
544 
545 }
546 
getAvailableLocalesCountImpl(JNIEnv * env,jclass clazz)547 static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
548     return ucol_countAvailable();
549 }
550 // END android-added
551 
552 /*
553  * JNI registratio
554  */
555 static JNINativeMethod gMethods[] = {
556     /* name, signature, funcPtr */
557     // BEGIN android-added
558     { "getAvailableLocalesImpl", "(I)Ljava/lang/String;", (void*) getAvailableLocalesImpl },
559     { "getAvailableLocalesCountImpl", "()I", (void*) getAvailableLocalesCountImpl },
560     // END android-added
561     { "openCollator", "()I", (void*) openCollator__ },
562     { "openCollator", "(Ljava/lang/String;)I", (void*) openCollator__Ljava_lang_String_2 },
563     { "openCollatorFromRules", "(Ljava/lang/String;II)I", (void*) openCollatorFromRules },
564     { "closeCollator", "(I)V", (void*) closeCollator },
565     { "compare", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) compare },
566     { "getNormalization", "(I)I", (void*) getNormalization },
567     { "setNormalization", "(II)V", (void*) setNormalization },
568     { "getRules", "(I)Ljava/lang/String;", (void*) getRules },
569     { "getSortKey", "(ILjava/lang/String;)[B", (void*) getSortKey },
570     { "setAttribute", "(III)V", (void*) setAttribute },
571     { "getAttribute", "(II)I", (void*) getAttribute },
572     { "safeClone", "(I)I", (void*) safeClone },
573     { "getCollationElementIterator", "(ILjava/lang/String;)I", (void*) getCollationElementIterator },
574     { "hashCode", "(I)I", (void*) hashCode },
575     { "closeElements", "(I)V", (void*) closeElements },
576     { "reset", "(I)V", (void*) reset },
577     { "next", "(I)I", (void*) next },
578     { "previous", "(I)I", (void*) previous },
579     { "getMaxExpansion", "(II)I", (void*) getMaxExpansion },
580     { "setText", "(ILjava/lang/String;)V", (void*) setText },
581     { "getOffset", "(I)I", (void*) getOffset },
582     { "setOffset", "(II)V", (void*) setOffset }
583 };
584 
register_com_ibm_icu4jni_text_NativeCollator(JNIEnv * _env)585 int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv *_env) {
586     return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/text/NativeCollation",
587                 gMethods, NELEM(gMethods));
588 }
589 
590