• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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