diff options
author | Elliott Hughes <enh@google.com> | 2010-01-22 18:22:53 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2010-01-22 18:28:47 -0800 |
commit | 1698d148fba5718d68de04df1b726940c50fd015 (patch) | |
tree | aaea1c31ef4b6413ce2f0c3ed26e261abf8eb605 /icu/src/main/native/NativeConverter.cpp | |
parent | 29d8606c7d5f8e1b6957ef4bced99251ec1dffff (diff) | |
download | libcore-1698d148fba5718d68de04df1b726940c50fd015.zip libcore-1698d148fba5718d68de04df1b726940c50fd015.tar.gz libcore-1698d148fba5718d68de04df1b726940c50fd015.tar.bz2 |
Switch our ICU JNI over to C++ and tidy up a little.
The big ugly files (implementing NativeCollation and NativeConverter), I've
just done the minimum necessary for them to compile under a C++ compiler. For
the small ones, I've been through them more thoroughly, removing duplication
and the like.
I only came across one bug; a failure path in BidiWrapper that would have
leaked.
Diffstat (limited to 'icu/src/main/native/NativeConverter.cpp')
-rw-r--r-- | icu/src/main/native/NativeConverter.cpp | 1365 |
1 files changed, 1365 insertions, 0 deletions
diff --git a/icu/src/main/native/NativeConverter.cpp b/icu/src/main/native/NativeConverter.cpp new file mode 100644 index 0000000..f704e8f --- /dev/null +++ b/icu/src/main/native/NativeConverter.cpp @@ -0,0 +1,1365 @@ +/** +******************************************************************************* +* Copyright (C) 1996-2006, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +* +* +******************************************************************************* +*/ +/* + * @(#) icujniinterface.c 1.2 00/10/11 + * + * (C) Copyright IBM Corp. 2000 - All Rights Reserved + * A JNI wrapper to ICU native converter Interface + * @author: Ram Viswanadha + */ + +#include "JNIHelp.h" +#include "AndroidSystemNatives.h" +#include "unicode/utypes.h" /* Basic ICU data types */ +#include "unicode/ucnv.h" /* C Converter API */ +#include "unicode/ustring.h" /* some more string functions*/ +#include "unicode/ucnv_cb.h" /* for callback functions */ +#include "unicode/uset.h" /* for contains function */ +#include "ErrorCode.h" +#include <stdlib.h> +#include <string.h> + +#define com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK 0L +#define com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK 1L +#define com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK 2L + +// BEGIN android-removed +// #define UTF_16BE "UTF-16BE" +// #define UTF_16 "UTF-16" +// END android-removed + +/* Prototype of callback for substituting user settable sub chars */ +static void JNI_TO_U_CALLBACK_SUBSTITUTE + (const void *,UConverterToUnicodeArgs *,const char* ,int32_t ,UConverterCallbackReason ,UErrorCode * ); + +/** + * Opens the ICU converter + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle buffer to recieve ICU's converter address + * @param converterName name of the ICU converter + */ +static jlong openConverter (JNIEnv *env, jclass jClass, jstring converterName) { + + UConverter* conv=NULL; + UErrorCode errorCode = U_ZERO_ERROR; + + const char* cnvName= (const char*) env->GetStringUTFChars(converterName,NULL); + if(cnvName) { + int count = env->GetStringUTFLength(converterName); + + conv = ucnv_open(cnvName,&errorCode); + } + env->ReleaseStringUTFChars(converterName,cnvName); + + if (icu4jni_error(env, errorCode) != FALSE) { + return 0; + } + + return (jlong) conv; +} + +/** + * Closes the ICU converter + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle address of ICU converter + */ +static void closeConverter (JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)(long)handle; + if(cnv) { + // BEGIN android-added + // Free up any contexts created in setCallback[Encode|Decode]() + UConverterToUCallback toAction; + UConverterFromUCallback fromAction; + void* context1 = NULL; + void* context2 = NULL; + // TODO: ICU API bug? + // The documentation clearly states that the caller owns the returned + // pointers: http://icu-project.org/apiref/icu4c/ucnv_8h.html + ucnv_getToUCallBack(cnv, &toAction, const_cast<const void**>(&context1)); + ucnv_getFromUCallBack(cnv, &fromAction, const_cast<const void**>(&context2)); + // END android-added + ucnv_close(cnv); + // BEGIN android-added + if (context1 != NULL) { + free(context1); + } + if (context2 != NULL) { + free(context2); + } + // END android-added + } +} + +/** + * Sets the substution mode for from Unicode conversion. Currently only + * two modes are supported: substitute or report + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle address of ICU converter + * @param mode the mode to set + */ +static jint setSubstitutionModeCharToByte (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) { + + UConverter* conv = (UConverter*)(long)handle; + UErrorCode errorCode =U_ZERO_ERROR; + + if(conv) { + + UConverterFromUCallback fromUOldAction ; + void* fromUOldContext; + void* fromUNewContext=NULL; + if(mode) { + + ucnv_setFromUCallBack(conv, + UCNV_FROM_U_CALLBACK_SUBSTITUTE, + fromUNewContext, + &fromUOldAction, + (const void**)&fromUOldContext, + &errorCode); + + } + else{ + + ucnv_setFromUCallBack(conv, + UCNV_FROM_U_CALLBACK_STOP, + fromUNewContext, + &fromUOldAction, + (const void**)&fromUOldContext, + &errorCode); + + } + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} +/** + * Sets the substution mode for to Unicode conversion. Currently only + * two modes are supported: substitute or report + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle address of ICU converter + * @param mode the mode to set + */ +static jint setSubstitutionModeByteToChar (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) { + + UConverter* conv = (UConverter*)handle; + UErrorCode errorCode =U_ZERO_ERROR; + + if(conv) { + + UConverterToUCallback toUOldAction ; + void* toUOldContext; + void* toUNewContext=NULL; + if(mode) { + + ucnv_setToUCallBack(conv, + UCNV_TO_U_CALLBACK_SUBSTITUTE, + toUNewContext, + &toUOldAction, + (const void**)&toUOldContext, + &errorCode); + + } + else{ + + ucnv_setToUCallBack(conv, + UCNV_TO_U_CALLBACK_STOP, + toUNewContext, + &toUOldAction, + (const void**)&toUOldContext, + &errorCode); + + } + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} +/** + * Converts a buffer of Unicode code units to target encoding + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle address of ICU converter + * @param source buffer of Unicode chars to convert + * @param sourceEnd limit of the source buffer + * @param target buffer to recieve the converted bytes + * @param targetEnd the limit of the target buffer + * @param data buffer to recieve state of the current conversion + * @param flush boolean that specifies end of source input + */ +static jint convertCharToByte(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + if(cnv) { + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + if(myData) { + jint* sourceOffset = &myData[0]; + jint* targetOffset = &myData[1]; + const jchar* uSource =(jchar*) env->GetPrimitiveArrayCritical(source, NULL); + if(uSource) { + jbyte* uTarget=(jbyte*) env->GetPrimitiveArrayCritical(target,NULL); + if(uTarget) { + const jchar* mySource = uSource+ *sourceOffset; + const UChar* mySourceLimit= uSource+sourceEnd; + char* cTarget = reinterpret_cast<char*>(uTarget+ *targetOffset); + const char* cTargetLimit = reinterpret_cast<const char*>(uTarget+targetEnd); + + ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource, + mySourceLimit,NULL,(UBool) flush, &errorCode); + + *sourceOffset = (jint) (mySource - uSource)-*sourceOffset; + *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset; + if(U_FAILURE(errorCode)) { + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + env->ReleasePrimitiveArrayCritical(source,(jchar*)uSource,0); + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(source,(jchar*)uSource,0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} + +static jint encode(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) { + + UErrorCode ec = UErrorCode(convertCharToByte(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush)); + UConverter* cnv = (UConverter*)handle; + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + + if(cnv && myData) { + + UErrorCode errorCode = U_ZERO_ERROR; + myData[3] = ucnv_fromUCountPending(cnv, &errorCode); + + if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND) { + int8_t count =32; + UChar invalidUChars[32]; + ucnv_getInvalidUChars(cnv,invalidUChars,&count,&errorCode); + + if(U_SUCCESS(errorCode)) { + myData[2] = count; + } + } + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return ec; +} + +/** + * Converts a buffer of encoded bytes to Unicode code units + * @param env environment handle for JNI + * @param jClass handle for the class + * @param handle address of ICU converter + * @param source buffer of Unicode chars to convert + * @param sourceEnd limit of the source buffer + * @param target buffer to recieve the converted bytes + * @param targetEnd the limit of the target buffer + * @param data buffer to recieve state of the current conversion + * @param flush boolean that specifies end of source input + */ +static jint convertByteToChar(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + if(cnv) { + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + if(myData) { + jint* sourceOffset = &myData[0]; + jint* targetOffset = &myData[1]; + + const jbyte* uSource =(jbyte*) env->GetPrimitiveArrayCritical(source, NULL); + if(uSource) { + jchar* uTarget=(jchar*) env->GetPrimitiveArrayCritical(target,NULL); + if(uTarget) { + const jbyte* mySource = uSource+ *sourceOffset; + const char* mySourceLimit = reinterpret_cast<const char*>(uSource+sourceEnd); + UChar* cTarget=uTarget+ *targetOffset; + const UChar* cTargetLimit=uTarget+targetEnd; + + ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource, + mySourceLimit,NULL,(UBool) flush, &errorCode); + + *sourceOffset = mySource - uSource - *sourceOffset ; + *targetOffset = cTarget - uTarget - *targetOffset; + if(U_FAILURE(errorCode)) { + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + env->ReleasePrimitiveArrayCritical(source,(jchar*)uSource,0); + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(source,(jchar*)uSource,0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} + +static jint decode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) { + + jint ec = convertByteToChar(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush); + + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + UConverter* cnv = (UConverter*)handle; + + if(myData && cnv) { + UErrorCode errorCode = U_ZERO_ERROR; + myData[3] = ucnv_toUCountPending(cnv, &errorCode); + + if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND ) { + char invalidChars[32] = {'\0'}; + int8_t len = 32; + ucnv_getInvalidChars(cnv,invalidChars,&len,&errorCode); + + if(U_SUCCESS(errorCode)) { + myData[2] = len; + } + } + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return ec; +} +static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)handle; + if(cnv) { + ucnv_resetToUnicode(cnv); + } +} + +static void resetCharToByte(JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)handle; + if(cnv) { + ucnv_resetFromUnicode(cnv); + } + +} + +static jint countInvalidBytes (JNIEnv *env, jclass jClass, jlong handle, jintArray length) { + + UConverter* cnv = (UConverter*)handle; + UErrorCode errorCode = U_ZERO_ERROR; + if(cnv) { + char invalidChars[32]; + + jint* len = (jint*) env->GetPrimitiveArrayCritical(length, NULL); + if(len) { + ucnv_getInvalidChars(cnv,invalidChars,(int8_t*)len,&errorCode); + } + env->ReleasePrimitiveArrayCritical(length,(jint*)len,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; + +} + + +static jint countInvalidChars(JNIEnv *env, jclass jClass, jlong handle, jintArray length) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + UChar invalidUChars[32]; + if(cnv) { + jint* len = (jint*) env->GetPrimitiveArrayCritical(length, NULL); + if(len) { + ucnv_getInvalidUChars(cnv,invalidUChars,(int8_t*)len,&errorCode); + } + env->ReleasePrimitiveArrayCritical(length,(jint*)len,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; + +} + +static jint getMaxBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)handle; + if(cnv) { + return (jint)ucnv_getMaxCharSize(cnv); + } + return -1; +} + +static jint getMinBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)handle; + if(cnv) { + return (jint)ucnv_getMinCharSize(cnv); + } + return -1; +} +static jfloat getAveBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { + + UConverter* cnv = (UConverter*)handle; + if(cnv) { + jfloat max = (jfloat)ucnv_getMaxCharSize(cnv); + jfloat min = (jfloat)ucnv_getMinCharSize(cnv); + return (jfloat) ( (max+min)/2 ); + } + return -1; +} +static jint flushByteToChar(JNIEnv *env, jclass jClass,jlong handle, jcharArray target, jint targetEnd, jintArray data) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + if(cnv) { + jbyte source ='\0'; + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + if(myData) { + jint* targetOffset = &myData[1]; + jchar* uTarget=(jchar*) env->GetPrimitiveArrayCritical(target,NULL); + if(uTarget) { + const jbyte* mySource = &source; + const char* mySourceLimit = reinterpret_cast<char*>(&source); + UChar* cTarget=uTarget+ *targetOffset; + const UChar* cTargetLimit=uTarget+targetEnd; + + ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource, + mySourceLimit,NULL,TRUE, &errorCode); + + + *targetOffset = (jint) ((jchar*)cTarget - uTarget)- *targetOffset; + if(U_FAILURE(errorCode)) { + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} + +static jint flushCharToByte (JNIEnv *env, jclass jClass, jlong handle, jbyteArray target, jint targetEnd, jintArray data) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + jchar source = '\0'; + if(cnv) { + jint* myData = (jint*) env->GetPrimitiveArrayCritical(data,NULL); + if(myData) { + jint* targetOffset = &myData[1]; + jbyte* uTarget=(jbyte*) env->GetPrimitiveArrayCritical(target,NULL); + if(uTarget) { + const jchar* mySource = &source; + const UChar* mySourceLimit= &source; + char* cTarget = reinterpret_cast<char*>(uTarget+ *targetOffset); + const char* cTargetLimit = reinterpret_cast<char*>(uTarget+targetEnd); + + ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource, + mySourceLimit,NULL,TRUE, &errorCode); + + + *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset; + if(U_FAILURE(errorCode)) { + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(target,uTarget,0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(data,(jint*)myData,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} + +static void toChars(const UChar* us, char* cs, int32_t length) { + UChar u; + while(length>0) { + u=*us++; + *cs++=(char)u; + --length; + } +} +static jint setSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle, jbyteArray subChars, jint length) { + + UConverter* cnv = (UConverter*) handle; + UErrorCode errorCode = U_ZERO_ERROR; + if(cnv) { + jbyte* u_subChars = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(subChars, NULL)); + if(u_subChars) { + char* mySubChars = new char[length]; + toChars((UChar*)u_subChars,&mySubChars[0],length); + ucnv_setSubstChars(cnv,mySubChars, (char)length,&errorCode); + if(U_FAILURE(errorCode)) { + env->ReleasePrimitiveArrayCritical(subChars,mySubChars,0); + return errorCode; + } + delete[] mySubChars; + } + else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(subChars,u_subChars,0); + return errorCode; + } + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return errorCode; +} + + +#define VALUE_STRING_LENGTH 32 + +struct SubCharStruct { + int length; + UChar subChars[256]; + UBool stopOnIllegal; +}; + + +static UErrorCode +setToUCallbackSubs(UConverter* cnv,UChar* subChars, int32_t length,UBool stopOnIllegal ) { + SubCharStruct* substitutionCharS = (SubCharStruct*) malloc(sizeof(SubCharStruct)); + UErrorCode errorCode = U_ZERO_ERROR; + if(substitutionCharS) { + UConverterToUCallback toUOldAction; + void* toUOldContext=NULL; + void* toUNewContext=NULL ; + if(subChars) { + u_strncpy(substitutionCharS->subChars,subChars,length); + }else{ + substitutionCharS->subChars[length++] =0xFFFD; + } + substitutionCharS->subChars[length]=0; + substitutionCharS->length = length; + substitutionCharS->stopOnIllegal = stopOnIllegal; + toUNewContext = substitutionCharS; + + ucnv_setToUCallBack(cnv, + JNI_TO_U_CALLBACK_SUBSTITUTE, + toUNewContext, + &toUOldAction, + (const void**)&toUOldContext, + &errorCode); + + if(toUOldContext) { + SubCharStruct* temp = (SubCharStruct*) toUOldContext; + free(temp); + } + + return errorCode; + } + return U_MEMORY_ALLOCATION_ERROR; +} +static jint setSubstitutionChars(JNIEnv *env, jclass jClass, jlong handle, jcharArray subChars, jint length) { + + UErrorCode errorCode = U_ZERO_ERROR; + UConverter* cnv = (UConverter*) handle; + jchar* u_subChars=NULL; + if(cnv) { + if(subChars) { + int len = env->GetArrayLength(subChars); + u_subChars = reinterpret_cast<jchar*>(env->GetPrimitiveArrayCritical(subChars,NULL)); + if(u_subChars) { + errorCode = setToUCallbackSubs(cnv,u_subChars,len,FALSE); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + env->ReleasePrimitiveArrayCritical(subChars,u_subChars,0); + return errorCode; + } + } + return U_ILLEGAL_ARGUMENT_ERROR; +} + + +static void JNI_TO_U_CALLBACK_SUBSTITUTE( const void *context, UConverterToUnicodeArgs *toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode * err) { + + if(context) { + SubCharStruct* temp = (SubCharStruct*)context; + if( temp) { + if(temp->stopOnIllegal==FALSE) { + if (reason > UCNV_IRREGULAR) { + return; + } + /* reset the error */ + *err = U_ZERO_ERROR; + ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err); + }else{ + if(reason != UCNV_UNASSIGNED) { + /* the caller must have set + * the error code accordingly + */ + return; + }else{ + *err = U_ZERO_ERROR; + ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err); + return; + } + } + } + } + return; +} + +static jboolean canEncode(JNIEnv *env, jclass jClass, jlong handle, jint codeUnit) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + if(cnv) { + UChar source[3]; + UChar *mySource=source; + const UChar* sourceLimit = (codeUnit<0x010000) ? &source[1] : &source[2]; + char target[5]; + char *myTarget = target; + const char* targetLimit = &target[4]; + int i=0; + UTF_APPEND_CHAR(&source[0],i,2,codeUnit); + + ucnv_fromUnicode(cnv,&myTarget,targetLimit, + (const UChar**)&mySource, + sourceLimit,NULL, TRUE,&errorCode); + + if(U_SUCCESS(errorCode)) { + return (jboolean)TRUE; + } + } + return (jboolean)FALSE; +} + + +static jboolean canDecode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source) { + + UErrorCode errorCode =U_ZERO_ERROR; + UConverter* cnv = (UConverter*)handle; + if(cnv) { + jint len = env->GetArrayLength(source); + jbyte* cSource =(jbyte*) env->GetPrimitiveArrayCritical(source, NULL); + if(cSource) { + const char* cSourceLimit = reinterpret_cast<const char*>(cSource+len); + + /* Assume that we need at most twice the length of source */ + UChar* target = (UChar*) malloc(sizeof(UChar)* (len<<1)); + UChar* targetLimit = target + (len<<1); + if(target) { + ucnv_toUnicode(cnv,&target,targetLimit, (const char**)&cSource, + cSourceLimit,NULL, TRUE,&errorCode); + + if(U_SUCCESS(errorCode)) { + free(target); + env->ReleasePrimitiveArrayCritical(source,cSource,0); + return (jboolean)TRUE; + } + } + free(target); + } + env->ReleasePrimitiveArrayCritical(source,cSource,0); + } + return (jboolean)FALSE; +} + +static int32_t copyString(char* dest, int32_t destCapacity, int32_t startIndex, + const char* src, UErrorCode* status) { + int32_t srcLen = 0, i=0; + if(U_FAILURE(*status)) { + return 0; + } + if(dest == NULL || src == NULL || destCapacity < startIndex) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + srcLen = strlen(src); + if(srcLen >= destCapacity) { + *status = U_BUFFER_OVERFLOW_ERROR; + return 0; + } + for(i=0; i < srcLen; i++) { + dest[startIndex++] = src[i]; + } + /* null terminate the buffer */ + dest[startIndex] = 0; /* no bounds check already made sure that we have enough room */ + return startIndex; +} + +static int32_t getJavaCanonicalName1(const char* icuCanonicalName, + char* canonicalName, int32_t capacity, + UErrorCode* status) { + /* + If a charset listed in the IANA Charset Registry is supported by an implementation + of the Java platform then its canonical name must be the name listed in the registry. + Many charsets are given more than one name in the registry, in which case the registry + identifies one of the names as MIME-preferred. If a charset has more than one registry + name then its canonical name must be the MIME-preferred name and the other names in + the registry must be valid aliases. If a supported charset is not listed in the IANA + registry then its canonical name must begin with one of the strings "X-" or "x-". + */ + int32_t retLen = 0; + const char* cName = NULL; + /* find out the alias with MIME tag */ + if((cName =ucnv_getStandardName(icuCanonicalName, "MIME", status)) != NULL) { + retLen = copyString(canonicalName, capacity, 0, cName, status); + /* find out the alias with IANA tag */ + }else if((cName =ucnv_getStandardName(icuCanonicalName, "IANA", status)) != NULL) { + retLen = copyString(canonicalName, capacity, 0, cName, status); + }else { + /* + check to see if an alias already exists with x- prefix, if yes then + make that the canonical name + */ + int32_t aliasNum = ucnv_countAliases(icuCanonicalName,status); + int32_t i=0; + const char* name; + for(i=0;i<aliasNum;i++) { + name = ucnv_getAlias(icuCanonicalName,(uint16_t)i, status); + if(name != NULL && name[0]=='x' && name[1]=='-') { + retLen = copyString(canonicalName, capacity, 0, name, status); + break; + } + } + /* last resort just append x- to any of the alias and + make it the canonical name */ + if(retLen == 0 && U_SUCCESS(*status)) { + name = ucnv_getStandardName(icuCanonicalName, "UTR22", status); + if(name == NULL && strchr(icuCanonicalName, ',')!= NULL) { + name = ucnv_getAlias(icuCanonicalName, 1, status); + if(*status == U_INDEX_OUTOFBOUNDS_ERROR) { + *status = U_ZERO_ERROR; + } + } + /* if there is no UTR22 canonical name .. then just return itself*/ + if(name == NULL) { + name = icuCanonicalName; + } + if(capacity >= 2) { + strcpy(canonicalName,"x-"); + } + retLen = copyString(canonicalName, capacity, 2, name, status); + } + } + return retLen; +} + +static jobjectArray getAvailable(JNIEnv *env, jclass jClass) { + + jobjectArray ret; + int32_t i = 0; + int32_t num = ucnv_countAvailable(); + UErrorCode error = U_ZERO_ERROR; + const char* name =NULL; + char canonicalName[256]={0}; + ret= env->NewObjectArray(num, env->FindClass("java/lang/String"), + env->NewStringUTF("")); + + for(i=0;i<num;i++) { + name = ucnv_getAvailableName(i); + getJavaCanonicalName1(name, canonicalName, 256, &error); +#if DEBUG + if(U_FAILURE(error)) { + printf("An error occurred retrieving index %i. Error: %s. \n", i, u_errorName(error)); + } + + printf("canonical name for %s\n", canonicalName); +#endif + // BEGIN android-changed + jstring canonName = env->NewStringUTF(canonicalName); + env->SetObjectArrayElement(ret,i,canonName); + env->DeleteLocalRef(canonName); + // END android-changed + /*printf("canonical name : %s at %i\n", name,i); */ + canonicalName[0]='\0';/* nul terminate */ + } + return (ret); +} + +static jint countAliases(JNIEnv *env, jclass jClass,jstring enc) { + + UErrorCode error = U_ZERO_ERROR; + jint num =0; + const char* encName = env->GetStringUTFChars(enc,NULL); + + if(encName) { + num = ucnv_countAliases(encName,&error); + } + + env->ReleaseStringUTFChars(enc,encName); + + return num; +} + + +static jobjectArray getAliases(JNIEnv *env, jclass jClass, jstring enc) { + + jobjectArray ret=NULL; + int32_t aliasNum = 0; + UErrorCode error = U_ZERO_ERROR; + const char* encName = env->GetStringUTFChars(enc,NULL); + int i=0; + int j=0; + const char* aliasArray[50]; + // BEGIN android-removed + // int32_t utf16AliasNum = 0; + // END android-removed + + + if(encName) { + const char* myEncName = encName; + aliasNum = ucnv_countAliases(myEncName,&error); + + // BEGIN android-removed + // /* special case for UTF-16. In java UTF-16 is always BE*/ + // if(strcmp(myEncName, UTF_16BE)==0) { + // utf16AliasNum=ucnv_countAliases(UTF_16,&error); + // } + // END android-removed + + if(aliasNum==0 && encName[0] == 0x78 /*x*/ && encName[1]== 0x2d /*-*/) { + myEncName = encName+2; + aliasNum = ucnv_countAliases(myEncName,&error); + } + if(U_SUCCESS(error)) { + for(i=0,j=0;i<aliasNum;i++) { + const char* name = ucnv_getAlias(myEncName,(uint16_t)i,&error); + if(strchr(name,'+')==0 && strchr(name,',')==0) { + aliasArray[j++]= name; + } + } + + // BEGIN android-removed + // if(utf16AliasNum>0) { + // for(i=0;i<utf16AliasNum;i++) { + // const char* name = ucnv_getAlias(UTF_16,(uint16_t)i,&error); + // if(strchr(name,'+')==0 && strchr(name,',')==0) { + // aliasArray[j++]= name; + // } + // } + // } + // END android-removed + + ret = (jobjectArray)env->NewObjectArray(j, + env->FindClass("java/lang/String"), env->NewStringUTF("")); + for(;--j>=0;) { + // BEGIN android-changed + jstring alias = env->NewStringUTF(aliasArray[j]); + env->SetObjectArrayElement(ret, j, alias); + env->DeleteLocalRef(alias); + // END android-changed + } + } + } + env->ReleaseStringUTFChars(enc,encName); + + return (ret); +} + +static jstring getCanonicalName(JNIEnv *env, jclass jClass,jstring enc) { + + UErrorCode error = U_ZERO_ERROR; + const char* encName = env->GetStringUTFChars(enc,NULL); + const char* canonicalName = ""; + // BEGIN android-changed + jstring ret = NULL; + if(encName) { + canonicalName = ucnv_getAlias(encName,0,&error); + if(canonicalName !=NULL && strstr(canonicalName,",")!=0) { + canonicalName = ucnv_getAlias(canonicalName,1,&error); + } + ret = (env->NewStringUTF(canonicalName)); + env->ReleaseStringUTFChars(enc,encName); + } + // END android-changed + return ret; +} + +static jstring getICUCanonicalName(JNIEnv *env, jclass jClass, jstring enc) { + + UErrorCode error = U_ZERO_ERROR; + const char* encName = env->GetStringUTFChars(enc,NULL); + const char* canonicalName = NULL; + jstring ret = NULL; + if(encName) { + // BEGIN android-removed + // if(strcmp(encName,"UTF-16")==0) { + // ret = (env->NewStringUTF(UTF_16BE)); + // }else + // END android-removed + if((canonicalName = ucnv_getCanonicalName(encName, "MIME", &error))!=NULL) { + ret = (env->NewStringUTF(canonicalName)); + }else if((canonicalName = ucnv_getCanonicalName(encName, "IANA", &error))!=NULL) { + ret = (env->NewStringUTF(canonicalName)); + }else if((canonicalName = ucnv_getCanonicalName(encName, "", &error))!=NULL) { + ret = (env->NewStringUTF(canonicalName)); + }else if((canonicalName = ucnv_getAlias(encName, 0, &error)) != NULL) { + /* we have some aliases in the form x-blah .. match those first */ + ret = (env->NewStringUTF(canonicalName)); + }else if( ret ==NULL && strstr(encName, "x-") == encName) { + /* check if the converter can be opened with the encName given */ + UConverter* conv = NULL; + error = U_ZERO_ERROR; + conv = ucnv_open(encName+2, &error); + if(conv!=NULL) { + ret = (env->NewStringUTF(encName+2)); + }else{ + /* unsupported encoding */ + ret = (env->NewStringUTF("")); + } + ucnv_close(conv); + }else{ + /* unsupported encoding */ + ret = (env->NewStringUTF("")); + } + } + env->ReleaseStringUTFChars(enc,encName); + return ret; +} + +static jstring getJavaCanonicalName2(JNIEnv *env, jclass jClass, jstring icuCanonName) { + /* + If a charset listed in the IANA Charset Registry is supported by an implementation + of the Java platform then its canonical name must be the name listed in the registry. + Many charsets are given more than one name in the registry, in which case the registry + identifies one of the names as MIME-preferred. If a charset has more than one registry + name then its canonical name must be the MIME-preferred name and the other names in + the registry must be valid aliases. If a supported charset is not listed in the IANA + registry then its canonical name must begin with one of the strings "X-" or "x-". + */ + UErrorCode error = U_ZERO_ERROR; + const char* icuCanonicalName = env->GetStringUTFChars(icuCanonName,NULL); + char cName[UCNV_MAX_CONVERTER_NAME_LENGTH] = {0}; + jstring ret; + if(icuCanonicalName && icuCanonicalName[0] != 0) { + getJavaCanonicalName1(icuCanonicalName, cName, UCNV_MAX_CONVERTER_NAME_LENGTH, &error); + } + ret = (env->NewStringUTF(cName)); + env->ReleaseStringUTFChars(icuCanonName,icuCanonicalName); + return ret; +} + +#define SUBS_ARRAY_CAPACITY 256 +struct EncoderCallbackContext { + int length; + char subChars[SUBS_ARRAY_CAPACITY]; + UConverterFromUCallback onUnmappableInput; + UConverterFromUCallback onMalformedInput; +}; + +static void CHARSET_ENCODER_CALLBACK(const void *context, + UConverterFromUnicodeArgs *fromArgs, + const UChar* codeUnits, + int32_t length, + UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode * status) { + if(context) { + EncoderCallbackContext* ctx = (EncoderCallbackContext*)context; + + if(ctx) { + UConverterFromUCallback realCB = NULL; + switch(reason) { + case UCNV_UNASSIGNED: + realCB = ctx->onUnmappableInput; + break; + case UCNV_ILLEGAL:/*malformed input*/ + case UCNV_IRREGULAR:/*malformed input*/ + realCB = ctx->onMalformedInput; + break; + /* + case UCNV_RESET: + ucnv_resetToUnicode(args->converter); + break; + case UCNV_CLOSE: + ucnv_close(args->converter); + break; + case UCNV_CLONE: + ucnv_clone(args->clone); + */ + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + if(realCB==NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + } + realCB(context, fromArgs, codeUnits, length, codePoint, reason, status); + } + } +} + +static void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void *context, + UConverterFromUnicodeArgs *fromArgs, + const UChar* codeUnits, + int32_t length, + UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode * err) { + if(context) { + EncoderCallbackContext* temp = (EncoderCallbackContext*)context; + *err = U_ZERO_ERROR; + ucnv_cbFromUWriteBytes(fromArgs,temp->subChars ,temp->length , 0, err); + } + return; +} + +static UConverterFromUCallback getFromUCallback(int32_t mode) { + switch(mode) { + default: /* falls through */ + case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK: + return UCNV_FROM_U_CALLBACK_STOP; + case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK: + return UCNV_FROM_U_CALLBACK_SKIP ; + case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK: + return JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER; + } +} + +static jint setCallbackEncode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) { + + UConverter* conv = (UConverter*)handle; + UErrorCode errorCode =U_ZERO_ERROR; + + if(conv) { + + UConverterFromUCallback fromUOldAction = NULL; + void* fromUOldContext = NULL; + EncoderCallbackContext* fromUNewContext=NULL; + UConverterFromUCallback fromUNewAction=NULL; + jbyte* sub = (jbyte*) env->GetPrimitiveArrayCritical(subChars, NULL); + ucnv_getFromUCallBack(conv, &fromUOldAction, const_cast<const void**>(&fromUOldContext)); + + /* fromUOldContext can only be DecodeCallbackContext since + the converter created is private data for the decoder + and callbacks can only be set via this method! + */ + if(fromUOldContext==NULL) { + fromUNewContext = (EncoderCallbackContext*) malloc(sizeof(EncoderCallbackContext)); + fromUNewAction = CHARSET_ENCODER_CALLBACK; + }else{ + fromUNewContext = (EncoderCallbackContext*) fromUOldContext; + fromUNewAction = fromUOldAction; + fromUOldAction = NULL; + fromUOldContext = NULL; + } + fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput); + fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput); + // BEGIN android-changed + if(sub!=NULL) { + fromUNewContext->length = length; + const char* src = const_cast<const char*>(reinterpret_cast<char*>(sub)); + strncpy(fromUNewContext->subChars, src, length); + env->ReleasePrimitiveArrayCritical(subChars, sub, 0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + // END android-changed + + ucnv_setFromUCallBack(conv, + fromUNewAction, + fromUNewContext, + &fromUOldAction, + (const void**)&fromUOldContext, + &errorCode); + + + return errorCode; + } + return U_ILLEGAL_ARGUMENT_ERROR; +} + +struct DecoderCallbackContext { + int length; + UChar subUChars[256]; + UConverterToUCallback onUnmappableInput; + UConverterToUCallback onMalformedInput; +}; + +static void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void *context, + UConverterToUnicodeArgs *toArgs, + const char* codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode * err) { + if(context) { + DecoderCallbackContext* temp = (DecoderCallbackContext*)context; + *err = U_ZERO_ERROR; + ucnv_cbToUWriteUChars(toArgs,temp->subUChars ,temp->length , 0, err); + } + return; +} + +static UConverterToUCallback getToUCallback(int32_t mode) { + switch(mode) { + default: /* falls through */ + case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK: + return UCNV_TO_U_CALLBACK_STOP; + case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK: + return UCNV_TO_U_CALLBACK_SKIP ; + case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK: + return JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER; + } +} + +static void CHARSET_DECODER_CALLBACK(const void *context, + UConverterToUnicodeArgs *args, + const char* codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode *status ) { + + if(context) { + DecoderCallbackContext* ctx = (DecoderCallbackContext*)context; + + if(ctx) { + UConverterToUCallback realCB = NULL; + switch(reason) { + case UCNV_UNASSIGNED: + realCB = ctx->onUnmappableInput; + break; + case UCNV_ILLEGAL:/*malformed input*/ + case UCNV_IRREGULAR:/*malformed input*/ + realCB = ctx->onMalformedInput; + break; + /* + case UCNV_RESET: + ucnv_resetToUnicode(args->converter); + break; + case UCNV_CLOSE: + ucnv_close(args->converter); + break; + case UCNV_CLONE: + ucnv_clone(args->clone); + */ + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + if(realCB==NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + } + realCB(context, args, codeUnits, length, reason, status); + } + } +} + +static jint setCallbackDecode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) { + + UConverter* conv = (UConverter*)handle; + UErrorCode errorCode =U_ZERO_ERROR; + if(conv) { + + UConverterToUCallback toUOldAction ; + void* toUOldContext; + DecoderCallbackContext* toUNewContext = NULL; + UConverterToUCallback toUNewAction = NULL; + jchar* sub = (jchar*) env->GetPrimitiveArrayCritical(subChars, NULL); + + ucnv_getToUCallBack(conv, &toUOldAction, const_cast<const void**>(&toUOldContext)); + + /* toUOldContext can only be DecodeCallbackContext since + the converter created is private data for the decoder + and callbacks can only be set via this method! + */ + if(toUOldContext==NULL) { + toUNewContext = (DecoderCallbackContext*) malloc(sizeof(DecoderCallbackContext)); + toUNewAction = CHARSET_DECODER_CALLBACK; + }else{ + toUNewContext = reinterpret_cast<DecoderCallbackContext*>(toUOldContext); + toUNewAction = toUOldAction; + toUOldAction = NULL; + toUOldContext = NULL; + } + toUNewContext->onMalformedInput = getToUCallback(onMalformedInput); + toUNewContext->onUnmappableInput = getToUCallback(onUnmappableInput); + // BEGIN android-changed + if(sub!=NULL) { + toUNewContext->length = length; + u_strncpy(toUNewContext->subUChars, sub, length); + env->ReleasePrimitiveArrayCritical(subChars, sub, 0); + }else{ + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + } + // END android-changed + ucnv_setToUCallBack(conv, + toUNewAction, + toUNewContext, + &toUOldAction, + (const void**)&toUOldContext, + &errorCode); + + return errorCode; + } + return U_ILLEGAL_ARGUMENT_ERROR; +} + +static jlong safeClone(JNIEnv *env, jclass, jlong address) { + UConverter* source = reinterpret_cast<UConverter*>(static_cast<uintptr_t>(address)); + if (!source) { + return NULL; + } + UErrorCode status = U_ZERO_ERROR; + jint bufferSize = U_CNV_SAFECLONE_BUFFERSIZE; + UConverter* conv = ucnv_safeClone(source, NULL, &bufferSize, &status); + icu4jni_error(env, status); + return reinterpret_cast<uintptr_t>(conv); +} + +static jint getMaxCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) { + /* + * currently we know that max number of chars per byte is 2 + */ + return 2; +} + +static jfloat getAveCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) { + jfloat ret = 0; + ret = (jfloat)( 1/(jfloat)getMaxBytesPerChar(env, jClass, handle)); + return ret; +} + +static void toUChars(const char* cs, UChar* us, int32_t length) { + char c; + while(length>0) { + c=*cs++; + *us++=(char)c; + --length; + } +} + +static jbyteArray getSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle) { + + const UConverter * cnv = (const UConverter *) handle; + UErrorCode status = U_ZERO_ERROR; + char subBytes[10]; + int8_t len =(char)10; + jbyteArray arr; + if(cnv) { + ucnv_getSubstChars(cnv,subBytes,&len,&status); + if(U_SUCCESS(status)) { + arr = (env->NewByteArray(len)); + if(arr) { + env->SetByteArrayRegion(arr,0,len,(jbyte*)subBytes); + } + return arr; + } + } + return (env->NewByteArray(0)); +} + +static jboolean contains( JNIEnv *env, jclass jClass, jlong handle1, jlong handle2) { + UErrorCode status = U_ZERO_ERROR; + const UConverter * cnv1 = (const UConverter *) handle1; + const UConverter * cnv2 = (const UConverter *) handle2; + USet* set1; + USet* set2; + UBool bRet = 0; + + if(cnv1 != NULL && cnv2 != NULL) { + /* open charset 1 */ + set1 = uset_open(1, 2); + ucnv_getUnicodeSet(cnv1, set1, UCNV_ROUNDTRIP_SET, &status); + + if(U_SUCCESS(status)) { + /* open charset 2 */ + status = U_ZERO_ERROR; + set2 = uset_open(1, 2); + ucnv_getUnicodeSet(cnv2, set2, UCNV_ROUNDTRIP_SET, &status); + + /* contains? */ + if(U_SUCCESS(status)) { + bRet = uset_containsAll(set1, set2); + uset_close(set2); + } + uset_close(set1); + } + } + return bRet; +} + +/* + * JNI registration + */ +static JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "convertByteToChar", "(J[BI[CI[IZ)I", (void*) convertByteToChar }, + { "decode", "(J[BI[CI[IZ)I", (void*) decode }, + { "convertCharToByte", "(J[CI[BI[IZ)I", (void*) convertCharToByte }, + { "encode", "(J[CI[BI[IZ)I", (void*) encode }, + { "flushCharToByte", "(J[BI[I)I", (void*) flushCharToByte }, + { "flushByteToChar", "(J[CI[I)I", (void*) flushByteToChar }, + { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter }, + { "resetByteToChar", "(J)V", (void*) resetByteToChar }, + { "resetCharToByte", "(J)V", (void*) resetCharToByte }, + { "closeConverter", "(J)V", (void*) closeConverter }, + { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars }, + { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes }, + { "setSubstitutionModeCharToByte", "(JZ)I", (void*) setSubstitutionModeCharToByte }, + { "setSubstitutionModeByteToChar", "(JZ)I", (void*) setSubstitutionModeByteToChar }, + { "countInvalidBytes", "(J[I)I", (void*) countInvalidBytes }, + { "countInvalidChars", "(J[I)I", (void*) countInvalidChars }, + { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar }, + { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar }, + { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar }, + { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte }, + { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte }, + { "contains", "(JJ)Z", (void*) contains }, + { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes }, + { "canEncode", "(JI)Z", (void*) canEncode }, + { "canDecode", "(J[B)Z", (void*) canDecode }, + { "getAvailable", "()[Ljava/lang/String;", (void*) getAvailable }, + { "countAliases", "(Ljava/lang/String;)I", (void*) countAliases }, + { "getAliases", "(Ljava/lang/String;)[Ljava/lang/String;", (void*) getAliases }, + { "getCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCanonicalName }, + { "getICUCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getICUCanonicalName }, + { "getJavaCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getJavaCanonicalName2 }, + { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode }, + { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode }, + { "safeClone", "(J)J", (void*) safeClone } +}; + +int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv *_env) { + return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/charset/NativeConverter", + gMethods, NELEM(gMethods)); +} |