1/** 2******************************************************************************* 3* Copyright (C) 1996-2006, International Business Machines Corporation and * 4* others. All Rights Reserved. * 5******************************************************************************* 6* 7* 8******************************************************************************* 9*/ 10/* 11 * @(#) icujniinterface.c 1.2 00/10/11 12 * 13 * (C) Copyright IBM Corp. 2000 - All Rights Reserved 14 * A JNI wrapper to ICU native converter Interface 15 * @author: Ram Viswanadha 16 */ 17 18#include "ConverterInterface.h" 19#include "JNIHelp.h" 20#include "AndroidSystemNatives.h" 21#include "unicode/utypes.h" /* Basic ICU data types */ 22#include "unicode/ucnv.h" /* C Converter API */ 23#include "unicode/ustring.h" /* some more string functions*/ 24#include "unicode/ucnv_cb.h" /* for callback functions */ 25#include "unicode/uset.h" /* for contains function */ 26#include "ErrorCode.h" 27#include <stdlib.h> 28#include <string.h> 29 30// BEGIN android-removed 31// #define UTF_16BE "UTF-16BE" 32// #define UTF_16 "UTF-16" 33// END android-removed 34 35/* Prototype of callback for substituting user settable sub chars */ 36void JNI_TO_U_CALLBACK_SUBSTITUTE 37 (const void *,UConverterToUnicodeArgs *,const char* ,int32_t ,UConverterCallbackReason ,UErrorCode * ); 38 39/** 40 * Opens the ICU converter 41 * @param env environment handle for JNI 42 * @param jClass handle for the class 43 * @param handle buffer to recieve ICU's converter address 44 * @param converterName name of the ICU converter 45 */ 46static jlong openConverter (JNIEnv *env, jclass jClass, jstring converterName) { 47 48 UConverter* conv=NULL; 49 UErrorCode errorCode = U_ZERO_ERROR; 50 51 const char* cnvName= (const char*) (*env)->GetStringUTFChars(env, converterName,NULL); 52 if(cnvName) { 53 int count = (*env)->GetStringUTFLength(env,converterName); 54 55 conv = ucnv_open(cnvName,&errorCode); 56 } 57 (*env)->ReleaseStringUTFChars(env, converterName,cnvName); 58 59 if (icu4jni_error(env, errorCode) != FALSE) { 60 return 0; 61 } 62 63 return (jlong) conv; 64} 65 66/** 67 * Closes the ICU converter 68 * @param env environment handle for JNI 69 * @param jClass handle for the class 70 * @param handle address of ICU converter 71 */ 72static void closeConverter (JNIEnv *env, jclass jClass, jlong handle) { 73 74 UConverter* cnv = (UConverter*)(long)handle; 75 if(cnv) { 76 // BEGIN android-added 77 // Free up any contexts created in setCallback[Encode|Decode]() 78 UConverterToUCallback toAction; 79 UConverterFromUCallback fromAction; 80 void * context1 = NULL; 81 void * context2 = NULL; 82 ucnv_getToUCallBack(cnv, &toAction, &context1); 83 ucnv_getFromUCallBack(cnv, &fromAction, &context2); 84 // END android-added 85 ucnv_close(cnv); 86 // BEGIN android-added 87 if (context1 != NULL) { 88 free(context1); 89 } 90 if (context2 != NULL) { 91 free(context2); 92 } 93 // END android-added 94 } 95} 96 97/** 98 * Sets the substution mode for from Unicode conversion. Currently only 99 * two modes are supported: substitute or report 100 * @param env environment handle for JNI 101 * @param jClass handle for the class 102 * @param handle address of ICU converter 103 * @param mode the mode to set 104 */ 105static jint setSubstitutionModeCharToByte (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) { 106 107 UConverter* conv = (UConverter*)(long)handle; 108 UErrorCode errorCode =U_ZERO_ERROR; 109 110 if(conv) { 111 112 UConverterFromUCallback fromUOldAction ; 113 void* fromUOldContext; 114 void* fromUNewContext=NULL; 115 if(mode) { 116 117 ucnv_setFromUCallBack(conv, 118 UCNV_FROM_U_CALLBACK_SUBSTITUTE, 119 fromUNewContext, 120 &fromUOldAction, 121 (const void**)&fromUOldContext, 122 &errorCode); 123 124 } 125 else{ 126 127 ucnv_setFromUCallBack(conv, 128 UCNV_FROM_U_CALLBACK_STOP, 129 fromUNewContext, 130 &fromUOldAction, 131 (const void**)&fromUOldContext, 132 &errorCode); 133 134 } 135 return errorCode; 136 } 137 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 138 return errorCode; 139} 140/** 141 * Sets the substution mode for to Unicode conversion. Currently only 142 * two modes are supported: substitute or report 143 * @param env environment handle for JNI 144 * @param jClass handle for the class 145 * @param handle address of ICU converter 146 * @param mode the mode to set 147 */ 148static jint setSubstitutionModeByteToChar (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) { 149 150 UConverter* conv = (UConverter*)handle; 151 UErrorCode errorCode =U_ZERO_ERROR; 152 153 if(conv) { 154 155 UConverterToUCallback toUOldAction ; 156 void* toUOldContext; 157 void* toUNewContext=NULL; 158 if(mode) { 159 160 ucnv_setToUCallBack(conv, 161 UCNV_TO_U_CALLBACK_SUBSTITUTE, 162 toUNewContext, 163 &toUOldAction, 164 (const void**)&toUOldContext, 165 &errorCode); 166 167 } 168 else{ 169 170 ucnv_setToUCallBack(conv, 171 UCNV_TO_U_CALLBACK_STOP, 172 toUNewContext, 173 &toUOldAction, 174 (const void**)&toUOldContext, 175 &errorCode); 176 177 } 178 return errorCode; 179 } 180 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 181 return errorCode; 182} 183/** 184 * Converts a buffer of Unicode code units to target encoding 185 * @param env environment handle for JNI 186 * @param jClass handle for the class 187 * @param handle address of ICU converter 188 * @param source buffer of Unicode chars to convert 189 * @param sourceEnd limit of the source buffer 190 * @param target buffer to recieve the converted bytes 191 * @param targetEnd the limit of the target buffer 192 * @param data buffer to recieve state of the current conversion 193 * @param flush boolean that specifies end of source input 194 */ 195static jint convertCharToByte(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) { 196 197 198 UErrorCode errorCode =U_ZERO_ERROR; 199 UConverter* cnv = (UConverter*)handle; 200 if(cnv) { 201 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 202 if(myData) { 203 jint* sourceOffset = &myData[0]; 204 jint* targetOffset = &myData[1]; 205 const jchar* uSource =(jchar*) (*env)->GetPrimitiveArrayCritical(env,source, NULL); 206 if(uSource) { 207 jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL); 208 if(uTarget) { 209 const jchar* mySource = uSource+ *sourceOffset; 210 const UChar* mySourceLimit= uSource+sourceEnd; 211 char* cTarget=uTarget+ *targetOffset; 212 const char* cTargetLimit=uTarget+targetEnd; 213 214 ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource, 215 mySourceLimit,NULL,(UBool) flush, &errorCode); 216 217 *sourceOffset = (jint) (mySource - uSource)-*sourceOffset; 218 *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset; 219 if(U_FAILURE(errorCode)) { 220 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 221 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 222 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 223 return errorCode; 224 } 225 }else{ 226 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 227 } 228 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 229 }else{ 230 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 231 } 232 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 233 }else{ 234 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 235 } 236 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 237 return errorCode; 238 } 239 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 240 return errorCode; 241} 242 243static jint encode(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) { 244 245 UErrorCode ec = convertCharToByte(env,jClass,handle,source,sourceEnd, target,targetEnd,data,flush); 246 UConverter* cnv = (UConverter*)handle; 247 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 248 249 if(cnv && myData) { 250 251 UErrorCode errorCode = U_ZERO_ERROR; 252 myData[3] = ucnv_fromUCountPending(cnv, &errorCode); 253 254 if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND) { 255 int8_t count =32; 256 UChar invalidUChars[32]; 257 ucnv_getInvalidUChars(cnv,invalidUChars,&count,&errorCode); 258 259 if(U_SUCCESS(errorCode)) { 260 myData[2] = count; 261 } 262 } 263 } 264 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 265 return ec; 266} 267 268/** 269 * Converts a buffer of encoded bytes to Unicode code units 270 * @param env environment handle for JNI 271 * @param jClass handle for the class 272 * @param handle address of ICU converter 273 * @param source buffer of Unicode chars to convert 274 * @param sourceEnd limit of the source buffer 275 * @param target buffer to recieve the converted bytes 276 * @param targetEnd the limit of the target buffer 277 * @param data buffer to recieve state of the current conversion 278 * @param flush boolean that specifies end of source input 279 */ 280static jint convertByteToChar(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) { 281 282 UErrorCode errorCode =U_ZERO_ERROR; 283 UConverter* cnv = (UConverter*)handle; 284 if(cnv) { 285 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 286 if(myData) { 287 jint* sourceOffset = &myData[0]; 288 jint* targetOffset = &myData[1]; 289 290 const jbyte* uSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL); 291 if(uSource) { 292 jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL); 293 if(uTarget) { 294 const jbyte* mySource = uSource+ *sourceOffset; 295 const char* mySourceLimit= uSource+sourceEnd; 296 UChar* cTarget=uTarget+ *targetOffset; 297 const UChar* cTargetLimit=uTarget+targetEnd; 298 299 ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource, 300 mySourceLimit,NULL,(UBool) flush, &errorCode); 301 302 *sourceOffset = mySource - uSource - *sourceOffset ; 303 *targetOffset = cTarget - uTarget - *targetOffset; 304 if(U_FAILURE(errorCode)) { 305 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 306 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 307 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 308 return errorCode; 309 } 310 }else{ 311 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 312 } 313 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 314 }else{ 315 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 316 } 317 (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 318 }else{ 319 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 320 } 321 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 322 return errorCode; 323 } 324 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 325 return errorCode; 326} 327 328static jint decode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) { 329 330 jint ec = convertByteToChar(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush); 331 332 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 333 UConverter* cnv = (UConverter*)handle; 334 335 if(myData && cnv) { 336 UErrorCode errorCode = U_ZERO_ERROR; 337 myData[3] = ucnv_toUCountPending(cnv, &errorCode); 338 339 if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND ) { 340 char invalidChars[32] = {'\0'}; 341 int8_t len = 32; 342 ucnv_getInvalidChars(cnv,invalidChars,&len,&errorCode); 343 344 if(U_SUCCESS(errorCode)) { 345 myData[2] = len; 346 } 347 } 348 } 349 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 350 return ec; 351} 352static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) { 353 354 UConverter* cnv = (UConverter*)handle; 355 if(cnv) { 356 ucnv_resetToUnicode(cnv); 357 } 358} 359 360static void resetCharToByte(JNIEnv *env, jclass jClass, jlong handle) { 361 362 UConverter* cnv = (UConverter*)handle; 363 if(cnv) { 364 ucnv_resetFromUnicode(cnv); 365 } 366 367} 368 369static jint countInvalidBytes (JNIEnv *env, jclass jClass, jlong handle, jintArray length) { 370 371 UConverter* cnv = (UConverter*)handle; 372 UErrorCode errorCode = U_ZERO_ERROR; 373 if(cnv) { 374 char invalidChars[32]; 375 376 jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL); 377 if(len) { 378 ucnv_getInvalidChars(cnv,invalidChars,(int8_t*)len,&errorCode); 379 } 380 (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0); 381 return errorCode; 382 } 383 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 384 return errorCode; 385 386} 387 388 389static jint countInvalidChars(JNIEnv *env, jclass jClass, jlong handle, jintArray length) { 390 391 UErrorCode errorCode =U_ZERO_ERROR; 392 UConverter* cnv = (UConverter*)handle; 393 UChar invalidUChars[32]; 394 if(cnv) { 395 jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL); 396 if(len) { 397 ucnv_getInvalidUChars(cnv,invalidUChars,(int8_t*)len,&errorCode); 398 } 399 (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0); 400 return errorCode; 401 } 402 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 403 return errorCode; 404 405} 406 407static jint getMaxBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { 408 409 UConverter* cnv = (UConverter*)handle; 410 if(cnv) { 411 return (jint)ucnv_getMaxCharSize(cnv); 412 } 413 return -1; 414} 415 416static jint getMinBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { 417 418 UConverter* cnv = (UConverter*)handle; 419 if(cnv) { 420 return (jint)ucnv_getMinCharSize(cnv); 421 } 422 return -1; 423} 424static jfloat getAveBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) { 425 426 UConverter* cnv = (UConverter*)handle; 427 if(cnv) { 428 jfloat max = (jfloat)ucnv_getMaxCharSize(cnv); 429 jfloat min = (jfloat)ucnv_getMinCharSize(cnv); 430 return (jfloat) ( (max+min)/2 ); 431 } 432 return -1; 433} 434static jint flushByteToChar(JNIEnv *env, jclass jClass,jlong handle, jcharArray target, jint targetEnd, jintArray data) { 435 436 UErrorCode errorCode =U_ZERO_ERROR; 437 UConverter* cnv = (UConverter*)handle; 438 if(cnv) { 439 jbyte source ='\0'; 440 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 441 if(myData) { 442 jint* targetOffset = &myData[1]; 443 jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL); 444 if(uTarget) { 445 const jbyte* mySource =&source; 446 const char* mySourceLimit=&source; 447 UChar* cTarget=uTarget+ *targetOffset; 448 const UChar* cTargetLimit=uTarget+targetEnd; 449 450 ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource, 451 mySourceLimit,NULL,TRUE, &errorCode); 452 453 454 *targetOffset = (jint) ((jchar*)cTarget - uTarget)- *targetOffset; 455 if(U_FAILURE(errorCode)) { 456 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 457 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 458 return errorCode; 459 } 460 }else{ 461 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 462 } 463 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 464 465 }else{ 466 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 467 } 468 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 469 return errorCode; 470 } 471 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 472 return errorCode; 473} 474 475static jint flushCharToByte (JNIEnv *env, jclass jClass, jlong handle, jbyteArray target, jint targetEnd, jintArray data) { 476 477 UErrorCode errorCode =U_ZERO_ERROR; 478 UConverter* cnv = (UConverter*)handle; 479 jchar source = '\0'; 480 if(cnv) { 481 jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL); 482 if(myData) { 483 jint* targetOffset = &myData[1]; 484 jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL); 485 if(uTarget) { 486 const jchar* mySource = &source; 487 const UChar* mySourceLimit= &source; 488 char* cTarget=uTarget+ *targetOffset; 489 const char* cTargetLimit=uTarget+targetEnd; 490 491 ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource, 492 mySourceLimit,NULL,TRUE, &errorCode); 493 494 495 *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset; 496 if(U_FAILURE(errorCode)) { 497 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 498 499 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 500 return errorCode; 501 } 502 }else{ 503 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 504 } 505 (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0); 506 }else{ 507 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 508 } 509 (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0); 510 return errorCode; 511 } 512 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 513 return errorCode; 514} 515 516void toChars(const UChar* us, char* cs, int32_t length) { 517 UChar u; 518 while(length>0) { 519 u=*us++; 520 *cs++=(char)u; 521 --length; 522 } 523} 524static jint setSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle, jbyteArray subChars, jint length) { 525 526 UConverter* cnv = (UConverter*) handle; 527 UErrorCode errorCode = U_ZERO_ERROR; 528 if(cnv) { 529 jbyte* u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL); 530 if(u_subChars) { 531 char* mySubChars= (char*)malloc(sizeof(char)*length); 532 toChars((UChar*)u_subChars,&mySubChars[0],length); 533 ucnv_setSubstChars(cnv,mySubChars, (char)length,&errorCode); 534 if(U_FAILURE(errorCode)) { 535 (*env)->ReleasePrimitiveArrayCritical(env,subChars,mySubChars,0); 536 return errorCode; 537 } 538 free(mySubChars); 539 } 540 else{ 541 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 542 } 543 (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0); 544 return errorCode; 545 } 546 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 547 return errorCode; 548} 549 550 551#define VALUE_STRING_LENGTH 32 552 553typedef struct{ 554 int length; 555 UChar subChars[256]; 556 UBool stopOnIllegal; 557}SubCharStruct; 558 559 560static UErrorCode 561setToUCallbackSubs(UConverter* cnv,UChar* subChars, int32_t length,UBool stopOnIllegal ) { 562 SubCharStruct* substitutionCharS = (SubCharStruct*) malloc(sizeof(SubCharStruct)); 563 UErrorCode errorCode = U_ZERO_ERROR; 564 if(substitutionCharS) { 565 UConverterToUCallback toUOldAction; 566 void* toUOldContext=NULL; 567 void* toUNewContext=NULL ; 568 if(subChars) { 569 u_strncpy(substitutionCharS->subChars,subChars,length); 570 }else{ 571 substitutionCharS->subChars[length++] =0xFFFD; 572 } 573 substitutionCharS->subChars[length]=0; 574 substitutionCharS->length = length; 575 substitutionCharS->stopOnIllegal = stopOnIllegal; 576 toUNewContext = substitutionCharS; 577 578 ucnv_setToUCallBack(cnv, 579 JNI_TO_U_CALLBACK_SUBSTITUTE, 580 toUNewContext, 581 &toUOldAction, 582 (const void**)&toUOldContext, 583 &errorCode); 584 585 if(toUOldContext) { 586 SubCharStruct* temp = (SubCharStruct*) toUOldContext; 587 free(temp); 588 } 589 590 return errorCode; 591 } 592 return U_MEMORY_ALLOCATION_ERROR; 593} 594static jint setSubstitutionChars(JNIEnv *env, jclass jClass, jlong handle, jcharArray subChars, jint length) { 595 596 UErrorCode errorCode = U_ZERO_ERROR; 597 UConverter* cnv = (UConverter*) handle; 598 jchar* u_subChars=NULL; 599 if(cnv) { 600 if(subChars) { 601 int len = (*env)->GetArrayLength(env,subChars); 602 u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL); 603 if(u_subChars) { 604 errorCode = setToUCallbackSubs(cnv,u_subChars,len,FALSE); 605 }else{ 606 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 607 } 608 (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0); 609 return errorCode; 610 } 611 } 612 return U_ILLEGAL_ARGUMENT_ERROR; 613} 614 615 616void JNI_TO_U_CALLBACK_SUBSTITUTE( const void *context, UConverterToUnicodeArgs *toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode * err) { 617 618 if(context) { 619 SubCharStruct* temp = (SubCharStruct*)context; 620 if( temp) { 621 if(temp->stopOnIllegal==FALSE) { 622 if (reason > UCNV_IRREGULAR) { 623 return; 624 } 625 /* reset the error */ 626 *err = U_ZERO_ERROR; 627 ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err); 628 }else{ 629 if(reason != UCNV_UNASSIGNED) { 630 /* the caller must have set 631 * the error code accordingly 632 */ 633 return; 634 }else{ 635 *err = U_ZERO_ERROR; 636 ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err); 637 return; 638 } 639 } 640 } 641 } 642 return; 643} 644 645static jboolean canEncode(JNIEnv *env, jclass jClass, jlong handle, jint codeUnit) { 646 647 UErrorCode errorCode =U_ZERO_ERROR; 648 UConverter* cnv = (UConverter*)handle; 649 if(cnv) { 650 UChar source[3]; 651 UChar *mySource=source; 652 const UChar* sourceLimit = (codeUnit<0x010000) ? &source[1] : &source[2]; 653 char target[5]; 654 char *myTarget = target; 655 const char* targetLimit = &target[4]; 656 int i=0; 657 UTF_APPEND_CHAR(&source[0],i,2,codeUnit); 658 659 ucnv_fromUnicode(cnv,&myTarget,targetLimit, 660 (const UChar**)&mySource, 661 sourceLimit,NULL, TRUE,&errorCode); 662 663 if(U_SUCCESS(errorCode)) { 664 return (jboolean)TRUE; 665 } 666 } 667 return (jboolean)FALSE; 668} 669 670 671static jboolean canDecode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source) { 672 673 UErrorCode errorCode =U_ZERO_ERROR; 674 UConverter* cnv = (UConverter*)handle; 675 if(cnv) { 676 jint len = (*env)->GetArrayLength(env,source); 677 jbyte* cSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL); 678 if(cSource) { 679 const jbyte* cSourceLimit = cSource+len; 680 681 /* Assume that we need at most twice the length of source */ 682 UChar* target = (UChar*) malloc(sizeof(UChar)* (len<<1)); 683 UChar* targetLimit = target + (len<<1); 684 if(target) { 685 ucnv_toUnicode(cnv,&target,targetLimit, 686 (const char**)&cSource, 687 cSourceLimit,NULL, TRUE,&errorCode); 688 689 if(U_SUCCESS(errorCode)) { 690 free(target); 691 (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0); 692 return (jboolean)TRUE; 693 } 694 } 695 free(target); 696 } 697 (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0); 698 } 699 return (jboolean)FALSE; 700} 701 702static jint countAvailable(JNIEnv *env, jclass jClass) { 703 return ucnv_countAvailable(); 704} 705 706int32_t copyString(char* dest, int32_t destCapacity, int32_t startIndex, 707 const char* src, UErrorCode* status) { 708 int32_t srcLen = 0, i=0; 709 if(U_FAILURE(*status)) { 710 return 0; 711 } 712 if(dest == NULL || src == NULL || destCapacity < startIndex) { 713 *status = U_ILLEGAL_ARGUMENT_ERROR; 714 return 0; 715 } 716 srcLen = strlen(src); 717 if(srcLen >= destCapacity) { 718 *status = U_BUFFER_OVERFLOW_ERROR; 719 return 0; 720 } 721 for(i=0; i < srcLen; i++) { 722 dest[startIndex++] = src[i]; 723 } 724 /* null terminate the buffer */ 725 dest[startIndex] = 0; /* no bounds check already made sure that we have enough room */ 726 return startIndex; 727} 728 729int32_t getJavaCanonicalName1(const char* icuCanonicalName, 730 char* canonicalName, int32_t capacity, 731 UErrorCode* status) { 732 /* 733 If a charset listed in the IANA Charset Registry is supported by an implementation 734 of the Java platform then its canonical name must be the name listed in the registry. 735 Many charsets are given more than one name in the registry, in which case the registry 736 identifies one of the names as MIME-preferred. If a charset has more than one registry 737 name then its canonical name must be the MIME-preferred name and the other names in 738 the registry must be valid aliases. If a supported charset is not listed in the IANA 739 registry then its canonical name must begin with one of the strings "X-" or "x-". 740 */ 741 int32_t retLen = 0; 742 const char* cName = NULL; 743 /* find out the alias with MIME tag */ 744 if((cName =ucnv_getStandardName(icuCanonicalName, "MIME", status)) != NULL) { 745 retLen = copyString(canonicalName, capacity, 0, cName, status); 746 /* find out the alias with IANA tag */ 747 }else if((cName =ucnv_getStandardName(icuCanonicalName, "IANA", status)) != NULL) { 748 retLen = copyString(canonicalName, capacity, 0, cName, status); 749 }else { 750 /* 751 check to see if an alias already exists with x- prefix, if yes then 752 make that the canonical name 753 */ 754 int32_t aliasNum = ucnv_countAliases(icuCanonicalName,status); 755 int32_t i=0; 756 const char* name; 757 for(i=0;i<aliasNum;i++) { 758 name = ucnv_getAlias(icuCanonicalName,(uint16_t)i, status); 759 if(name != NULL && name[0]=='x' && name[1]=='-') { 760 retLen = copyString(canonicalName, capacity, 0, name, status); 761 break; 762 } 763 } 764 /* last resort just append x- to any of the alias and 765 make it the canonical name */ 766 if(retLen == 0 && U_SUCCESS(*status)) { 767 name = ucnv_getStandardName(icuCanonicalName, "UTR22", status); 768 if(name == NULL && strchr(icuCanonicalName, ',')!= NULL) { 769 name = ucnv_getAlias(icuCanonicalName, 1, status); 770 if(*status == U_INDEX_OUTOFBOUNDS_ERROR) { 771 *status = U_ZERO_ERROR; 772 } 773 } 774 /* if there is no UTR22 canonical name .. then just return itself*/ 775 if(name == NULL) { 776 name = icuCanonicalName; 777 } 778 if(capacity >= 2) { 779 strcpy(canonicalName,"x-"); 780 } 781 retLen = copyString(canonicalName, capacity, 2, name, status); 782 } 783 } 784 return retLen; 785} 786 787static jobjectArray getAvailable(JNIEnv *env, jclass jClass) { 788 789 jobjectArray ret; 790 int32_t i = 0; 791 int32_t num = ucnv_countAvailable(); 792 UErrorCode error = U_ZERO_ERROR; 793 const char* name =NULL; 794 char canonicalName[256]={0}; 795 ret= (jobjectArray)(*env)->NewObjectArray( env,num, 796 (*env)->FindClass(env,"java/lang/String"), 797 (*env)->NewStringUTF(env,"")); 798 799 for(i=0;i<num;i++) { 800 name = ucnv_getAvailableName(i); 801 getJavaCanonicalName1(name, canonicalName, 256, &error); 802#if DEBUG 803 if(U_FAILURE(error)) { 804 printf("An error occurred retrieving index %i. Error: %s. \n", i, u_errorName(error)); 805 } 806 807 printf("canonical name for %s\n", canonicalName); 808#endif 809 // BEGIN android-changed 810 jstring canonName = (*env)->NewStringUTF(env,canonicalName); 811 (*env)->SetObjectArrayElement(env,ret,i,canonName); 812 (*env)->DeleteLocalRef(env, canonName); 813 // END android-changed 814 /*printf("canonical name : %s at %i\n", name,i); */ 815 canonicalName[0]='\0';/* nul terminate */ 816 } 817 return (ret); 818} 819 820static jint countAliases(JNIEnv *env, jclass jClass,jstring enc) { 821 822 UErrorCode error = U_ZERO_ERROR; 823 jint num =0; 824 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL); 825 826 if(encName) { 827 num = ucnv_countAliases(encName,&error); 828 } 829 830 (*env)->ReleaseStringUTFChars(env,enc,encName); 831 832 return num; 833} 834 835 836static jobjectArray getAliases(JNIEnv *env, jclass jClass, jstring enc) { 837 838 jobjectArray ret=NULL; 839 int32_t aliasNum = 0; 840 UErrorCode error = U_ZERO_ERROR; 841 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL); 842 int i=0; 843 int j=0; 844 const char* aliasArray[50]; 845 // BEGIN android-removed 846 // int32_t utf16AliasNum = 0; 847 // END android-removed 848 849 850 if(encName) { 851 const char* myEncName = encName; 852 aliasNum = ucnv_countAliases(myEncName,&error); 853 854 // BEGIN android-removed 855 // /* special case for UTF-16. In java UTF-16 is always BE*/ 856 // if(strcmp(myEncName, UTF_16BE)==0) { 857 // utf16AliasNum=ucnv_countAliases(UTF_16,&error); 858 // } 859 // END android-removed 860 861 if(aliasNum==0 && encName[0] == 0x78 /*x*/ && encName[1]== 0x2d /*-*/) { 862 myEncName = encName+2; 863 aliasNum = ucnv_countAliases(myEncName,&error); 864 } 865 if(U_SUCCESS(error)) { 866 for(i=0,j=0;i<aliasNum;i++) { 867 const char* name = ucnv_getAlias(myEncName,(uint16_t)i,&error); 868 if(strchr(name,'+')==0 && strchr(name,',')==0) { 869 aliasArray[j++]= name; 870 } 871 } 872 873 // BEGIN android-removed 874 // if(utf16AliasNum>0) { 875 // for(i=0;i<utf16AliasNum;i++) { 876 // const char* name = ucnv_getAlias(UTF_16,(uint16_t)i,&error); 877 // if(strchr(name,'+')==0 && strchr(name,',')==0) { 878 // aliasArray[j++]= name; 879 // } 880 // } 881 // } 882 // END android-removed 883 884 ret = (jobjectArray)(*env)->NewObjectArray(env,j, 885 (*env)->FindClass(env,"java/lang/String"), 886 (*env)->NewStringUTF(env,"")); 887 for(;--j>=0;) { 888 // BEGIN android-changed 889 jstring alias = (*env)->NewStringUTF(env, aliasArray[j]); 890 (*env)->SetObjectArrayElement(env, ret, j, alias); 891 (*env)->DeleteLocalRef(env, alias); 892 // END android-changed 893 } 894 } 895 } 896 (*env)->ReleaseStringUTFChars(env,enc,encName); 897 898 return (ret); 899} 900 901static jstring getCanonicalName(JNIEnv *env, jclass jClass,jstring enc) { 902 903 UErrorCode error = U_ZERO_ERROR; 904 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL); 905 const char* canonicalName = ""; 906 // BEGIN android-changed 907 jstring ret = NULL; 908 if(encName) { 909 canonicalName = ucnv_getAlias(encName,0,&error); 910 if(canonicalName !=NULL && strstr(canonicalName,",")!=0) { 911 canonicalName = ucnv_getAlias(canonicalName,1,&error); 912 } 913 ret = ((*env)->NewStringUTF(env, canonicalName)); 914 (*env)->ReleaseStringUTFChars(env,enc,encName); 915 } 916 // END android-changed 917 return ret; 918} 919 920static jstring getICUCanonicalName(JNIEnv *env, jclass jClass, jstring enc) { 921 922 UErrorCode error = U_ZERO_ERROR; 923 const char* encName = (*env)->GetStringUTFChars(env,enc,NULL); 924 const char* canonicalName = NULL; 925 jstring ret = NULL; 926 if(encName) { 927 // BEGIN android-removed 928 // if(strcmp(encName,"UTF-16")==0) { 929 // ret = ((*env)->NewStringUTF(env,UTF_16BE)); 930 // }else 931 // END android-removed 932 if((canonicalName = ucnv_getCanonicalName(encName, "MIME", &error))!=NULL) { 933 ret = ((*env)->NewStringUTF(env, canonicalName)); 934 }else if((canonicalName = ucnv_getCanonicalName(encName, "IANA", &error))!=NULL) { 935 ret = ((*env)->NewStringUTF(env, canonicalName)); 936 }else if((canonicalName = ucnv_getCanonicalName(encName, "", &error))!=NULL) { 937 ret = ((*env)->NewStringUTF(env, canonicalName)); 938 }else if((canonicalName = ucnv_getAlias(encName, 0, &error)) != NULL) { 939 /* we have some aliases in the form x-blah .. match those first */ 940 ret = ((*env)->NewStringUTF(env, canonicalName)); 941 }else if( ret ==NULL && strstr(encName, "x-") == encName) { 942 /* check if the converter can be opened with the encName given */ 943 UConverter* conv = NULL; 944 error = U_ZERO_ERROR; 945 conv = ucnv_open(encName+2, &error); 946 if(conv!=NULL) { 947 ret = ((*env)->NewStringUTF(env, encName+2)); 948 }else{ 949 /* unsupported encoding */ 950 ret = ((*env)->NewStringUTF(env, "")); 951 } 952 ucnv_close(conv); 953 }else{ 954 /* unsupported encoding */ 955 ret = ((*env)->NewStringUTF(env, "")); 956 } 957 } 958 (*env)->ReleaseStringUTFChars(env,enc,encName); 959 return ret; 960} 961 962static jstring getJavaCanonicalName2(JNIEnv *env, jclass jClass, jstring icuCanonName) { 963 /* 964 If a charset listed in the IANA Charset Registry is supported by an implementation 965 of the Java platform then its canonical name must be the name listed in the registry. 966 Many charsets are given more than one name in the registry, in which case the registry 967 identifies one of the names as MIME-preferred. If a charset has more than one registry 968 name then its canonical name must be the MIME-preferred name and the other names in 969 the registry must be valid aliases. If a supported charset is not listed in the IANA 970 registry then its canonical name must begin with one of the strings "X-" or "x-". 971 */ 972 UErrorCode error = U_ZERO_ERROR; 973 const char* icuCanonicalName = (*env)->GetStringUTFChars(env,icuCanonName,NULL); 974 char cName[UCNV_MAX_CONVERTER_NAME_LENGTH] = {0}; 975 jstring ret; 976 if(icuCanonicalName && icuCanonicalName[0] != 0) { 977 getJavaCanonicalName1(icuCanonicalName, cName, UCNV_MAX_CONVERTER_NAME_LENGTH, &error); 978 } 979 ret = ((*env)->NewStringUTF(env, cName)); 980 (*env)->ReleaseStringUTFChars(env,icuCanonName,icuCanonicalName); 981 return ret; 982} 983 984#define SUBS_ARRAY_CAPACITY 256 985typedef struct{ 986 int length; 987 char subChars[SUBS_ARRAY_CAPACITY]; 988 UConverterFromUCallback onUnmappableInput; 989 UConverterFromUCallback onMalformedInput; 990}EncoderCallbackContext; 991 992void CHARSET_ENCODER_CALLBACK(const void *context, 993 UConverterFromUnicodeArgs *fromArgs, 994 const UChar* codeUnits, 995 int32_t length, 996 UChar32 codePoint, 997 UConverterCallbackReason reason, 998 UErrorCode * status) { 999 if(context) { 1000 EncoderCallbackContext* ctx = (EncoderCallbackContext*)context; 1001 1002 if(ctx) { 1003 UConverterFromUCallback realCB = NULL; 1004 switch(reason) { 1005 case UCNV_UNASSIGNED: 1006 realCB = ctx->onUnmappableInput; 1007 break; 1008 case UCNV_ILLEGAL:/*malformed input*/ 1009 case UCNV_IRREGULAR:/*malformed input*/ 1010 realCB = ctx->onMalformedInput; 1011 break; 1012 /* 1013 case UCNV_RESET: 1014 ucnv_resetToUnicode(args->converter); 1015 break; 1016 case UCNV_CLOSE: 1017 ucnv_close(args->converter); 1018 break; 1019 case UCNV_CLONE: 1020 ucnv_clone(args->clone); 1021 */ 1022 default: 1023 *status = U_ILLEGAL_ARGUMENT_ERROR; 1024 return; 1025 } 1026 if(realCB==NULL) { 1027 *status = U_INTERNAL_PROGRAM_ERROR; 1028 } 1029 realCB(context, fromArgs, codeUnits, length, codePoint, reason, status); 1030 } 1031 } 1032} 1033 1034void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void *context, 1035 UConverterFromUnicodeArgs *fromArgs, 1036 const UChar* codeUnits, 1037 int32_t length, 1038 UChar32 codePoint, 1039 UConverterCallbackReason reason, 1040 UErrorCode * err) { 1041 if(context) { 1042 EncoderCallbackContext* temp = (EncoderCallbackContext*)context; 1043 *err = U_ZERO_ERROR; 1044 ucnv_cbFromUWriteBytes(fromArgs,temp->subChars ,temp->length , 0, err); 1045 } 1046 return; 1047} 1048 1049UConverterFromUCallback getFromUCallback(int32_t mode) { 1050 switch(mode) { 1051 default: /* falls through */ 1052 case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK: 1053 return UCNV_FROM_U_CALLBACK_STOP; 1054 case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK: 1055 return UCNV_FROM_U_CALLBACK_SKIP ; 1056 case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK: 1057 return JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER; 1058 } 1059} 1060 1061static jint setCallbackEncode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) { 1062 1063 UConverter* conv = (UConverter*)handle; 1064 UErrorCode errorCode =U_ZERO_ERROR; 1065 1066 if(conv) { 1067 1068 UConverterFromUCallback fromUOldAction = NULL; 1069 void* fromUOldContext = NULL; 1070 EncoderCallbackContext* fromUNewContext=NULL; 1071 UConverterFromUCallback fromUNewAction=NULL; 1072 jbyte* sub = (jbyte*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL); 1073 ucnv_getFromUCallBack(conv, &fromUOldAction, &fromUOldContext); 1074 1075 /* fromUOldContext can only be DecodeCallbackContext since 1076 the converter created is private data for the decoder 1077 and callbacks can only be set via this method! 1078 */ 1079 if(fromUOldContext==NULL) { 1080 fromUNewContext = (EncoderCallbackContext*) malloc(sizeof(EncoderCallbackContext)); 1081 fromUNewAction = CHARSET_ENCODER_CALLBACK; 1082 }else{ 1083 fromUNewContext = fromUOldContext; 1084 fromUNewAction = fromUOldAction; 1085 fromUOldAction = NULL; 1086 fromUOldContext = NULL; 1087 } 1088 fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput); 1089 fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput); 1090 // BEGIN android-changed 1091 if(sub!=NULL) { 1092 fromUNewContext->length = length; 1093 strncpy(fromUNewContext->subChars, sub, length); 1094 (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0); 1095 }else{ 1096 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 1097 } 1098 // END android-changed 1099 1100 ucnv_setFromUCallBack(conv, 1101 fromUNewAction, 1102 fromUNewContext, 1103 &fromUOldAction, 1104 (const void**)&fromUOldContext, 1105 &errorCode); 1106 1107 1108 return errorCode; 1109 } 1110 return U_ILLEGAL_ARGUMENT_ERROR; 1111} 1112 1113typedef struct{ 1114 int length; 1115 UChar subUChars[256]; 1116 UConverterToUCallback onUnmappableInput; 1117 UConverterToUCallback onMalformedInput; 1118}DecoderCallbackContext; 1119 1120void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void *context, 1121 UConverterToUnicodeArgs *toArgs, 1122 const char* codeUnits, 1123 int32_t length, 1124 UConverterCallbackReason reason, 1125 UErrorCode * err) { 1126 if(context) { 1127 DecoderCallbackContext* temp = (DecoderCallbackContext*)context; 1128 *err = U_ZERO_ERROR; 1129 ucnv_cbToUWriteUChars(toArgs,temp->subUChars ,temp->length , 0, err); 1130 } 1131 return; 1132} 1133 1134UConverterToUCallback getToUCallback(int32_t mode) { 1135 switch(mode) { 1136 default: /* falls through */ 1137 case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK: 1138 return UCNV_TO_U_CALLBACK_STOP; 1139 case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK: 1140 return UCNV_TO_U_CALLBACK_SKIP ; 1141 case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK: 1142 return JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER; 1143 } 1144} 1145 1146void CHARSET_DECODER_CALLBACK(const void *context, 1147 UConverterToUnicodeArgs *args, 1148 const char* codeUnits, 1149 int32_t length, 1150 UConverterCallbackReason reason, 1151 UErrorCode *status ) { 1152 1153 if(context) { 1154 DecoderCallbackContext* ctx = (DecoderCallbackContext*)context; 1155 1156 if(ctx) { 1157 UConverterToUCallback realCB = NULL; 1158 switch(reason) { 1159 case UCNV_UNASSIGNED: 1160 realCB = ctx->onUnmappableInput; 1161 break; 1162 case UCNV_ILLEGAL:/*malformed input*/ 1163 case UCNV_IRREGULAR:/*malformed input*/ 1164 realCB = ctx->onMalformedInput; 1165 break; 1166 /* 1167 case UCNV_RESET: 1168 ucnv_resetToUnicode(args->converter); 1169 break; 1170 case UCNV_CLOSE: 1171 ucnv_close(args->converter); 1172 break; 1173 case UCNV_CLONE: 1174 ucnv_clone(args->clone); 1175 */ 1176 default: 1177 *status = U_ILLEGAL_ARGUMENT_ERROR; 1178 return; 1179 } 1180 if(realCB==NULL) { 1181 *status = U_INTERNAL_PROGRAM_ERROR; 1182 } 1183 realCB(context, args, codeUnits, length, reason, status); 1184 } 1185 } 1186} 1187 1188static jint setCallbackDecode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) { 1189 1190 UConverter* conv = (UConverter*)handle; 1191 UErrorCode errorCode =U_ZERO_ERROR; 1192 if(conv) { 1193 1194 UConverterToUCallback toUOldAction ; 1195 void* toUOldContext; 1196 DecoderCallbackContext* toUNewContext = NULL; 1197 UConverterToUCallback toUNewAction = NULL; 1198 jchar* sub = (jchar*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL); 1199 1200 ucnv_getToUCallBack(conv, &toUOldAction, &toUOldContext); 1201 1202 /* toUOldContext can only be DecodeCallbackContext since 1203 the converter created is private data for the decoder 1204 and callbacks can only be set via this method! 1205 */ 1206 if(toUOldContext==NULL) { 1207 toUNewContext = (DecoderCallbackContext*) malloc(sizeof(DecoderCallbackContext)); 1208 toUNewAction = CHARSET_DECODER_CALLBACK; 1209 }else{ 1210 toUNewContext = toUOldContext; 1211 toUNewAction = toUOldAction; 1212 toUOldAction = NULL; 1213 toUOldContext = NULL; 1214 } 1215 toUNewContext->onMalformedInput = getToUCallback(onMalformedInput); 1216 toUNewContext->onUnmappableInput = getToUCallback(onUnmappableInput); 1217 // BEGIN android-changed 1218 if(sub!=NULL) { 1219 toUNewContext->length = length; 1220 u_strncpy(toUNewContext->subUChars, sub, length); 1221 (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0); 1222 }else{ 1223 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 1224 } 1225 // END android-changed 1226 ucnv_setToUCallBack(conv, 1227 toUNewAction, 1228 toUNewContext, 1229 &toUOldAction, 1230 (const void**)&toUOldContext, 1231 &errorCode); 1232 1233 return errorCode; 1234 } 1235 return U_ILLEGAL_ARGUMENT_ERROR; 1236} 1237 1238static jlong safeClone(JNIEnv *env, jclass jClass, jlong src) { 1239 1240 UErrorCode status = U_ZERO_ERROR; 1241 1242 jint buffersize = U_CNV_SAFECLONE_BUFFERSIZE; 1243 1244 UConverter* conv=NULL; 1245 UErrorCode errorCode = U_ZERO_ERROR; 1246 UConverter* source = (UConverter*) src; 1247 1248 if(source) { 1249 conv = ucnv_safeClone(source, NULL, &buffersize, &errorCode); 1250 } 1251 1252 if (icu4jni_error(env, errorCode) != FALSE) { 1253 return NULL; 1254 } 1255 1256 return conv; 1257} 1258 1259static jint getMaxCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) { 1260 /* 1261 * currently we know that max number of chars per byte is 2 1262 */ 1263 return 2; 1264} 1265 1266static jfloat getAveCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) { 1267 jfloat ret = 0; 1268 ret = (jfloat)( 1/(jfloat)getMaxBytesPerChar(env, jClass, handle)); 1269 return ret; 1270} 1271 1272void toUChars(const char* cs, UChar* us, int32_t length) { 1273 char c; 1274 while(length>0) { 1275 c=*cs++; 1276 *us++=(char)c; 1277 --length; 1278 } 1279} 1280 1281static jbyteArray getSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle) { 1282 1283 const UConverter * cnv = (const UConverter *) handle; 1284 UErrorCode status = U_ZERO_ERROR; 1285 char subBytes[10]; 1286 int8_t len =(char)10; 1287 jbyteArray arr; 1288 if(cnv) { 1289 ucnv_getSubstChars(cnv,subBytes,&len,&status); 1290 if(U_SUCCESS(status)) { 1291 arr = ((*env)->NewByteArray(env, len)); 1292 if(arr) { 1293 (*env)->SetByteArrayRegion(env,arr,0,len,(jbyte*)subBytes); 1294 } 1295 return arr; 1296 } 1297 } 1298 return ((*env)->NewByteArray(env, 0)); 1299} 1300 1301static jboolean contains( JNIEnv *env, jclass jClass, jlong handle1, jlong handle2) { 1302 UErrorCode status = U_ZERO_ERROR; 1303 const UConverter * cnv1 = (const UConverter *) handle1; 1304 const UConverter * cnv2 = (const UConverter *) handle2; 1305 USet* set1; 1306 USet* set2; 1307 UBool bRet = 0; 1308 1309 if(cnv1 != NULL && cnv2 != NULL) { 1310 /* open charset 1 */ 1311 set1 = uset_open(1, 2); 1312 ucnv_getUnicodeSet(cnv1, set1, UCNV_ROUNDTRIP_SET, &status); 1313 1314 if(U_SUCCESS(status)) { 1315 /* open charset 2 */ 1316 status = U_ZERO_ERROR; 1317 set2 = uset_open(1, 2); 1318 ucnv_getUnicodeSet(cnv2, set2, UCNV_ROUNDTRIP_SET, &status); 1319 1320 /* contains? */ 1321 if(U_SUCCESS(status)) { 1322 bRet = uset_containsAll(set1, set2); 1323 uset_close(set2); 1324 } 1325 uset_close(set1); 1326 } 1327 } 1328 return bRet; 1329} 1330 1331/* 1332 * JNI registration 1333 */ 1334static JNINativeMethod gMethods[] = { 1335 /* name, signature, funcPtr */ 1336 { "convertByteToChar", "(J[BI[CI[IZ)I", (void*) convertByteToChar }, 1337 { "decode", "(J[BI[CI[IZ)I", (void*) decode }, 1338 { "convertCharToByte", "(J[CI[BI[IZ)I", (void*) convertCharToByte }, 1339 { "encode", "(J[CI[BI[IZ)I", (void*) encode }, 1340 { "flushCharToByte", "(J[BI[I)I", (void*) flushCharToByte }, 1341 { "flushByteToChar", "(J[CI[I)I", (void*) flushByteToChar }, 1342 { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter }, 1343 { "resetByteToChar", "(J)V", (void*) resetByteToChar }, 1344 { "resetCharToByte", "(J)V", (void*) resetCharToByte }, 1345 { "closeConverter", "(J)V", (void*) closeConverter }, 1346 { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars }, 1347 { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes }, 1348 { "setSubstitutionModeCharToByte", "(JZ)I", (void*) setSubstitutionModeCharToByte }, 1349 { "setSubstitutionModeByteToChar", "(JZ)I", (void*) setSubstitutionModeByteToChar }, 1350 { "countInvalidBytes", "(J[I)I", (void*) countInvalidBytes }, 1351 { "countInvalidChars", "(J[I)I", (void*) countInvalidChars }, 1352 { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar }, 1353 { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar }, 1354 { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar }, 1355 { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte }, 1356 { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte }, 1357 { "contains", "(JJ)Z", (void*) contains }, 1358 { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes }, 1359 { "canEncode", "(JI)Z", (void*) canEncode }, 1360 { "canDecode", "(J[B)Z", (void*) canDecode }, 1361 { "countAvailable", "()I", (void*) countAvailable }, 1362 { "getAvailable", "()[Ljava/lang/String;", (void*) getAvailable }, 1363 { "countAliases", "(Ljava/lang/String;)I", (void*) countAliases }, 1364 { "getAliases", "(Ljava/lang/String;)[Ljava/lang/String;", (void*) getAliases }, 1365 { "getCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCanonicalName }, 1366 { "getICUCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getICUCanonicalName }, 1367 { "getJavaCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getJavaCanonicalName2 }, 1368 { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode }, 1369 { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode }, 1370 { "safeClone", "(J)J", (void*) safeClone } 1371}; 1372 1373int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv *_env) { 1374 return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/charset/NativeConverter", 1375 gMethods, NELEM(gMethods)); 1376} 1377 1378 1379