1 /**
2 *******************************************************************************
3 * Copyright (C) 1996-2006, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 *
7 *
8 *******************************************************************************
9 */
10 /*
11 * @(#) icujniinterface.c 1.2 00/10/11
12 *
13 * (C) Copyright IBM Corp. 2000 - All Rights Reserved
14 * A JNI wrapper to ICU native converter Interface
15 * @author: Ram Viswanadha
16 */
17
18 #include "ConverterInterface.h"
19 #include "JNIHelp.h"
20 #include "AndroidSystemNatives.h"
21 #include "unicode/utypes.h" /* Basic ICU data types */
22 #include "unicode/ucnv.h" /* C Converter API */
23 #include "unicode/ustring.h" /* some more string functions*/
24 #include "unicode/ucnv_cb.h" /* for callback functions */
25 #include "unicode/uset.h" /* for contains function */
26 #include "ErrorCode.h"
27 #include <stdlib.h>
28 #include <string.h>
29
30 // BEGIN android-removed
31 // #define UTF_16BE "UTF-16BE"
32 // #define UTF_16 "UTF-16"
33 // END android-removed
34
35 /* Prototype of callback for substituting user settable sub chars */
36 void JNI_TO_U_CALLBACK_SUBSTITUTE
37 (const void *,UConverterToUnicodeArgs *,const char* ,int32_t ,UConverterCallbackReason ,UErrorCode * );
38
39 /**
40 * Opens the ICU converter
41 * @param env environment handle for JNI
42 * @param jClass handle for the class
43 * @param handle buffer to recieve ICU's converter address
44 * @param converterName name of the ICU converter
45 */
openConverter(JNIEnv * env,jclass jClass,jstring converterName)46 static jlong openConverter (JNIEnv *env, jclass jClass, jstring converterName) {
47
48 UConverter* conv=NULL;
49 UErrorCode errorCode = U_ZERO_ERROR;
50
51 const char* cnvName= (const char*) (*env)->GetStringUTFChars(env, converterName,NULL);
52 if(cnvName) {
53 int count = (*env)->GetStringUTFLength(env,converterName);
54
55 conv = ucnv_open(cnvName,&errorCode);
56 }
57 (*env)->ReleaseStringUTFChars(env, converterName,cnvName);
58
59 if (icu4jni_error(env, errorCode) != FALSE) {
60 return 0;
61 }
62
63 return (jlong) conv;
64 }
65
66 /**
67 * Closes the ICU converter
68 * @param env environment handle for JNI
69 * @param jClass handle for the class
70 * @param handle address of ICU converter
71 */
closeConverter(JNIEnv * env,jclass jClass,jlong handle)72 static void closeConverter (JNIEnv *env, jclass jClass, jlong handle) {
73
74 UConverter* cnv = (UConverter*)(long)handle;
75 if(cnv) {
76 // BEGIN android-added
77 // Free up any contexts created in setCallback[Encode|Decode]()
78 UConverterToUCallback toAction;
79 UConverterFromUCallback fromAction;
80 void * context1 = NULL;
81 void * context2 = NULL;
82 ucnv_getToUCallBack(cnv, &toAction, &context1);
83 ucnv_getFromUCallBack(cnv, &fromAction, &context2);
84 // END android-added
85 ucnv_close(cnv);
86 // BEGIN android-added
87 if (context1 != NULL) {
88 free(context1);
89 }
90 if (context2 != NULL) {
91 free(context2);
92 }
93 // END android-added
94 }
95 }
96
97 /**
98 * Sets the substution mode for from Unicode conversion. Currently only
99 * two modes are supported: substitute or report
100 * @param env environment handle for JNI
101 * @param jClass handle for the class
102 * @param handle address of ICU converter
103 * @param mode the mode to set
104 */
setSubstitutionModeCharToByte(JNIEnv * env,jclass jClass,jlong handle,jboolean mode)105 static jint setSubstitutionModeCharToByte (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
106
107 UConverter* conv = (UConverter*)(long)handle;
108 UErrorCode errorCode =U_ZERO_ERROR;
109
110 if(conv) {
111
112 UConverterFromUCallback fromUOldAction ;
113 void* fromUOldContext;
114 void* fromUNewContext=NULL;
115 if(mode) {
116
117 ucnv_setFromUCallBack(conv,
118 UCNV_FROM_U_CALLBACK_SUBSTITUTE,
119 fromUNewContext,
120 &fromUOldAction,
121 (const void**)&fromUOldContext,
122 &errorCode);
123
124 }
125 else{
126
127 ucnv_setFromUCallBack(conv,
128 UCNV_FROM_U_CALLBACK_STOP,
129 fromUNewContext,
130 &fromUOldAction,
131 (const void**)&fromUOldContext,
132 &errorCode);
133
134 }
135 return errorCode;
136 }
137 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
138 return errorCode;
139 }
140 /**
141 * Sets the substution mode for to Unicode conversion. Currently only
142 * two modes are supported: substitute or report
143 * @param env environment handle for JNI
144 * @param jClass handle for the class
145 * @param handle address of ICU converter
146 * @param mode the mode to set
147 */
setSubstitutionModeByteToChar(JNIEnv * env,jclass jClass,jlong handle,jboolean mode)148 static jint setSubstitutionModeByteToChar (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
149
150 UConverter* conv = (UConverter*)handle;
151 UErrorCode errorCode =U_ZERO_ERROR;
152
153 if(conv) {
154
155 UConverterToUCallback toUOldAction ;
156 void* toUOldContext;
157 void* toUNewContext=NULL;
158 if(mode) {
159
160 ucnv_setToUCallBack(conv,
161 UCNV_TO_U_CALLBACK_SUBSTITUTE,
162 toUNewContext,
163 &toUOldAction,
164 (const void**)&toUOldContext,
165 &errorCode);
166
167 }
168 else{
169
170 ucnv_setToUCallBack(conv,
171 UCNV_TO_U_CALLBACK_STOP,
172 toUNewContext,
173 &toUOldAction,
174 (const void**)&toUOldContext,
175 &errorCode);
176
177 }
178 return errorCode;
179 }
180 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
181 return errorCode;
182 }
183 /**
184 * Converts a buffer of Unicode code units to target encoding
185 * @param env environment handle for JNI
186 * @param jClass handle for the class
187 * @param handle address of ICU converter
188 * @param source buffer of Unicode chars to convert
189 * @param sourceEnd limit of the source buffer
190 * @param target buffer to recieve the converted bytes
191 * @param targetEnd the limit of the target buffer
192 * @param data buffer to recieve state of the current conversion
193 * @param flush boolean that specifies end of source input
194 */
convertCharToByte(JNIEnv * env,jclass jClass,jlong handle,jcharArray source,jint sourceEnd,jbyteArray target,jint targetEnd,jintArray data,jboolean flush)195 static jint convertCharToByte(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
196
197
198 UErrorCode errorCode =U_ZERO_ERROR;
199 UConverter* cnv = (UConverter*)handle;
200 if(cnv) {
201 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
202 if(myData) {
203 jint* sourceOffset = &myData[0];
204 jint* targetOffset = &myData[1];
205 const jchar* uSource =(jchar*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
206 if(uSource) {
207 jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
208 if(uTarget) {
209 const jchar* mySource = uSource+ *sourceOffset;
210 const UChar* mySourceLimit= uSource+sourceEnd;
211 char* cTarget=uTarget+ *targetOffset;
212 const char* cTargetLimit=uTarget+targetEnd;
213
214 ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
215 mySourceLimit,NULL,(UBool) flush, &errorCode);
216
217 *sourceOffset = (jint) (mySource - uSource)-*sourceOffset;
218 *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
219 if(U_FAILURE(errorCode)) {
220 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
221 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
222 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
223 return errorCode;
224 }
225 }else{
226 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
227 }
228 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
229 }else{
230 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
231 }
232 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
233 }else{
234 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
235 }
236 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
237 return errorCode;
238 }
239 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
240 return errorCode;
241 }
242
encode(JNIEnv * env,jclass jClass,jlong handle,jcharArray source,jint sourceEnd,jbyteArray target,jint targetEnd,jintArray data,jboolean flush)243 static jint encode(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
244
245 UErrorCode ec = convertCharToByte(env,jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
246 UConverter* cnv = (UConverter*)handle;
247 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
248
249 if(cnv && myData) {
250
251 UErrorCode errorCode = U_ZERO_ERROR;
252 myData[3] = ucnv_fromUCountPending(cnv, &errorCode);
253
254 if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND) {
255 int8_t count =32;
256 UChar invalidUChars[32];
257 ucnv_getInvalidUChars(cnv,invalidUChars,&count,&errorCode);
258
259 if(U_SUCCESS(errorCode)) {
260 myData[2] = count;
261 }
262 }
263 }
264 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
265 return ec;
266 }
267
268 /**
269 * Converts a buffer of encoded bytes to Unicode code units
270 * @param env environment handle for JNI
271 * @param jClass handle for the class
272 * @param handle address of ICU converter
273 * @param source buffer of Unicode chars to convert
274 * @param sourceEnd limit of the source buffer
275 * @param target buffer to recieve the converted bytes
276 * @param targetEnd the limit of the target buffer
277 * @param data buffer to recieve state of the current conversion
278 * @param flush boolean that specifies end of source input
279 */
convertByteToChar(JNIEnv * env,jclass jClass,jlong handle,jbyteArray source,jint sourceEnd,jcharArray target,jint targetEnd,jintArray data,jboolean flush)280 static jint convertByteToChar(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
281
282 UErrorCode errorCode =U_ZERO_ERROR;
283 UConverter* cnv = (UConverter*)handle;
284 if(cnv) {
285 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
286 if(myData) {
287 jint* sourceOffset = &myData[0];
288 jint* targetOffset = &myData[1];
289
290 const jbyte* uSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
291 if(uSource) {
292 jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
293 if(uTarget) {
294 const jbyte* mySource = uSource+ *sourceOffset;
295 const char* mySourceLimit= uSource+sourceEnd;
296 UChar* cTarget=uTarget+ *targetOffset;
297 const UChar* cTargetLimit=uTarget+targetEnd;
298
299 ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
300 mySourceLimit,NULL,(UBool) flush, &errorCode);
301
302 *sourceOffset = mySource - uSource - *sourceOffset ;
303 *targetOffset = cTarget - uTarget - *targetOffset;
304 if(U_FAILURE(errorCode)) {
305 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
306 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
307 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
308 return errorCode;
309 }
310 }else{
311 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
312 }
313 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
314 }else{
315 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
316 }
317 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
318 }else{
319 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
320 }
321 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
322 return errorCode;
323 }
324 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
325 return errorCode;
326 }
327
decode(JNIEnv * env,jclass jClass,jlong handle,jbyteArray source,jint sourceEnd,jcharArray target,jint targetEnd,jintArray data,jboolean flush)328 static jint decode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
329
330 jint ec = convertByteToChar(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
331
332 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
333 UConverter* cnv = (UConverter*)handle;
334
335 if(myData && cnv) {
336 UErrorCode errorCode = U_ZERO_ERROR;
337 myData[3] = ucnv_toUCountPending(cnv, &errorCode);
338
339 if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND ) {
340 char invalidChars[32] = {'\0'};
341 int8_t len = 32;
342 ucnv_getInvalidChars(cnv,invalidChars,&len,&errorCode);
343
344 if(U_SUCCESS(errorCode)) {
345 myData[2] = len;
346 }
347 }
348 }
349 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
350 return ec;
351 }
resetByteToChar(JNIEnv * env,jclass jClass,jlong handle)352 static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) {
353
354 UConverter* cnv = (UConverter*)handle;
355 if(cnv) {
356 ucnv_resetToUnicode(cnv);
357 }
358 }
359
resetCharToByte(JNIEnv * env,jclass jClass,jlong handle)360 static void resetCharToByte(JNIEnv *env, jclass jClass, jlong handle) {
361
362 UConverter* cnv = (UConverter*)handle;
363 if(cnv) {
364 ucnv_resetFromUnicode(cnv);
365 }
366
367 }
368
countInvalidBytes(JNIEnv * env,jclass jClass,jlong handle,jintArray length)369 static jint countInvalidBytes (JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
370
371 UConverter* cnv = (UConverter*)handle;
372 UErrorCode errorCode = U_ZERO_ERROR;
373 if(cnv) {
374 char invalidChars[32];
375
376 jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
377 if(len) {
378 ucnv_getInvalidChars(cnv,invalidChars,(int8_t*)len,&errorCode);
379 }
380 (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
381 return errorCode;
382 }
383 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
384 return errorCode;
385
386 }
387
388
countInvalidChars(JNIEnv * env,jclass jClass,jlong handle,jintArray length)389 static jint countInvalidChars(JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
390
391 UErrorCode errorCode =U_ZERO_ERROR;
392 UConverter* cnv = (UConverter*)handle;
393 UChar invalidUChars[32];
394 if(cnv) {
395 jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
396 if(len) {
397 ucnv_getInvalidUChars(cnv,invalidUChars,(int8_t*)len,&errorCode);
398 }
399 (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
400 return errorCode;
401 }
402 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
403 return errorCode;
404
405 }
406
getMaxBytesPerChar(JNIEnv * env,jclass jClass,jlong handle)407 static jint getMaxBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
408
409 UConverter* cnv = (UConverter*)handle;
410 if(cnv) {
411 return (jint)ucnv_getMaxCharSize(cnv);
412 }
413 return -1;
414 }
415
getMinBytesPerChar(JNIEnv * env,jclass jClass,jlong handle)416 static jint getMinBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
417
418 UConverter* cnv = (UConverter*)handle;
419 if(cnv) {
420 return (jint)ucnv_getMinCharSize(cnv);
421 }
422 return -1;
423 }
getAveBytesPerChar(JNIEnv * env,jclass jClass,jlong handle)424 static jfloat getAveBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
425
426 UConverter* cnv = (UConverter*)handle;
427 if(cnv) {
428 jfloat max = (jfloat)ucnv_getMaxCharSize(cnv);
429 jfloat min = (jfloat)ucnv_getMinCharSize(cnv);
430 return (jfloat) ( (max+min)/2 );
431 }
432 return -1;
433 }
flushByteToChar(JNIEnv * env,jclass jClass,jlong handle,jcharArray target,jint targetEnd,jintArray data)434 static jint flushByteToChar(JNIEnv *env, jclass jClass,jlong handle, jcharArray target, jint targetEnd, jintArray data) {
435
436 UErrorCode errorCode =U_ZERO_ERROR;
437 UConverter* cnv = (UConverter*)handle;
438 if(cnv) {
439 jbyte source ='\0';
440 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
441 if(myData) {
442 jint* targetOffset = &myData[1];
443 jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
444 if(uTarget) {
445 const jbyte* mySource =&source;
446 const char* mySourceLimit=&source;
447 UChar* cTarget=uTarget+ *targetOffset;
448 const UChar* cTargetLimit=uTarget+targetEnd;
449
450 ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
451 mySourceLimit,NULL,TRUE, &errorCode);
452
453
454 *targetOffset = (jint) ((jchar*)cTarget - uTarget)- *targetOffset;
455 if(U_FAILURE(errorCode)) {
456 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
457 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
458 return errorCode;
459 }
460 }else{
461 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
462 }
463 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
464
465 }else{
466 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
467 }
468 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
469 return errorCode;
470 }
471 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
472 return errorCode;
473 }
474
flushCharToByte(JNIEnv * env,jclass jClass,jlong handle,jbyteArray target,jint targetEnd,jintArray data)475 static jint flushCharToByte (JNIEnv *env, jclass jClass, jlong handle, jbyteArray target, jint targetEnd, jintArray data) {
476
477 UErrorCode errorCode =U_ZERO_ERROR;
478 UConverter* cnv = (UConverter*)handle;
479 jchar source = '\0';
480 if(cnv) {
481 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
482 if(myData) {
483 jint* targetOffset = &myData[1];
484 jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
485 if(uTarget) {
486 const jchar* mySource = &source;
487 const UChar* mySourceLimit= &source;
488 char* cTarget=uTarget+ *targetOffset;
489 const char* cTargetLimit=uTarget+targetEnd;
490
491 ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
492 mySourceLimit,NULL,TRUE, &errorCode);
493
494
495 *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
496 if(U_FAILURE(errorCode)) {
497 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
498
499 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
500 return errorCode;
501 }
502 }else{
503 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
504 }
505 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
506 }else{
507 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
508 }
509 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
510 return errorCode;
511 }
512 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
513 return errorCode;
514 }
515
toChars(const UChar * us,char * cs,int32_t length)516 void toChars(const UChar* us, char* cs, int32_t length) {
517 UChar u;
518 while(length>0) {
519 u=*us++;
520 *cs++=(char)u;
521 --length;
522 }
523 }
setSubstitutionBytes(JNIEnv * env,jclass jClass,jlong handle,jbyteArray subChars,jint length)524 static jint setSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle, jbyteArray subChars, jint length) {
525
526 UConverter* cnv = (UConverter*) handle;
527 UErrorCode errorCode = U_ZERO_ERROR;
528 if(cnv) {
529 jbyte* u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
530 if(u_subChars) {
531 char* mySubChars= (char*)malloc(sizeof(char)*length);
532 toChars((UChar*)u_subChars,&mySubChars[0],length);
533 ucnv_setSubstChars(cnv,mySubChars, (char)length,&errorCode);
534 if(U_FAILURE(errorCode)) {
535 (*env)->ReleasePrimitiveArrayCritical(env,subChars,mySubChars,0);
536 return errorCode;
537 }
538 free(mySubChars);
539 }
540 else{
541 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
542 }
543 (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0);
544 return errorCode;
545 }
546 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
547 return errorCode;
548 }
549
550
551 #define VALUE_STRING_LENGTH 32
552
553 typedef struct{
554 int length;
555 UChar subChars[256];
556 UBool stopOnIllegal;
557 }SubCharStruct;
558
559
560 static UErrorCode
setToUCallbackSubs(UConverter * cnv,UChar * subChars,int32_t length,UBool stopOnIllegal)561 setToUCallbackSubs(UConverter* cnv,UChar* subChars, int32_t length,UBool stopOnIllegal ) {
562 SubCharStruct* substitutionCharS = (SubCharStruct*) malloc(sizeof(SubCharStruct));
563 UErrorCode errorCode = U_ZERO_ERROR;
564 if(substitutionCharS) {
565 UConverterToUCallback toUOldAction;
566 void* toUOldContext=NULL;
567 void* toUNewContext=NULL ;
568 if(subChars) {
569 u_strncpy(substitutionCharS->subChars,subChars,length);
570 }else{
571 substitutionCharS->subChars[length++] =0xFFFD;
572 }
573 substitutionCharS->subChars[length]=0;
574 substitutionCharS->length = length;
575 substitutionCharS->stopOnIllegal = stopOnIllegal;
576 toUNewContext = substitutionCharS;
577
578 ucnv_setToUCallBack(cnv,
579 JNI_TO_U_CALLBACK_SUBSTITUTE,
580 toUNewContext,
581 &toUOldAction,
582 (const void**)&toUOldContext,
583 &errorCode);
584
585 if(toUOldContext) {
586 SubCharStruct* temp = (SubCharStruct*) toUOldContext;
587 free(temp);
588 }
589
590 return errorCode;
591 }
592 return U_MEMORY_ALLOCATION_ERROR;
593 }
setSubstitutionChars(JNIEnv * env,jclass jClass,jlong handle,jcharArray subChars,jint length)594 static jint setSubstitutionChars(JNIEnv *env, jclass jClass, jlong handle, jcharArray subChars, jint length) {
595
596 UErrorCode errorCode = U_ZERO_ERROR;
597 UConverter* cnv = (UConverter*) handle;
598 jchar* u_subChars=NULL;
599 if(cnv) {
600 if(subChars) {
601 int len = (*env)->GetArrayLength(env,subChars);
602 u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
603 if(u_subChars) {
604 errorCode = setToUCallbackSubs(cnv,u_subChars,len,FALSE);
605 }else{
606 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
607 }
608 (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0);
609 return errorCode;
610 }
611 }
612 return U_ILLEGAL_ARGUMENT_ERROR;
613 }
614
615
JNI_TO_U_CALLBACK_SUBSTITUTE(const void * context,UConverterToUnicodeArgs * toArgs,const char * codeUnits,int32_t length,UConverterCallbackReason reason,UErrorCode * err)616 void JNI_TO_U_CALLBACK_SUBSTITUTE( const void *context, UConverterToUnicodeArgs *toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode * err) {
617
618 if(context) {
619 SubCharStruct* temp = (SubCharStruct*)context;
620 if( temp) {
621 if(temp->stopOnIllegal==FALSE) {
622 if (reason > UCNV_IRREGULAR) {
623 return;
624 }
625 /* reset the error */
626 *err = U_ZERO_ERROR;
627 ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
628 }else{
629 if(reason != UCNV_UNASSIGNED) {
630 /* the caller must have set
631 * the error code accordingly
632 */
633 return;
634 }else{
635 *err = U_ZERO_ERROR;
636 ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
637 return;
638 }
639 }
640 }
641 }
642 return;
643 }
644
canEncode(JNIEnv * env,jclass jClass,jlong handle,jint codeUnit)645 static jboolean canEncode(JNIEnv *env, jclass jClass, jlong handle, jint codeUnit) {
646
647 UErrorCode errorCode =U_ZERO_ERROR;
648 UConverter* cnv = (UConverter*)handle;
649 if(cnv) {
650 UChar source[3];
651 UChar *mySource=source;
652 const UChar* sourceLimit = (codeUnit<0x010000) ? &source[1] : &source[2];
653 char target[5];
654 char *myTarget = target;
655 const char* targetLimit = &target[4];
656 int i=0;
657 UTF_APPEND_CHAR(&source[0],i,2,codeUnit);
658
659 ucnv_fromUnicode(cnv,&myTarget,targetLimit,
660 (const UChar**)&mySource,
661 sourceLimit,NULL, TRUE,&errorCode);
662
663 if(U_SUCCESS(errorCode)) {
664 return (jboolean)TRUE;
665 }
666 }
667 return (jboolean)FALSE;
668 }
669
670
canDecode(JNIEnv * env,jclass jClass,jlong handle,jbyteArray source)671 static jboolean canDecode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source) {
672
673 UErrorCode errorCode =U_ZERO_ERROR;
674 UConverter* cnv = (UConverter*)handle;
675 if(cnv) {
676 jint len = (*env)->GetArrayLength(env,source);
677 jbyte* cSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
678 if(cSource) {
679 const jbyte* cSourceLimit = cSource+len;
680
681 /* Assume that we need at most twice the length of source */
682 UChar* target = (UChar*) malloc(sizeof(UChar)* (len<<1));
683 UChar* targetLimit = target + (len<<1);
684 if(target) {
685 ucnv_toUnicode(cnv,&target,targetLimit,
686 (const char**)&cSource,
687 cSourceLimit,NULL, TRUE,&errorCode);
688
689 if(U_SUCCESS(errorCode)) {
690 free(target);
691 (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);
692 return (jboolean)TRUE;
693 }
694 }
695 free(target);
696 }
697 (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);
698 }
699 return (jboolean)FALSE;
700 }
701
countAvailable(JNIEnv * env,jclass jClass)702 static jint countAvailable(JNIEnv *env, jclass jClass) {
703 return ucnv_countAvailable();
704 }
705
copyString(char * dest,int32_t destCapacity,int32_t startIndex,const char * src,UErrorCode * status)706 int32_t copyString(char* dest, int32_t destCapacity, int32_t startIndex,
707 const char* src, UErrorCode* status) {
708 int32_t srcLen = 0, i=0;
709 if(U_FAILURE(*status)) {
710 return 0;
711 }
712 if(dest == NULL || src == NULL || destCapacity < startIndex) {
713 *status = U_ILLEGAL_ARGUMENT_ERROR;
714 return 0;
715 }
716 srcLen = strlen(src);
717 if(srcLen >= destCapacity) {
718 *status = U_BUFFER_OVERFLOW_ERROR;
719 return 0;
720 }
721 for(i=0; i < srcLen; i++) {
722 dest[startIndex++] = src[i];
723 }
724 /* null terminate the buffer */
725 dest[startIndex] = 0; /* no bounds check already made sure that we have enough room */
726 return startIndex;
727 }
728
getJavaCanonicalName1(const char * icuCanonicalName,char * canonicalName,int32_t capacity,UErrorCode * status)729 int32_t getJavaCanonicalName1(const char* icuCanonicalName,
730 char* canonicalName, int32_t capacity,
731 UErrorCode* status) {
732 /*
733 If a charset listed in the IANA Charset Registry is supported by an implementation
734 of the Java platform then its canonical name must be the name listed in the registry.
735 Many charsets are given more than one name in the registry, in which case the registry
736 identifies one of the names as MIME-preferred. If a charset has more than one registry
737 name then its canonical name must be the MIME-preferred name and the other names in
738 the registry must be valid aliases. If a supported charset is not listed in the IANA
739 registry then its canonical name must begin with one of the strings "X-" or "x-".
740 */
741 int32_t retLen = 0;
742 const char* cName = NULL;
743 /* find out the alias with MIME tag */
744 if((cName =ucnv_getStandardName(icuCanonicalName, "MIME", status)) != NULL) {
745 retLen = copyString(canonicalName, capacity, 0, cName, status);
746 /* find out the alias with IANA tag */
747 }else if((cName =ucnv_getStandardName(icuCanonicalName, "IANA", status)) != NULL) {
748 retLen = copyString(canonicalName, capacity, 0, cName, status);
749 }else {
750 /*
751 check to see if an alias already exists with x- prefix, if yes then
752 make that the canonical name
753 */
754 int32_t aliasNum = ucnv_countAliases(icuCanonicalName,status);
755 int32_t i=0;
756 const char* name;
757 for(i=0;i<aliasNum;i++) {
758 name = ucnv_getAlias(icuCanonicalName,(uint16_t)i, status);
759 if(name != NULL && name[0]=='x' && name[1]=='-') {
760 retLen = copyString(canonicalName, capacity, 0, name, status);
761 break;
762 }
763 }
764 /* last resort just append x- to any of the alias and
765 make it the canonical name */
766 if(retLen == 0 && U_SUCCESS(*status)) {
767 name = ucnv_getStandardName(icuCanonicalName, "UTR22", status);
768 if(name == NULL && strchr(icuCanonicalName, ',')!= NULL) {
769 name = ucnv_getAlias(icuCanonicalName, 1, status);
770 if(*status == U_INDEX_OUTOFBOUNDS_ERROR) {
771 *status = U_ZERO_ERROR;
772 }
773 }
774 /* if there is no UTR22 canonical name .. then just return itself*/
775 if(name == NULL) {
776 name = icuCanonicalName;
777 }
778 if(capacity >= 2) {
779 strcpy(canonicalName,"x-");
780 }
781 retLen = copyString(canonicalName, capacity, 2, name, status);
782 }
783 }
784 return retLen;
785 }
786
getAvailable(JNIEnv * env,jclass jClass)787 static jobjectArray getAvailable(JNIEnv *env, jclass jClass) {
788
789 jobjectArray ret;
790 int32_t i = 0;
791 int32_t num = ucnv_countAvailable();
792 UErrorCode error = U_ZERO_ERROR;
793 const char* name =NULL;
794 char canonicalName[256]={0};
795 ret= (jobjectArray)(*env)->NewObjectArray( env,num,
796 (*env)->FindClass(env,"java/lang/String"),
797 (*env)->NewStringUTF(env,""));
798
799 for(i=0;i<num;i++) {
800 name = ucnv_getAvailableName(i);
801 getJavaCanonicalName1(name, canonicalName, 256, &error);
802 #if DEBUG
803 if(U_FAILURE(error)) {
804 printf("An error occurred retrieving index %i. Error: %s. \n", i, u_errorName(error));
805 }
806
807 printf("canonical name for %s\n", canonicalName);
808 #endif
809 // BEGIN android-changed
810 jstring canonName = (*env)->NewStringUTF(env,canonicalName);
811 (*env)->SetObjectArrayElement(env,ret,i,canonName);
812 (*env)->DeleteLocalRef(env, canonName);
813 // END android-changed
814 /*printf("canonical name : %s at %i\n", name,i); */
815 canonicalName[0]='\0';/* nul terminate */
816 }
817 return (ret);
818 }
819
countAliases(JNIEnv * env,jclass jClass,jstring enc)820 static jint countAliases(JNIEnv *env, jclass jClass,jstring enc) {
821
822 UErrorCode error = U_ZERO_ERROR;
823 jint num =0;
824 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
825
826 if(encName) {
827 num = ucnv_countAliases(encName,&error);
828 }
829
830 (*env)->ReleaseStringUTFChars(env,enc,encName);
831
832 return num;
833 }
834
835
getAliases(JNIEnv * env,jclass jClass,jstring enc)836 static jobjectArray getAliases(JNIEnv *env, jclass jClass, jstring enc) {
837
838 jobjectArray ret=NULL;
839 int32_t aliasNum = 0;
840 UErrorCode error = U_ZERO_ERROR;
841 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
842 int i=0;
843 int j=0;
844 const char* aliasArray[50];
845 // BEGIN android-removed
846 // int32_t utf16AliasNum = 0;
847 // END android-removed
848
849
850 if(encName) {
851 const char* myEncName = encName;
852 aliasNum = ucnv_countAliases(myEncName,&error);
853
854 // BEGIN android-removed
855 // /* special case for UTF-16. In java UTF-16 is always BE*/
856 // if(strcmp(myEncName, UTF_16BE)==0) {
857 // utf16AliasNum=ucnv_countAliases(UTF_16,&error);
858 // }
859 // END android-removed
860
861 if(aliasNum==0 && encName[0] == 0x78 /*x*/ && encName[1]== 0x2d /*-*/) {
862 myEncName = encName+2;
863 aliasNum = ucnv_countAliases(myEncName,&error);
864 }
865 if(U_SUCCESS(error)) {
866 for(i=0,j=0;i<aliasNum;i++) {
867 const char* name = ucnv_getAlias(myEncName,(uint16_t)i,&error);
868 if(strchr(name,'+')==0 && strchr(name,',')==0) {
869 aliasArray[j++]= name;
870 }
871 }
872
873 // BEGIN android-removed
874 // if(utf16AliasNum>0) {
875 // for(i=0;i<utf16AliasNum;i++) {
876 // const char* name = ucnv_getAlias(UTF_16,(uint16_t)i,&error);
877 // if(strchr(name,'+')==0 && strchr(name,',')==0) {
878 // aliasArray[j++]= name;
879 // }
880 // }
881 // }
882 // END android-removed
883
884 ret = (jobjectArray)(*env)->NewObjectArray(env,j,
885 (*env)->FindClass(env,"java/lang/String"),
886 (*env)->NewStringUTF(env,""));
887 for(;--j>=0;) {
888 // BEGIN android-changed
889 jstring alias = (*env)->NewStringUTF(env, aliasArray[j]);
890 (*env)->SetObjectArrayElement(env, ret, j, alias);
891 (*env)->DeleteLocalRef(env, alias);
892 // END android-changed
893 }
894 }
895 }
896 (*env)->ReleaseStringUTFChars(env,enc,encName);
897
898 return (ret);
899 }
900
getCanonicalName(JNIEnv * env,jclass jClass,jstring enc)901 static jstring getCanonicalName(JNIEnv *env, jclass jClass,jstring enc) {
902
903 UErrorCode error = U_ZERO_ERROR;
904 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
905 const char* canonicalName = "";
906 // BEGIN android-changed
907 jstring ret = NULL;
908 if(encName) {
909 canonicalName = ucnv_getAlias(encName,0,&error);
910 if(canonicalName !=NULL && strstr(canonicalName,",")!=0) {
911 canonicalName = ucnv_getAlias(canonicalName,1,&error);
912 }
913 ret = ((*env)->NewStringUTF(env, canonicalName));
914 (*env)->ReleaseStringUTFChars(env,enc,encName);
915 }
916 // END android-changed
917 return ret;
918 }
919
getICUCanonicalName(JNIEnv * env,jclass jClass,jstring enc)920 static jstring getICUCanonicalName(JNIEnv *env, jclass jClass, jstring enc) {
921
922 UErrorCode error = U_ZERO_ERROR;
923 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
924 const char* canonicalName = NULL;
925 jstring ret = NULL;
926 if(encName) {
927 // BEGIN android-removed
928 // if(strcmp(encName,"UTF-16")==0) {
929 // ret = ((*env)->NewStringUTF(env,UTF_16BE));
930 // }else
931 // END android-removed
932 if((canonicalName = ucnv_getCanonicalName(encName, "MIME", &error))!=NULL) {
933 ret = ((*env)->NewStringUTF(env, canonicalName));
934 }else if((canonicalName = ucnv_getCanonicalName(encName, "IANA", &error))!=NULL) {
935 ret = ((*env)->NewStringUTF(env, canonicalName));
936 }else if((canonicalName = ucnv_getCanonicalName(encName, "", &error))!=NULL) {
937 ret = ((*env)->NewStringUTF(env, canonicalName));
938 }else if((canonicalName = ucnv_getAlias(encName, 0, &error)) != NULL) {
939 /* we have some aliases in the form x-blah .. match those first */
940 ret = ((*env)->NewStringUTF(env, canonicalName));
941 }else if( ret ==NULL && strstr(encName, "x-") == encName) {
942 /* check if the converter can be opened with the encName given */
943 UConverter* conv = NULL;
944 error = U_ZERO_ERROR;
945 conv = ucnv_open(encName+2, &error);
946 if(conv!=NULL) {
947 ret = ((*env)->NewStringUTF(env, encName+2));
948 }else{
949 /* unsupported encoding */
950 ret = ((*env)->NewStringUTF(env, ""));
951 }
952 ucnv_close(conv);
953 }else{
954 /* unsupported encoding */
955 ret = ((*env)->NewStringUTF(env, ""));
956 }
957 }
958 (*env)->ReleaseStringUTFChars(env,enc,encName);
959 return ret;
960 }
961
getJavaCanonicalName2(JNIEnv * env,jclass jClass,jstring icuCanonName)962 static jstring getJavaCanonicalName2(JNIEnv *env, jclass jClass, jstring icuCanonName) {
963 /*
964 If a charset listed in the IANA Charset Registry is supported by an implementation
965 of the Java platform then its canonical name must be the name listed in the registry.
966 Many charsets are given more than one name in the registry, in which case the registry
967 identifies one of the names as MIME-preferred. If a charset has more than one registry
968 name then its canonical name must be the MIME-preferred name and the other names in
969 the registry must be valid aliases. If a supported charset is not listed in the IANA
970 registry then its canonical name must begin with one of the strings "X-" or "x-".
971 */
972 UErrorCode error = U_ZERO_ERROR;
973 const char* icuCanonicalName = (*env)->GetStringUTFChars(env,icuCanonName,NULL);
974 char cName[UCNV_MAX_CONVERTER_NAME_LENGTH] = {0};
975 jstring ret;
976 if(icuCanonicalName && icuCanonicalName[0] != 0) {
977 getJavaCanonicalName1(icuCanonicalName, cName, UCNV_MAX_CONVERTER_NAME_LENGTH, &error);
978 }
979 ret = ((*env)->NewStringUTF(env, cName));
980 (*env)->ReleaseStringUTFChars(env,icuCanonName,icuCanonicalName);
981 return ret;
982 }
983
984 #define SUBS_ARRAY_CAPACITY 256
985 typedef struct{
986 int length;
987 char subChars[SUBS_ARRAY_CAPACITY];
988 UConverterFromUCallback onUnmappableInput;
989 UConverterFromUCallback onMalformedInput;
990 }EncoderCallbackContext;
991
CHARSET_ENCODER_CALLBACK(const void * context,UConverterFromUnicodeArgs * fromArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * status)992 void CHARSET_ENCODER_CALLBACK(const void *context,
993 UConverterFromUnicodeArgs *fromArgs,
994 const UChar* codeUnits,
995 int32_t length,
996 UChar32 codePoint,
997 UConverterCallbackReason reason,
998 UErrorCode * status) {
999 if(context) {
1000 EncoderCallbackContext* ctx = (EncoderCallbackContext*)context;
1001
1002 if(ctx) {
1003 UConverterFromUCallback realCB = NULL;
1004 switch(reason) {
1005 case UCNV_UNASSIGNED:
1006 realCB = ctx->onUnmappableInput;
1007 break;
1008 case UCNV_ILLEGAL:/*malformed input*/
1009 case UCNV_IRREGULAR:/*malformed input*/
1010 realCB = ctx->onMalformedInput;
1011 break;
1012 /*
1013 case UCNV_RESET:
1014 ucnv_resetToUnicode(args->converter);
1015 break;
1016 case UCNV_CLOSE:
1017 ucnv_close(args->converter);
1018 break;
1019 case UCNV_CLONE:
1020 ucnv_clone(args->clone);
1021 */
1022 default:
1023 *status = U_ILLEGAL_ARGUMENT_ERROR;
1024 return;
1025 }
1026 if(realCB==NULL) {
1027 *status = U_INTERNAL_PROGRAM_ERROR;
1028 }
1029 realCB(context, fromArgs, codeUnits, length, codePoint, reason, status);
1030 }
1031 }
1032 }
1033
JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void * context,UConverterFromUnicodeArgs * fromArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * err)1034 void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void *context,
1035 UConverterFromUnicodeArgs *fromArgs,
1036 const UChar* codeUnits,
1037 int32_t length,
1038 UChar32 codePoint,
1039 UConverterCallbackReason reason,
1040 UErrorCode * err) {
1041 if(context) {
1042 EncoderCallbackContext* temp = (EncoderCallbackContext*)context;
1043 *err = U_ZERO_ERROR;
1044 ucnv_cbFromUWriteBytes(fromArgs,temp->subChars ,temp->length , 0, err);
1045 }
1046 return;
1047 }
1048
getFromUCallback(int32_t mode)1049 UConverterFromUCallback getFromUCallback(int32_t mode) {
1050 switch(mode) {
1051 default: /* falls through */
1052 case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
1053 return UCNV_FROM_U_CALLBACK_STOP;
1054 case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
1055 return UCNV_FROM_U_CALLBACK_SKIP ;
1056 case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
1057 return JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER;
1058 }
1059 }
1060
setCallbackEncode(JNIEnv * env,jclass jClass,jlong handle,jint onMalformedInput,jint onUnmappableInput,jbyteArray subChars,jint length)1061 static jint setCallbackEncode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) {
1062
1063 UConverter* conv = (UConverter*)handle;
1064 UErrorCode errorCode =U_ZERO_ERROR;
1065
1066 if(conv) {
1067
1068 UConverterFromUCallback fromUOldAction = NULL;
1069 void* fromUOldContext = NULL;
1070 EncoderCallbackContext* fromUNewContext=NULL;
1071 UConverterFromUCallback fromUNewAction=NULL;
1072 jbyte* sub = (jbyte*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
1073 ucnv_getFromUCallBack(conv, &fromUOldAction, &fromUOldContext);
1074
1075 /* fromUOldContext can only be DecodeCallbackContext since
1076 the converter created is private data for the decoder
1077 and callbacks can only be set via this method!
1078 */
1079 if(fromUOldContext==NULL) {
1080 fromUNewContext = (EncoderCallbackContext*) malloc(sizeof(EncoderCallbackContext));
1081 fromUNewAction = CHARSET_ENCODER_CALLBACK;
1082 }else{
1083 fromUNewContext = fromUOldContext;
1084 fromUNewAction = fromUOldAction;
1085 fromUOldAction = NULL;
1086 fromUOldContext = NULL;
1087 }
1088 fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput);
1089 fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput);
1090 // BEGIN android-changed
1091 if(sub!=NULL) {
1092 fromUNewContext->length = length;
1093 strncpy(fromUNewContext->subChars, sub, length);
1094 (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0);
1095 }else{
1096 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
1097 }
1098 // END android-changed
1099
1100 ucnv_setFromUCallBack(conv,
1101 fromUNewAction,
1102 fromUNewContext,
1103 &fromUOldAction,
1104 (const void**)&fromUOldContext,
1105 &errorCode);
1106
1107
1108 return errorCode;
1109 }
1110 return U_ILLEGAL_ARGUMENT_ERROR;
1111 }
1112
1113 typedef struct{
1114 int length;
1115 UChar subUChars[256];
1116 UConverterToUCallback onUnmappableInput;
1117 UConverterToUCallback onMalformedInput;
1118 }DecoderCallbackContext;
1119
JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void * context,UConverterToUnicodeArgs * toArgs,const char * codeUnits,int32_t length,UConverterCallbackReason reason,UErrorCode * err)1120 void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void *context,
1121 UConverterToUnicodeArgs *toArgs,
1122 const char* codeUnits,
1123 int32_t length,
1124 UConverterCallbackReason reason,
1125 UErrorCode * err) {
1126 if(context) {
1127 DecoderCallbackContext* temp = (DecoderCallbackContext*)context;
1128 *err = U_ZERO_ERROR;
1129 ucnv_cbToUWriteUChars(toArgs,temp->subUChars ,temp->length , 0, err);
1130 }
1131 return;
1132 }
1133
getToUCallback(int32_t mode)1134 UConverterToUCallback getToUCallback(int32_t mode) {
1135 switch(mode) {
1136 default: /* falls through */
1137 case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
1138 return UCNV_TO_U_CALLBACK_STOP;
1139 case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
1140 return UCNV_TO_U_CALLBACK_SKIP ;
1141 case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
1142 return JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER;
1143 }
1144 }
1145
CHARSET_DECODER_CALLBACK(const void * context,UConverterToUnicodeArgs * args,const char * codeUnits,int32_t length,UConverterCallbackReason reason,UErrorCode * status)1146 void CHARSET_DECODER_CALLBACK(const void *context,
1147 UConverterToUnicodeArgs *args,
1148 const char* codeUnits,
1149 int32_t length,
1150 UConverterCallbackReason reason,
1151 UErrorCode *status ) {
1152
1153 if(context) {
1154 DecoderCallbackContext* ctx = (DecoderCallbackContext*)context;
1155
1156 if(ctx) {
1157 UConverterToUCallback realCB = NULL;
1158 switch(reason) {
1159 case UCNV_UNASSIGNED:
1160 realCB = ctx->onUnmappableInput;
1161 break;
1162 case UCNV_ILLEGAL:/*malformed input*/
1163 case UCNV_IRREGULAR:/*malformed input*/
1164 realCB = ctx->onMalformedInput;
1165 break;
1166 /*
1167 case UCNV_RESET:
1168 ucnv_resetToUnicode(args->converter);
1169 break;
1170 case UCNV_CLOSE:
1171 ucnv_close(args->converter);
1172 break;
1173 case UCNV_CLONE:
1174 ucnv_clone(args->clone);
1175 */
1176 default:
1177 *status = U_ILLEGAL_ARGUMENT_ERROR;
1178 return;
1179 }
1180 if(realCB==NULL) {
1181 *status = U_INTERNAL_PROGRAM_ERROR;
1182 }
1183 realCB(context, args, codeUnits, length, reason, status);
1184 }
1185 }
1186 }
1187
setCallbackDecode(JNIEnv * env,jclass jClass,jlong handle,jint onMalformedInput,jint onUnmappableInput,jcharArray subChars,jint length)1188 static jint setCallbackDecode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) {
1189
1190 UConverter* conv = (UConverter*)handle;
1191 UErrorCode errorCode =U_ZERO_ERROR;
1192 if(conv) {
1193
1194 UConverterToUCallback toUOldAction ;
1195 void* toUOldContext;
1196 DecoderCallbackContext* toUNewContext = NULL;
1197 UConverterToUCallback toUNewAction = NULL;
1198 jchar* sub = (jchar*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
1199
1200 ucnv_getToUCallBack(conv, &toUOldAction, &toUOldContext);
1201
1202 /* toUOldContext can only be DecodeCallbackContext since
1203 the converter created is private data for the decoder
1204 and callbacks can only be set via this method!
1205 */
1206 if(toUOldContext==NULL) {
1207 toUNewContext = (DecoderCallbackContext*) malloc(sizeof(DecoderCallbackContext));
1208 toUNewAction = CHARSET_DECODER_CALLBACK;
1209 }else{
1210 toUNewContext = toUOldContext;
1211 toUNewAction = toUOldAction;
1212 toUOldAction = NULL;
1213 toUOldContext = NULL;
1214 }
1215 toUNewContext->onMalformedInput = getToUCallback(onMalformedInput);
1216 toUNewContext->onUnmappableInput = getToUCallback(onUnmappableInput);
1217 // BEGIN android-changed
1218 if(sub!=NULL) {
1219 toUNewContext->length = length;
1220 u_strncpy(toUNewContext->subUChars, sub, length);
1221 (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0);
1222 }else{
1223 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
1224 }
1225 // END android-changed
1226 ucnv_setToUCallBack(conv,
1227 toUNewAction,
1228 toUNewContext,
1229 &toUOldAction,
1230 (const void**)&toUOldContext,
1231 &errorCode);
1232
1233 return errorCode;
1234 }
1235 return U_ILLEGAL_ARGUMENT_ERROR;
1236 }
1237
safeClone(JNIEnv * env,jclass jClass,jlong src)1238 static jlong safeClone(JNIEnv *env, jclass jClass, jlong src) {
1239
1240 UErrorCode status = U_ZERO_ERROR;
1241
1242 jint buffersize = U_CNV_SAFECLONE_BUFFERSIZE;
1243
1244 UConverter* conv=NULL;
1245 UErrorCode errorCode = U_ZERO_ERROR;
1246 UConverter* source = (UConverter*) src;
1247
1248 if(source) {
1249 conv = ucnv_safeClone(source, NULL, &buffersize, &errorCode);
1250 }
1251
1252 if (icu4jni_error(env, errorCode) != FALSE) {
1253 return NULL;
1254 }
1255
1256 return conv;
1257 }
1258
getMaxCharsPerByte(JNIEnv * env,jclass jClass,jlong handle)1259 static jint getMaxCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
1260 /*
1261 * currently we know that max number of chars per byte is 2
1262 */
1263 return 2;
1264 }
1265
getAveCharsPerByte(JNIEnv * env,jclass jClass,jlong handle)1266 static jfloat getAveCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
1267 jfloat ret = 0;
1268 ret = (jfloat)( 1/(jfloat)getMaxBytesPerChar(env, jClass, handle));
1269 return ret;
1270 }
1271
toUChars(const char * cs,UChar * us,int32_t length)1272 void toUChars(const char* cs, UChar* us, int32_t length) {
1273 char c;
1274 while(length>0) {
1275 c=*cs++;
1276 *us++=(char)c;
1277 --length;
1278 }
1279 }
1280
getSubstitutionBytes(JNIEnv * env,jclass jClass,jlong handle)1281 static jbyteArray getSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle) {
1282
1283 const UConverter * cnv = (const UConverter *) handle;
1284 UErrorCode status = U_ZERO_ERROR;
1285 char subBytes[10];
1286 int8_t len =(char)10;
1287 jbyteArray arr;
1288 if(cnv) {
1289 ucnv_getSubstChars(cnv,subBytes,&len,&status);
1290 if(U_SUCCESS(status)) {
1291 arr = ((*env)->NewByteArray(env, len));
1292 if(arr) {
1293 (*env)->SetByteArrayRegion(env,arr,0,len,(jbyte*)subBytes);
1294 }
1295 return arr;
1296 }
1297 }
1298 return ((*env)->NewByteArray(env, 0));
1299 }
1300
contains(JNIEnv * env,jclass jClass,jlong handle1,jlong handle2)1301 static jboolean contains( JNIEnv *env, jclass jClass, jlong handle1, jlong handle2) {
1302 UErrorCode status = U_ZERO_ERROR;
1303 const UConverter * cnv1 = (const UConverter *) handle1;
1304 const UConverter * cnv2 = (const UConverter *) handle2;
1305 USet* set1;
1306 USet* set2;
1307 UBool bRet = 0;
1308
1309 if(cnv1 != NULL && cnv2 != NULL) {
1310 /* open charset 1 */
1311 set1 = uset_open(1, 2);
1312 ucnv_getUnicodeSet(cnv1, set1, UCNV_ROUNDTRIP_SET, &status);
1313
1314 if(U_SUCCESS(status)) {
1315 /* open charset 2 */
1316 status = U_ZERO_ERROR;
1317 set2 = uset_open(1, 2);
1318 ucnv_getUnicodeSet(cnv2, set2, UCNV_ROUNDTRIP_SET, &status);
1319
1320 /* contains? */
1321 if(U_SUCCESS(status)) {
1322 bRet = uset_containsAll(set1, set2);
1323 uset_close(set2);
1324 }
1325 uset_close(set1);
1326 }
1327 }
1328 return bRet;
1329 }
1330
1331 /*
1332 * JNI registration
1333 */
1334 static JNINativeMethod gMethods[] = {
1335 /* name, signature, funcPtr */
1336 { "convertByteToChar", "(J[BI[CI[IZ)I", (void*) convertByteToChar },
1337 { "decode", "(J[BI[CI[IZ)I", (void*) decode },
1338 { "convertCharToByte", "(J[CI[BI[IZ)I", (void*) convertCharToByte },
1339 { "encode", "(J[CI[BI[IZ)I", (void*) encode },
1340 { "flushCharToByte", "(J[BI[I)I", (void*) flushCharToByte },
1341 { "flushByteToChar", "(J[CI[I)I", (void*) flushByteToChar },
1342 { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter },
1343 { "resetByteToChar", "(J)V", (void*) resetByteToChar },
1344 { "resetCharToByte", "(J)V", (void*) resetCharToByte },
1345 { "closeConverter", "(J)V", (void*) closeConverter },
1346 { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars },
1347 { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes },
1348 { "setSubstitutionModeCharToByte", "(JZ)I", (void*) setSubstitutionModeCharToByte },
1349 { "setSubstitutionModeByteToChar", "(JZ)I", (void*) setSubstitutionModeByteToChar },
1350 { "countInvalidBytes", "(J[I)I", (void*) countInvalidBytes },
1351 { "countInvalidChars", "(J[I)I", (void*) countInvalidChars },
1352 { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar },
1353 { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar },
1354 { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar },
1355 { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte },
1356 { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte },
1357 { "contains", "(JJ)Z", (void*) contains },
1358 { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes },
1359 { "canEncode", "(JI)Z", (void*) canEncode },
1360 { "canDecode", "(J[B)Z", (void*) canDecode },
1361 { "countAvailable", "()I", (void*) countAvailable },
1362 { "getAvailable", "()[Ljava/lang/String;", (void*) getAvailable },
1363 { "countAliases", "(Ljava/lang/String;)I", (void*) countAliases },
1364 { "getAliases", "(Ljava/lang/String;)[Ljava/lang/String;", (void*) getAliases },
1365 { "getCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCanonicalName },
1366 { "getICUCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getICUCanonicalName },
1367 { "getJavaCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getJavaCanonicalName2 },
1368 { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode },
1369 { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode },
1370 { "safeClone", "(J)J", (void*) safeClone }
1371 };
1372
register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv * _env)1373 int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv *_env) {
1374 return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/charset/NativeConverter",
1375 gMethods, NELEM(gMethods));
1376 }
1377
1378
1379