diff options
author | Elliott Hughes <enh@google.com> | 2010-05-19 14:24:43 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2010-05-19 14:48:13 -0700 |
commit | cf6c3a752da274cc5025191d3bcd62e6222f4a4c (patch) | |
tree | e25c3f824d271ad4b03a5a85867666c630e4164f /luni/src/main/native | |
parent | ce32a5646e9905a55d1c03b18757d401b4ab587e (diff) | |
download | libcore-cf6c3a752da274cc5025191d3bcd62e6222f4a4c.zip libcore-cf6c3a752da274cc5025191d3bcd62e6222f4a4c.tar.gz libcore-cf6c3a752da274cc5025191d3bcd62e6222f4a4c.tar.bz2 |
Fix CharsetEncoder.replaceWith, and simplify our implementation.
All I wanted to do was remove some more Get/Release Critical calls,
but I stumbled across some code that couldn't possibly be right.
Bug: 2663177
Change-Id: I82e240fe27ff9fcfe7f036c2d7708a9e55afa3ee
Diffstat (limited to 'luni/src/main/native')
-rw-r--r-- | luni/src/main/native/NativeConverter.cpp | 611 |
1 files changed, 193 insertions, 418 deletions
diff --git a/luni/src/main/native/NativeConverter.cpp b/luni/src/main/native/NativeConverter.cpp index 22e3024..4afdaf2 100644 --- a/luni/src/main/native/NativeConverter.cpp +++ b/luni/src/main/native/NativeConverter.cpp @@ -20,8 +20,10 @@ #include "ErrorCode.h" #include "JNIHelp.h" #include "ScopedLocalRef.h" +#include "ScopedPrimitiveArray.h" #include "ScopedUtfChars.h" #include "UniquePtr.h" +#include "cutils/log.h" #include "unicode/ucnv.h" #include "unicode/ucnv_cb.h" #include "unicode/uset.h" @@ -34,9 +36,19 @@ #define com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK 1L #define com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK 2L -/* 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 * ); +struct DecoderCallbackContext { + int length; + UChar subUChars[256]; + UConverterToUCallback onUnmappableInput; + UConverterToUCallback onMalformedInput; +}; + +struct EncoderCallbackContext { + int length; + char subBytes[256]; + UConverterFromUCallback onUnmappableInput; + UConverterFromUCallback onMalformedInput; +}; static jlong openConverter(JNIEnv* env, jclass, jstring converterName) { ScopedUtfChars converterNameChars(env, converterName); @@ -46,34 +58,27 @@ static jlong openConverter(JNIEnv* env, jclass, jstring converterName) { UErrorCode errorCode = U_ZERO_ERROR; UConverter* conv = ucnv_open(converterNameChars.c_str(), &errorCode); icu4jni_error(env, errorCode); - return (jlong) conv; + return reinterpret_cast<uintptr_t>(conv); } static void closeConverter(JNIEnv*, 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 - } + UConverter* cnv = reinterpret_cast<UConverter*>(handle); + if (!cnv) { + return; + } + // Free up 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)); + ucnv_close(cnv); + delete reinterpret_cast<DecoderCallbackContext*>(context1); + delete reinterpret_cast<EncoderCallbackContext*>(context2); } /** @@ -354,137 +359,10 @@ static jint flushCharToByte (JNIEnv* env, jclass, jlong handle, jbyteArray targe 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) { - while (length > 0) { - UChar u = *us++; - *cs++=(char)u; - --length; - } -} -static jint setSubstitutionBytes(JNIEnv* env, 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[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; - } - } 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, 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*, jclass, jlong handle, jint codeUnit) { - UErrorCode errorCode =U_ZERO_ERROR; UConverter* cnv = (UConverter*)handle; if(cnv) { @@ -497,11 +375,9 @@ static jboolean canEncode(JNIEnv*, jclass, jlong handle, jint codeUnit) { 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)) { + ucnv_fromUnicode(cnv, &myTarget, targetLimit, + (const UChar**)&mySource, sourceLimit, NULL, TRUE, &errorCode); + if (U_SUCCESS(errorCode)) { return JNI_TRUE; } } @@ -625,268 +501,168 @@ static const char* getICUCanonicalName(const char* name) { return NULL; } -#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; - } else { - realCB(context, fromArgs, codeUnits, length, codePoint, reason, status); - } - } +static void CHARSET_ENCODER_CALLBACK(const void* rawContext, UConverterFromUnicodeArgs* args, + const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, + UErrorCode* status) { + if (!rawContext) { + return; + } + const EncoderCallbackContext* ctx = reinterpret_cast<const EncoderCallbackContext*>(rawContext); + switch(reason) { + case UCNV_UNASSIGNED: + ctx->onUnmappableInput(ctx, args, codeUnits, length, codePoint, reason, status); + return; + case UCNV_ILLEGAL: + case UCNV_IRREGULAR: + ctx->onMalformedInput(ctx, args, codeUnits, length, codePoint, reason, status); + return; + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; } } -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 void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void* rawContext, + UConverterFromUnicodeArgs *fromArgs, const UChar*, int32_t, UChar32, + UConverterCallbackReason, UErrorCode * err) { + if (rawContext == NULL) { + return; + } + const EncoderCallbackContext* context = reinterpret_cast<const EncoderCallbackContext*>(rawContext); + *err = U_ZERO_ERROR; + ucnv_cbFromUWriteBytes(fromArgs, context->subBytes, context->length, 0, err); } 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; + 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; } + abort(); } -static jint setCallbackEncode(JNIEnv* env, jclass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) { - +static jint setCallbackEncode(JNIEnv* env, jclass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subBytes) { 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; + if (!conv) { + return U_ILLEGAL_ARGUMENT_ERROR; } - 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; -} + UConverterFromUCallback fromUOldAction = NULL; + void* fromUOldContext = NULL; + ucnv_getFromUCallBack(conv, &fromUOldAction, const_cast<const void**>(&fromUOldContext)); -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; + /* fromUOldContext can only be DecodeCallbackContext since + * the converter created is private data for the decoder + * and callbacks can only be set via this method! + */ + EncoderCallbackContext* fromUNewContext=NULL; + UConverterFromUCallback fromUNewAction=NULL; + if (fromUOldContext == NULL) { + fromUNewContext = new EncoderCallbackContext; + fromUNewAction = CHARSET_ENCODER_CALLBACK; + } else { + fromUNewContext = (EncoderCallbackContext*) fromUOldContext; + fromUNewAction = fromUOldAction; + fromUOldAction = NULL; + fromUOldContext = NULL; + } + fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput); + fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput); + ScopedByteArray sub(env, subBytes); + if (sub.get() == NULL) { + return U_ILLEGAL_ARGUMENT_ERROR; } + fromUNewContext->length = sub.size(); + strncpy(fromUNewContext->subBytes, reinterpret_cast<const char*>(sub.get()), sub.size()); + UErrorCode errorCode = U_ZERO_ERROR; + ucnv_setFromUCallBack(conv, fromUNewAction, fromUNewContext, &fromUOldAction, (const void**)&fromUOldContext, &errorCode); + return errorCode; } -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; - } else { - realCB(context, args, codeUnits, length, reason, status); - } - } +static void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void* rawContext, + UConverterToUnicodeArgs* toArgs, const char*, int32_t, UConverterCallbackReason, + UErrorCode* err) { + if (!rawContext) { + return; } + const DecoderCallbackContext* context = reinterpret_cast<const DecoderCallbackContext*>(rawContext); + *err = U_ZERO_ERROR; + ucnv_cbToUWriteUChars(toArgs,context->subUChars ,context->length , 0, err); } -static jint setCallbackDecode(JNIEnv* env, jclass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) { - +static UConverterToUCallback getToUCallback(int32_t mode) { + switch (mode) { + 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; + } + abort(); +} + +static void CHARSET_DECODER_CALLBACK(const void* rawContext, UConverterToUnicodeArgs* args, + const char* codeUnits, int32_t length, + UConverterCallbackReason reason, UErrorCode* status) { + if (!rawContext) { + return; + } + const DecoderCallbackContext* ctx = reinterpret_cast<const DecoderCallbackContext*>(rawContext); + switch(reason) { + case UCNV_UNASSIGNED: + ctx->onUnmappableInput(ctx, args, codeUnits, length, reason, status); + return; + case UCNV_ILLEGAL: + case UCNV_IRREGULAR: + ctx->onMalformedInput(ctx, args, codeUnits, length, reason, status); + return; + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } +} + +static jint setCallbackDecode(JNIEnv* env, jclass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars) { 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; + if (conv == NULL) { + return U_ILLEGAL_ARGUMENT_ERROR; } - return U_ILLEGAL_ARGUMENT_ERROR; -} -static jint getMaxCharsPerByte(JNIEnv*, jclass, jlong) { - /* - * currently we know that max number of chars per byte is 2 + UConverterToUCallback toUOldAction; + void* toUOldContext; + 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! */ - return 2; + DecoderCallbackContext* toUNewContext = NULL; + UConverterToUCallback toUNewAction = NULL; + if (toUOldContext==NULL) { + toUNewContext = new 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); + ScopedCharArray sub(env, subChars); + if (sub.get() == NULL) { + return U_ILLEGAL_ARGUMENT_ERROR; + } + toUNewContext->length = sub.size(); + u_strncpy(toUNewContext->subUChars, sub.get(), sub.size()); + UErrorCode errorCode = U_ZERO_ERROR; + ucnv_setToUCallBack(conv, toUNewAction, toUNewContext, + &toUOldAction, (const void**)&toUOldContext, &errorCode); + return errorCode; } static jfloat getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) { @@ -894,21 +670,23 @@ static jfloat getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) { } static jbyteArray getSubstitutionBytes(JNIEnv* env, jclass, jlong handle) { - const UConverter * cnv = (const UConverter *) handle; - if (cnv) { - UErrorCode status = U_ZERO_ERROR; - char subBytes[10]; - int8_t len =(char)10; - ucnv_getSubstChars(cnv,subBytes,&len,&status); - if(U_SUCCESS(status)) { - jbyteArray arr = env->NewByteArray(len); - if (arr) { - env->SetByteArrayRegion(arr,0,len,(jbyte*)subBytes); - } - return arr; - } + const UConverter* cnv = reinterpret_cast<const UConverter*>(handle); + if (cnv == NULL) { + return NULL; } - return env->NewByteArray(0); + UErrorCode status = U_ZERO_ERROR; + char subBytes[10]; + int8_t len = sizeof(subBytes); + ucnv_getSubstChars(cnv, subBytes, &len, &status); + if (!U_SUCCESS(status)) { + return env->NewByteArray(0); + } + jbyteArray result = env->NewByteArray(len); + if (result == NULL) { + return NULL; + } + env->SetByteArrayRegion(result, 0, len, reinterpret_cast<jbyte*>(subBytes)); + return result; } static jboolean contains(JNIEnv*, jclass, jlong handle1, jlong handle2) { @@ -998,16 +776,13 @@ static JNINativeMethod gMethods[] = { { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar }, { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte }, { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar }, - { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte }, { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar }, { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes }, { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter }, { "resetByteToChar", "(J)V", (void*) resetByteToChar }, { "resetCharToByte", "(J)V", (void*) resetCharToByte }, - { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode }, - { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode }, - { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes }, - { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars }, + { "setCallbackDecode", "(JII[C)I", (void*) setCallbackDecode }, + { "setCallbackEncode", "(JII[B)I", (void*) setCallbackEncode }, }; int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/ibm/icu4jni/charset/NativeConverter", |