1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project******************************************************************************* 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* Copyright (C) 1996-2006, International Business Machines Corporation and * 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* others. All Rights Reserved. * 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project******************************************************************************* 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project******************************************************************************* 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/ 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (C) Copyright IBM Corp. 2000 - All Rights Reserved 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A JNI wrapper to ICU native converter Interface 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @author: Ram Viswanadha 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 16757a7942eed2b0aa457f8517a0259d2ac82c5b18Elliott Hughes#define LOG_TAG "NativeConverter" 17757a7942eed2b0aa457f8517a0259d2ac82c5b18Elliott Hughes 18ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "JNIHelp.h" 19a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes#include "JniConstants.h" 20bef9ec33e1368f57c731fce63b6a8c61628c64b0Elliott Hughes#include "JniException.h" 218044bf6b446c93cd29c5753544246316f269064fElliott Hughes#include "ScopedLocalRef.h" 22cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes#include "ScopedPrimitiveArray.h" 2337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes#include "ScopedStringChars.h" 24ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "ScopedUtfChars.h" 25ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "UniquePtr.h" 26cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes#include "cutils/log.h" 27ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes#include "toStringArray.h" 28ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "unicode/ucnv.h" 29ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "unicode/ucnv_cb.h" 307d52d787302b862019da41aa753646d88d43fd61Elliott Hughes#include "unicode/uniset.h" 31ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "unicode/ustring.h" 32ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes#include "unicode/utypes.h" 33ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes 34ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes#include <vector> 35ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <stdlib.h> 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <string.h> 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 39c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes#define NativeConverter_REPORT 0 40c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes#define NativeConverter_IGNORE 1 41c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes#define NativeConverter_REPLACE 2 424722f161d49b5c483aa7aec0daad7bfee18578bbElliott Hughes 4337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes#define MAX_REPLACEMENT_LENGTH 32 // equivalent to UCNV_ERROR_BUFFER_LENGTH 4437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 45cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughesstruct DecoderCallbackContext { 4637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes UChar replacementChars[MAX_REPLACEMENT_LENGTH]; 4737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes size_t replacementCharCount; 48cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterToUCallback onUnmappableInput; 49cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterToUCallback onMalformedInput; 50cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes}; 51cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes 52cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughesstruct EncoderCallbackContext { 5337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes char replacementBytes[MAX_REPLACEMENT_LENGTH]; 5437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes size_t replacementByteCount; 55cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterFromUCallback onUnmappableInput; 56cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterFromUCallback onMalformedInput; 57cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes}; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 597d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstruct UConverterDeleter { 607d52d787302b862019da41aa753646d88d43fd61Elliott Hughes void operator()(UConverter* p) const { 617d52d787302b862019da41aa753646d88d43fd61Elliott Hughes ucnv_close(p); 627d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 637d52d787302b862019da41aa753646d88d43fd61Elliott Hughes}; 647d52d787302b862019da41aa753646d88d43fd61Elliott Hughestypedef UniquePtr<UConverter, UConverterDeleter> UniqueUConverter; 657d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 66ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughesstatic UConverter* toUConverter(jlong address) { 67ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes return reinterpret_cast<UConverter*>(static_cast<uintptr_t>(address)); 68ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes} 69ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes 707d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jlong NativeConverter_openConverter(JNIEnv* env, jclass, jstring converterName) { 71bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes ScopedUtfChars converterNameChars(env, converterName); 7205960876dff6a5b686821eed8f7ae7cef5af4f50Elliott Hughes if (converterNameChars.c_str() == NULL) { 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 75bef9ec33e1368f57c731fce63b6a8c61628c64b0Elliott Hughes UErrorCode status = U_ZERO_ERROR; 76bef9ec33e1368f57c731fce63b6a8c61628c64b0Elliott Hughes UConverter* cnv = ucnv_open(converterNameChars.c_str(), &status); 775ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "ucnv_open", status); 78ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes return reinterpret_cast<uintptr_t>(cnv); 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 817d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic void NativeConverter_closeConverter(JNIEnv*, jclass, jlong address) { 829b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes ucnv_close(toUConverter(address)); 83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 855ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesstatic bool shouldCodecThrow(jboolean flush, UErrorCode error) { 865ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (flush) { 875ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return (error != U_BUFFER_OVERFLOW_ERROR && error != U_TRUNCATED_CHAR_FOUND); 885ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } else { 895ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return (error != U_BUFFER_OVERFLOW_ERROR && error != U_INVALID_CHAR_FOUND && error != U_ILLEGAL_CHAR_FOUND); 905ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } 915ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes} 925ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes 937d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jint NativeConverter_encode(JNIEnv* env, jclass, jlong address, 947d52d787302b862019da41aa753646d88d43fd61Elliott Hughes jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, 957d52d787302b862019da41aa753646d88d43fd61Elliott Hughes jintArray data, jboolean flush) { 967d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 97ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 9864101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (cnv == NULL) { 995ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR); 10064101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 10164101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 102ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedCharArrayRO uSource(env, source); 10364101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (uSource.get() == NULL) { 1045ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR); 10564101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 10664101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 107ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedByteArrayRW uTarget(env, target); 10864101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (uTarget.get() == NULL) { 1095ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR); 11064101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 11164101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 112ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedIntArrayRW myData(env, data); 11364101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (myData.get() == NULL) { 1145ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR); 11599c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 11699c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes } 117ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes 118ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes // Do the conversion. 119ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes jint* sourceOffset = &myData[0]; 120ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes jint* targetOffset = &myData[1]; 121ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes const jchar* mySource = uSource.get() + *sourceOffset; 122ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes const UChar* mySourceLimit= uSource.get() + sourceEnd; 123ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes char* cTarget = reinterpret_cast<char*>(uTarget.get() + *targetOffset); 124ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes const char* cTargetLimit = reinterpret_cast<const char*>(uTarget.get() + targetEnd); 12599c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 126ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ucnv_fromUnicode(cnv , &cTarget, cTargetLimit, &mySource, mySourceLimit, NULL, (UBool) flush, &errorCode); 127ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes *sourceOffset = (mySource - uSource.get()) - *sourceOffset; 128ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes *targetOffset = (reinterpret_cast<jbyte*>(cTarget) - uTarget.get()) - *targetOffset; 129ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes 130ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes // If there was an error, count the problematic characters. 131ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND) { 1322981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes int8_t invalidUCharCount = 32; 133ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UChar invalidUChars[32]; 13433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes UErrorCode minorErrorCode = U_ZERO_ERROR; 1352981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes ucnv_getInvalidUChars(cnv, invalidUChars, &invalidUCharCount, &minorErrorCode); 136ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes if (U_SUCCESS(minorErrorCode)) { 1372981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes myData[2] = invalidUCharCount; 138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1405ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes 1415ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes // Managed code handles some cases; throw all other errors. 1425ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (shouldCodecThrow(flush, errorCode)) { 1435ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "ucnv_fromUnicode", errorCode); 1445ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return errorCode; 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1487d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jint NativeConverter_decode(JNIEnv* env, jclass, jlong address, 1497d52d787302b862019da41aa753646d88d43fd61Elliott Hughes jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, 1507d52d787302b862019da41aa753646d88d43fd61Elliott Hughes jintArray data, jboolean flush) { 1517d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 152ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 15364101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (cnv == NULL) { 1545ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR); 15564101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 15664101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 157ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedByteArrayRO uSource(env, source); 15864101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (uSource.get() == NULL) { 1595ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR); 16064101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 16164101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 162ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedCharArrayRW uTarget(env, target); 16364101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (uTarget.get() == NULL) { 1645ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR); 16564101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 16664101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes } 167ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes ScopedIntArrayRW myData(env, data); 16864101124267c6a0a9a12dc854bdec39cbc506259Elliott Hughes if (myData.get() == NULL) { 1695ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR); 170ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes return U_ILLEGAL_ARGUMENT_ERROR; 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 173ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes // Do the conversion. 174ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes jint* sourceOffset = &myData[0]; 175ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes jint* targetOffset = &myData[1]; 176583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes const char* mySource = reinterpret_cast<const char*>(uSource.get() + *sourceOffset); 177ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes const char* mySourceLimit = reinterpret_cast<const char*>(uSource.get() + sourceEnd); 178ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UChar* cTarget = uTarget.get() + *targetOffset; 179ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes const UChar* cTargetLimit = uTarget.get() + targetEnd; 180ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 181583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes ucnv_toUnicode(cnv, &cTarget, cTargetLimit, &mySource, mySourceLimit, NULL, flush, &errorCode); 182583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes *sourceOffset = mySource - reinterpret_cast<const char*>(uSource.get()) - *sourceOffset; 183ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes *targetOffset = cTarget - uTarget.get() - *targetOffset; 184ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes 185ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes // If there was an error, count the problematic bytes. 186ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND) { 1872981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes int8_t invalidByteCount = 32; 1882981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes char invalidBytes[32] = {'\0'}; 1892981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes UErrorCode minorErrorCode = U_ZERO_ERROR; 1902981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes ucnv_getInvalidChars(cnv, invalidBytes, &invalidByteCount, &minorErrorCode); 191ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes if (U_SUCCESS(minorErrorCode)) { 1922981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes myData[2] = invalidByteCount; 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1965ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes // Managed code handles some cases; throw all other errors. 1975ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (shouldCodecThrow(flush, errorCode)) { 1985ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "ucnv_toUnicode", errorCode); 1995ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } 200ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes return errorCode; 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2037d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic void NativeConverter_resetByteToChar(JNIEnv*, jclass, jlong address) { 204ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 205bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (cnv) { 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ucnv_resetToUnicode(cnv); 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2107d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic void NativeConverter_resetCharToByte(JNIEnv*, jclass, jlong address) { 211ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 212bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (cnv) { 213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ucnv_resetFromUnicode(cnv); 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2177d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jint NativeConverter_getMaxBytesPerChar(JNIEnv*, jclass, jlong address) { 218ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 219bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return (cnv != NULL) ? ucnv_getMaxCharSize(cnv) : -1; 220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2227d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jint NativeConverter_getMinBytesPerChar(JNIEnv*, jclass, jlong address) { 223ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 224bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return (cnv != NULL) ? ucnv_getMinCharSize(cnv) : -1; 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2277d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jfloat NativeConverter_getAveBytesPerChar(JNIEnv*, jclass, jlong address) { 228ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 229c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes return (cnv != NULL) ? ((ucnv_getMaxCharSize(cnv) + ucnv_getMinCharSize(cnv)) / 2.0) : -1; 230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 231bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes 2327d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jboolean NativeConverter_canEncode(JNIEnv*, jclass, jlong address, jint codeUnit) { 233583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 234ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 235583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes if (cnv == NULL) { 236583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes return JNI_FALSE; 237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 238583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes 239583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes UChar srcBuffer[3]; 240583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes const UChar* src = &srcBuffer[0]; 241583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes const UChar* srcLimit = (codeUnit < 0x10000) ? &src[1] : &src[2]; 242583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes 243583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes char dstBuffer[5]; 244583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes char* dst = &dstBuffer[0]; 245583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes const char* dstLimit = &dstBuffer[4]; 246583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes 247583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes int i = 0; 248583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes UTF_APPEND_CHAR(&srcBuffer[0], i, 2, codeUnit); 249583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes 250583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes ucnv_fromUnicode(cnv, &dst, dstLimit, &src, srcLimit, NULL, TRUE, &errorCode); 251583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes return U_SUCCESS(errorCode); 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 254ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes/* 255ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * If a charset listed in the IANA Charset Registry is supported by an implementation 256ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * of the Java platform then its canonical name must be the name listed in the registry. 257ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * Many charsets are given more than one name in the registry, in which case the registry 258ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * identifies one of the names as MIME-preferred. If a charset has more than one registry 259ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * name then its canonical name must be the MIME-preferred name and the other names in 260ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * the registry must be valid aliases. If a supported charset is not listed in the IANA 261ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes * registry then its canonical name must begin with one of the strings "X-" or "x-". 262ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes */ 26344e0e560c92338110953ce806df475fedcdf926eBrian Carlstromstatic jstring getJavaCanonicalName(JNIEnv* env, const char* icuCanonicalName) { 264ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes UErrorCode status = U_ZERO_ERROR; 265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 266ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes // Check to see if this is a well-known MIME or IANA name. 267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project const char* cName = NULL; 268ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes if ((cName = ucnv_getStandardName(icuCanonicalName, "MIME", &status)) != NULL) { 269ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes return env->NewStringUTF(cName); 270ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes } else if ((cName = ucnv_getStandardName(icuCanonicalName, "IANA", &status)) != NULL) { 271ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes return env->NewStringUTF(cName); 272ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes } 273ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes 274ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes // Check to see if an alias already exists with "x-" prefix, if yes then 275ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes // make that the canonical name. 276ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes int32_t aliasCount = ucnv_countAliases(icuCanonicalName, &status); 277ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes for (int i = 0; i < aliasCount; ++i) { 278ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes const char* name = ucnv_getAlias(icuCanonicalName, i, &status); 279ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes if (name != NULL && name[0] == 'x' && name[1] == '-') { 280ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes return env->NewStringUTF(name); 281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 284ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes // As a last resort, prepend "x-" to any alias and make that the canonical name. 285ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes status = U_ZERO_ERROR; 286ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes const char* name = ucnv_getStandardName(icuCanonicalName, "UTR22", &status); 287ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes if (name == NULL && strchr(icuCanonicalName, ',') != NULL) { 288ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes name = ucnv_getAlias(icuCanonicalName, 1, &status); 289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 290ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes // If there is no UTR22 canonical name then just return the original name. 291ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes if (name == NULL) { 292ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes name = icuCanonicalName; 293ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes } 294ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes UniquePtr<char[]> result(new char[2 + strlen(name) + 1]); 295ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes strcpy(&result[0], "x-"); 296ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes strcat(&result[0], name); 297ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes return env->NewStringUTF(&result[0]); 298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 3007d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jobjectArray NativeConverter_getAvailableCharsetNames(JNIEnv* env, jclass) { 301bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes int32_t num = ucnv_countAvailable(); 302a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes jobjectArray result = env->NewObjectArray(num, JniConstants::stringClass, NULL); 303ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes if (result == NULL) { 304ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes return NULL; 305ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes } 306bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes for (int i = 0; i < num; ++i) { 307bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes const char* name = ucnv_getAvailableName(i); 3088044bf6b446c93cd29c5753544246316f269064fElliott Hughes ScopedLocalRef<jstring> javaCanonicalName(env, getJavaCanonicalName(env, name)); 309ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes if (javaCanonicalName.get() == NULL) { 310ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes return NULL; 311ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes } 3128044bf6b446c93cd29c5753544246316f269064fElliott Hughes env->SetObjectArrayElement(result, i, javaCanonicalName.get()); 313ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes if (env->ExceptionCheck()) { 314ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes return NULL; 315ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes } 316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 317bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return result; 318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 320bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughesstatic jobjectArray getAliases(JNIEnv* env, const char* icuCanonicalName) { 321bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Get an upper bound on the number of aliases... 322bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes const char* myEncName = icuCanonicalName; 323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project UErrorCode error = U_ZERO_ERROR; 324ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes size_t aliasCount = ucnv_countAliases(myEncName, &error); 325bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (aliasCount == 0 && myEncName[0] == 'x' && myEncName[1] == '-') { 326bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes myEncName = myEncName + 2; 327bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes aliasCount = ucnv_countAliases(myEncName, &error); 328bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 329bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (!U_SUCCESS(error)) { 330bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 331bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 333bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Collect the aliases we want... 334ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes std::vector<std::string> aliases; 335ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes for (size_t i = 0; i < aliasCount; ++i) { 336ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes const char* name = ucnv_getAlias(myEncName, i, &error); 337bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (!U_SUCCESS(error)) { 338bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 339bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 340bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // TODO: why do we ignore these ones? 341bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (strchr(name, '+') == 0 && strchr(name, ',') == 0) { 342ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes aliases.push_back(name); 343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 345ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes return toStringArray(env, aliases); 346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 348bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughesstatic const char* getICUCanonicalName(const char* name) { 349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project UErrorCode error = U_ZERO_ERROR; 350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project const char* canonicalName = NULL; 351bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if ((canonicalName = ucnv_getCanonicalName(name, "MIME", &error)) != NULL) { 352bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return canonicalName; 353bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } else if((canonicalName = ucnv_getCanonicalName(name, "IANA", &error)) != NULL) { 354bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return canonicalName; 355bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } else if((canonicalName = ucnv_getCanonicalName(name, "", &error)) != NULL) { 356bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return canonicalName; 357bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } else if((canonicalName = ucnv_getAlias(name, 0, &error)) != NULL) { 358bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes /* we have some aliases in the form x-blah .. match those first */ 359bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return canonicalName; 360bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } else if (strstr(name, "x-") == name) { 361bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes /* check if the converter can be opened with the name given */ 362bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes error = U_ZERO_ERROR; 3637d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UniqueUConverter cnv(ucnv_open(name + 2, &error)); 3647d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (cnv.get() != NULL) { 365bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return name + 2; 366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 368bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 371cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughesstatic void CHARSET_ENCODER_CALLBACK(const void* rawContext, UConverterFromUnicodeArgs* args, 372cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, 373cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UErrorCode* status) { 374cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (!rawContext) { 375cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 376cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 377cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const EncoderCallbackContext* ctx = reinterpret_cast<const EncoderCallbackContext*>(rawContext); 378cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes switch(reason) { 379cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_UNASSIGNED: 380cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes ctx->onUnmappableInput(ctx, args, codeUnits, length, codePoint, reason, status); 381cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 382cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_ILLEGAL: 383cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_IRREGULAR: 384cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes ctx->onMalformedInput(ctx, args, codeUnits, length, codePoint, reason, status); 385cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 3869b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes case UCNV_CLOSE: 3879b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes delete ctx; 3889b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes return; 389cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes default: 390cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes *status = U_ILLEGAL_ARGUMENT_ERROR; 391cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 39299c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes } 393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 395c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughesstatic void encoderReplaceCallback(const void* rawContext, 396acce5ff29455054faa08a10e1486a156b9d1553eElliott Hughes UConverterFromUnicodeArgs* fromArgs, const UChar*, int32_t, UChar32, 397cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterCallbackReason, UErrorCode * err) { 398cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (rawContext == NULL) { 399cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 400cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 401cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const EncoderCallbackContext* context = reinterpret_cast<const EncoderCallbackContext*>(rawContext); 402cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes *err = U_ZERO_ERROR; 40337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_cbFromUWriteBytes(fromArgs, context->replacementBytes, context->replacementByteCount, 0, err); 404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4061698d148fba5718d68de04df1b726940c50fd015Elliott Hughesstatic UConverterFromUCallback getFromUCallback(int32_t mode) { 407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project switch(mode) { 4082981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes case NativeConverter_IGNORE: return UCNV_FROM_U_CALLBACK_SKIP; 4092981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes case NativeConverter_REPLACE: return encoderReplaceCallback; 4102981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes case NativeConverter_REPORT: return UCNV_FROM_U_CALLBACK_STOP; 411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 412cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes abort(); 413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4155ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesstatic void NativeConverter_setCallbackEncode(JNIEnv* env, jclass, jlong address, 41637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes jint onMalformedInput, jint onUnmappableInput, jbyteArray javaReplacement) { 417ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 4185ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (cnv == NULL) { 4195ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR); 4205ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return; 421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 42237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 42337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes UConverterFromUCallback oldCallback = NULL; 42437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes const void* oldCallbackContext = NULL; 42537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_getFromUCallBack(cnv, &oldCallback, const_cast<const void**>(&oldCallbackContext)); 42637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 42737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes EncoderCallbackContext* callbackContext = const_cast<EncoderCallbackContext*>( 42837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes reinterpret_cast<const EncoderCallbackContext*>(oldCallbackContext)); 42937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes if (callbackContext == NULL) { 43037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext = new EncoderCallbackContext; 43137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes } 43237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 43337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->onMalformedInput = getFromUCallback(onMalformedInput); 43437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->onUnmappableInput = getFromUCallback(onUnmappableInput); 43537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 43637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ScopedByteArrayRO replacementBytes(env, javaReplacement); 43737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes if (replacementBytes.get() == NULL) { 4385ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "replacementBytes", U_ILLEGAL_ARGUMENT_ERROR); 4395ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return; 440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 44137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes memcpy(callbackContext->replacementBytes, replacementBytes.get(), replacementBytes.size()); 44237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->replacementByteCount = replacementBytes.size(); 44337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 444cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 44537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_setFromUCallBack(cnv, CHARSET_ENCODER_CALLBACK, callbackContext, NULL, NULL, &errorCode); 4465ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "ucnv_setFromUCallBack", errorCode); 447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 449c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughesstatic void decoderIgnoreCallback(const void*, UConverterToUnicodeArgs*, const char*, int32_t, UConverterCallbackReason, UErrorCode* err) { 450c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes // The icu4c UCNV_FROM_U_CALLBACK_SKIP callback requires that the context is NULL, which is 451c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes // never true for us. 452c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes *err = U_ZERO_ERROR; 453c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes} 454c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes 455c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughesstatic void decoderReplaceCallback(const void* rawContext, 456cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterToUnicodeArgs* toArgs, const char*, int32_t, UConverterCallbackReason, 457cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UErrorCode* err) { 458cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (!rawContext) { 459cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 46099c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes } 461cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const DecoderCallbackContext* context = reinterpret_cast<const DecoderCallbackContext*>(rawContext); 462cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes *err = U_ZERO_ERROR; 46337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_cbToUWriteUChars(toArgs,context->replacementChars, context->replacementCharCount, 0, err); 464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 466cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughesstatic UConverterToUCallback getToUCallback(int32_t mode) { 467cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes switch (mode) { 468c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes case NativeConverter_IGNORE: return decoderIgnoreCallback; 469c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes case NativeConverter_REPLACE: return decoderReplaceCallback; 470c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes case NativeConverter_REPORT: return UCNV_TO_U_CALLBACK_STOP; 471cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 472cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes abort(); 473cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes} 474cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes 475cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughesstatic void CHARSET_DECODER_CALLBACK(const void* rawContext, UConverterToUnicodeArgs* args, 476cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const char* codeUnits, int32_t length, 477cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UConverterCallbackReason reason, UErrorCode* status) { 478cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (!rawContext) { 479cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 480cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 481cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes const DecoderCallbackContext* ctx = reinterpret_cast<const DecoderCallbackContext*>(rawContext); 482cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes switch(reason) { 483cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_UNASSIGNED: 484cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes ctx->onUnmappableInput(ctx, args, codeUnits, length, reason, status); 485cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 486cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_ILLEGAL: 487cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes case UCNV_IRREGULAR: 488cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes ctx->onMalformedInput(ctx, args, codeUnits, length, reason, status); 489cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 4909b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes case UCNV_CLOSE: 4919b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes delete ctx; 4929b4866d3438f42fb2c0df788989261afe72bf713Elliott Hughes return; 493cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes default: 494cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes *status = U_ILLEGAL_ARGUMENT_ERROR; 495cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return; 496cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 497cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes} 498cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes 4995ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesstatic void NativeConverter_setCallbackDecode(JNIEnv* env, jclass, jlong address, 50037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes jint onMalformedInput, jint onUnmappableInput, jstring javaReplacement) { 501ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 502ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes if (cnv == NULL) { 5035ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "toConverter", U_ILLEGAL_ARGUMENT_ERROR); 5045ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return; 505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 50737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes UConverterToUCallback oldCallback; 50837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes const void* oldCallbackContext; 50937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_getToUCallBack(cnv, &oldCallback, &oldCallbackContext); 51037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 51137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes DecoderCallbackContext* callbackContext = const_cast<DecoderCallbackContext*>( 51237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes reinterpret_cast<const DecoderCallbackContext*>(oldCallbackContext)); 51337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes if (callbackContext == NULL) { 51437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext = new DecoderCallbackContext; 51537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes } 51637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 51737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->onMalformedInput = getToUCallback(onMalformedInput); 51837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->onUnmappableInput = getToUCallback(onUnmappableInput); 51937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 52037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ScopedStringChars replacement(env, javaReplacement); 52137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes if (replacement.get() == NULL) { 5225ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "replacement", U_ILLEGAL_ARGUMENT_ERROR); 5235ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes return; 524cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 52537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes u_strncpy(callbackContext->replacementChars, replacement.get(), replacement.size()); 52637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes callbackContext->replacementCharCount = replacement.size(); 52737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes 528cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 52937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_setToUCallBack(cnv, CHARSET_DECODER_CALLBACK, callbackContext, NULL, NULL, &errorCode); 5305ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes maybeThrowIcuException(env, "ucnv_setToUCallBack", errorCode); 531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5337d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jfloat NativeConverter_getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) { 5347d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return (1 / (jfloat) NativeConverter_getMaxBytesPerChar(env, NULL, handle)); 535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5377d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jbyteArray NativeConverter_getSubstitutionBytes(JNIEnv* env, jclass, jlong address) { 538ac0ccbb85b4a96ba79b4e770f5b71687bf8f25e9Elliott Hughes UConverter* cnv = toUConverter(address); 539cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (cnv == NULL) { 540cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return NULL; 541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 542cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes UErrorCode status = U_ZERO_ERROR; 54337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes char replacementBytes[MAX_REPLACEMENT_LENGTH]; 54437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes int8_t len = sizeof(replacementBytes); 54537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes ucnv_getSubstChars(cnv, replacementBytes, &len, &status); 546cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (!U_SUCCESS(status)) { 547cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return env->NewByteArray(0); 548cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 549cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes jbyteArray result = env->NewByteArray(len); 550cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes if (result == NULL) { 551cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return NULL; 552cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 55337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes env->SetByteArrayRegion(result, 0, len, reinterpret_cast<jbyte*>(replacementBytes)); 554cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes return result; 555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5577d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jboolean NativeConverter_contains(JNIEnv* env, jclass, jstring name1, jstring name2) { 5587d52d787302b862019da41aa753646d88d43fd61Elliott Hughes ScopedUtfChars name1Chars(env, name1); 5597d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (name1Chars.c_str() == NULL) { 5607d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return JNI_FALSE; 561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 5627d52d787302b862019da41aa753646d88d43fd61Elliott Hughes ScopedUtfChars name2Chars(env, name2); 5637d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (name2Chars.c_str() == NULL) { 5647d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return JNI_FALSE; 5657d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 5667d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 5677d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UErrorCode errorCode = U_ZERO_ERROR; 5687d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UniqueUConverter converter1(ucnv_open(name1Chars.c_str(), &errorCode)); 5697d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UnicodeSet set1; 5707d52d787302b862019da41aa753646d88d43fd61Elliott Hughes ucnv_getUnicodeSet(converter1.get(), set1.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode); 5717d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 5727d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UniqueUConverter converter2(ucnv_open(name2Chars.c_str(), &errorCode)); 5737d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UnicodeSet set2; 5747d52d787302b862019da41aa753646d88d43fd61Elliott Hughes ucnv_getUnicodeSet(converter2.get(), set2.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode); 5757d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 5767d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return U_SUCCESS(errorCode) && set1.containsAll(set2); 577bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes} 578bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes 5797d52d787302b862019da41aa753646d88d43fd61Elliott Hughesstatic jobject NativeConverter_charsetForName(JNIEnv* env, jclass, jstring charsetName) { 580bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes ScopedUtfChars charsetNameChars(env, charsetName); 58105960876dff6a5b686821eed8f7ae7cef5af4f50Elliott Hughes if (charsetNameChars.c_str() == NULL) { 582bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 583bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 584bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Get ICU's canonical name for this charset. 5850808cae1a2616ba9c708c7cc4489723b4060178eElliott Hughes const char* icuCanonicalName = getICUCanonicalName(charsetNameChars.c_str()); 586bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (icuCanonicalName == NULL) { 587bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 588bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 589bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Get Java's canonical name for this charset. 590bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes jstring javaCanonicalName = getJavaCanonicalName(env, icuCanonicalName); 591bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (env->ExceptionOccurred()) { 592bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 593bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 594bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes 595bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Check that this charset is supported. 596e1d0ebb5a4ccfe3c3f5faec1fbdf5e470fd63104Elliott Hughes // ICU doesn't offer any "isSupported", so we just open and immediately close. 597e1d0ebb5a4ccfe3c3f5faec1fbdf5e470fd63104Elliott Hughes // We ignore the UErrorCode because ucnv_open returning NULL is all the information we need. 598e1d0ebb5a4ccfe3c3f5faec1fbdf5e470fd63104Elliott Hughes UErrorCode dummy = U_ZERO_ERROR; 5997d52d787302b862019da41aa753646d88d43fd61Elliott Hughes UniqueUConverter cnv(ucnv_open(icuCanonicalName, &dummy)); 6007d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (cnv.get() == NULL) { 601bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 602bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 6037d52d787302b862019da41aa753646d88d43fd61Elliott Hughes cnv.reset(); 604bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes 605bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Get the aliases for this charset. 606bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes jobjectArray aliases = getAliases(env, icuCanonicalName); 607bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (env->ExceptionOccurred()) { 608bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 609bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 610bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes 611bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes // Construct the CharsetICU object. 612a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes jmethodID charsetConstructor = env->GetMethodID(JniConstants::charsetICUClass, "<init>", 613bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V"); 614bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes if (env->ExceptionOccurred()) { 615bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes return NULL; 616bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes } 617a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes return env->NewObject(JniConstants::charsetICUClass, charsetConstructor, 618bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes javaCanonicalName, env->NewStringUTF(icuCanonicalName), aliases); 619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic JNINativeMethod gMethods[] = { 622e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, canEncode, "(JI)Z"), 623e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, charsetForName, "(Ljava/lang/String;)Ljava/nio/charset/Charset;"), 624e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, closeConverter, "(J)V"), 625e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, contains, "(Ljava/lang/String;Ljava/lang/String;)Z"), 626e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, decode, "(J[BI[CI[IZ)I"), 627e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, encode, "(J[CI[BI[IZ)I"), 628e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getAvailableCharsetNames, "()[Ljava/lang/String;"), 629e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getAveBytesPerChar, "(J)F"), 630e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getAveCharsPerByte, "(J)F"), 631e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getMaxBytesPerChar, "(J)I"), 632e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getMinBytesPerChar, "(J)I"), 633e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, getSubstitutionBytes, "(J)[B"), 634e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, openConverter, "(Ljava/lang/String;)J"), 635e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, resetByteToChar, "(J)V"), 636e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"), 6375ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"), 6385ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"), 639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}; 6407cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughesvoid register_libcore_icu_NativeConverter(JNIEnv* env) { 6417cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods)); 642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 643