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 */
36void  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 */
46static 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 */
72static 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 */
105static 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 */
148static 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 */
195static 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
243static 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 */
280static 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
328static 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}
352static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) {
353
354    UConverter* cnv = (UConverter*)handle;
355    if(cnv) {
356        ucnv_resetToUnicode(cnv);
357    }
358}
359
360static 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
369static 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
389static 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
407static 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
416static 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}
424static 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}
434static 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
475static 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
516void 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}
524static 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
553typedef struct{
554    int length;
555    UChar subChars[256];
556    UBool stopOnIllegal;
557}SubCharStruct;
558
559
560static UErrorCode
561setToUCallbackSubs(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}
594static 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
616void  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
645static 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
671static 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
702static jint countAvailable(JNIEnv *env, jclass jClass) {
703    return ucnv_countAvailable();
704}
705
706int32_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
729int32_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
787static 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
820static 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
836static 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
901static 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
920static 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
962static 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
985typedef struct{
986    int length;
987    char subChars[SUBS_ARRAY_CAPACITY];
988    UConverterFromUCallback onUnmappableInput;
989    UConverterFromUCallback onMalformedInput;
990}EncoderCallbackContext;
991
992void 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
1034void 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
1049UConverterFromUCallback 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
1061static 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
1113typedef struct{
1114    int length;
1115    UChar subUChars[256];
1116    UConverterToUCallback onUnmappableInput;
1117    UConverterToUCallback onMalformedInput;
1118}DecoderCallbackContext;
1119
1120void 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
1134UConverterToUCallback 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
1146void  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
1188static 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
1238static 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
1259static 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
1266static 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
1272void 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
1281static 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
1301static 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 */
1334static 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
1373int 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