1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "Character" 18 19 #include "JNIHelp.h" 20 #include "JniConstants.h" 21 #include "ScopedUtfChars.h" 22 #include "unicode/uchar.h" 23 #include "unicode/uscript.h" 24 #include <math.h> 25 #include <stdio.h> // For BUFSIZ 26 #include <stdlib.h> 27 28 static jint Character_digitImpl(JNIEnv*, jclass, jint codePoint, jint radix) { 29 return u_digit(codePoint, radix); 30 } 31 32 static jint Character_getTypeImpl(JNIEnv*, jclass, jint codePoint) { 33 return u_charType(codePoint); 34 } 35 36 static jbyte Character_getIcuDirectionality(JNIEnv*, jclass, jint codePoint) { 37 return u_charDirection(codePoint); 38 } 39 40 static jboolean Character_isMirroredImpl(JNIEnv*, jclass, jint codePoint) { 41 return u_isMirrored(codePoint); 42 } 43 44 static jstring Character_getNameImpl(JNIEnv* env, jclass, jint codePoint) { 45 // U_UNICODE_CHAR_NAME gives us the modern names for characters. For control characters, 46 // we need U_EXTENDED_CHAR_NAME to get "NULL" rather than "BASIC LATIN 0" and so on. 47 // We could just use U_EXTENDED_CHAR_NAME except that it returns strings for characters 48 // that aren't unassigned but that don't have names, and those strings aren't in the form 49 // Java specifies. 50 bool isControl = (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)); 51 UCharNameChoice nameType = isControl ? U_EXTENDED_CHAR_NAME : U_UNICODE_CHAR_NAME; 52 UErrorCode status = U_ZERO_ERROR; 53 char buf[BUFSIZ]; // TODO: is there a more sensible upper bound? 54 int32_t byteCount = u_charName(codePoint, nameType, &buf[0], sizeof(buf), &status); 55 return (U_FAILURE(status) || byteCount == 0) ? NULL : env->NewStringUTF(buf); 56 } 57 58 static jint Character_getNumericValueImpl(JNIEnv*, jclass, jint codePoint) { 59 double result = u_getNumericValue(codePoint); 60 if (result == U_NO_NUMERIC_VALUE) { 61 return -1; 62 } else if (result < 0 || floor(result + 0.5) != result) { 63 return -2; 64 } 65 return static_cast<jint>(result); 66 } 67 68 static jboolean Character_isDefinedImpl(JNIEnv*, jclass, jint codePoint) { 69 return u_isdefined(codePoint); 70 } 71 72 static jboolean Character_isDigitImpl(JNIEnv*, jclass, jint codePoint) { 73 return u_isdigit(codePoint); 74 } 75 76 static jboolean Character_isIdentifierIgnorableImpl(JNIEnv*, jclass, jint codePoint) { 77 return u_isIDIgnorable(codePoint); 78 } 79 80 static jboolean Character_isLetterImpl(JNIEnv*, jclass, jint codePoint) { 81 return u_isalpha(codePoint); 82 } 83 84 static jboolean Character_isLetterOrDigitImpl(JNIEnv*, jclass, jint codePoint) { 85 return u_isalnum(codePoint); 86 } 87 88 static jboolean Character_isSpaceCharImpl(JNIEnv*, jclass, jint codePoint) { 89 return u_isJavaSpaceChar(codePoint); 90 } 91 92 static jboolean Character_isTitleCaseImpl(JNIEnv*, jclass, jint codePoint) { 93 return u_istitle(codePoint); 94 } 95 96 static jboolean Character_isUnicodeIdentifierPartImpl(JNIEnv*, jclass, jint codePoint) { 97 return u_isIDPart(codePoint); 98 } 99 100 static jboolean Character_isUnicodeIdentifierStartImpl(JNIEnv*, jclass, jint codePoint) { 101 return u_isIDStart(codePoint); 102 } 103 104 static jboolean Character_isWhitespaceImpl(JNIEnv*, jclass, jint codePoint) { 105 return u_isWhitespace(codePoint); 106 } 107 108 static jint Character_toLowerCaseImpl(JNIEnv*, jclass, jint codePoint) { 109 return u_tolower(codePoint); 110 } 111 112 static jint Character_toTitleCaseImpl(JNIEnv*, jclass, jint codePoint) { 113 return u_totitle(codePoint); 114 } 115 116 static jint Character_toUpperCaseImpl(JNIEnv*, jclass, jint codePoint) { 117 return u_toupper(codePoint); 118 } 119 120 static jboolean Character_isUpperCaseImpl(JNIEnv*, jclass, jint codePoint) { 121 return u_isupper(codePoint); 122 } 123 124 static jboolean Character_isLowerCaseImpl(JNIEnv*, jclass, jint codePoint) { 125 return u_islower(codePoint); 126 } 127 128 static int Character_unicodeBlockForName(JNIEnv* env, jclass, jstring javaBlockName) { 129 ScopedUtfChars blockName(env, javaBlockName); 130 if (blockName.c_str() == NULL) { 131 return 0; 132 } 133 return u_getPropertyValueEnum(UCHAR_BLOCK, blockName.c_str()); 134 } 135 136 static int Character_unicodeBlockForCodePoint(JNIEnv*, jclass, jint codePoint) { 137 return ublock_getCode(codePoint); 138 } 139 140 static int Character_unicodeScriptForName(JNIEnv* env, jclass, jstring javaScriptName) { 141 ScopedUtfChars scriptName(env, javaScriptName); 142 if (scriptName.c_str() == NULL) { 143 return -1; 144 } 145 146 return u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName.c_str()); 147 } 148 149 static int Character_unicodeScriptForCodePoint(JNIEnv*, jclass, jint codePoint) { 150 UErrorCode status = U_ZERO_ERROR; 151 const UScriptCode script = uscript_getScript(codePoint, &status); 152 if (status != U_ZERO_ERROR) { 153 return -1; 154 } 155 156 return script; 157 } 158 159 static jboolean Character_isAlphabetic(JNIEnv*, jclass, jint codePoint) { 160 return u_hasBinaryProperty(codePoint, UCHAR_ALPHABETIC); 161 } 162 163 static jboolean Character_isIdeographic(JNIEnv*, jclass, jint codePoint) { 164 return u_hasBinaryProperty(codePoint, UCHAR_IDEOGRAPHIC); 165 } 166 167 static JNINativeMethod gMethods[] = { 168 NATIVE_METHOD(Character, digitImpl, "!(II)I"), 169 NATIVE_METHOD(Character, getIcuDirectionality, "!(I)B"), 170 NATIVE_METHOD(Character, getNameImpl, "(I)Ljava/lang/String;"), 171 NATIVE_METHOD(Character, getNumericValueImpl, "!(I)I"), 172 NATIVE_METHOD(Character, getTypeImpl, "!(I)I"), 173 NATIVE_METHOD(Character, isAlphabetic, "!(I)Z"), 174 NATIVE_METHOD(Character, isDefinedImpl, "!(I)Z"), 175 NATIVE_METHOD(Character, isDigitImpl, "!(I)Z"), 176 NATIVE_METHOD(Character, isIdentifierIgnorableImpl, "!(I)Z"), 177 NATIVE_METHOD(Character, isIdeographic, "!(I)Z"), 178 NATIVE_METHOD(Character, isLetterImpl, "!(I)Z"), 179 NATIVE_METHOD(Character, isLetterOrDigitImpl, "!(I)Z"), 180 NATIVE_METHOD(Character, isLowerCaseImpl, "!(I)Z"), 181 NATIVE_METHOD(Character, isMirroredImpl, "!(I)Z"), 182 NATIVE_METHOD(Character, isSpaceCharImpl, "!(I)Z"), 183 NATIVE_METHOD(Character, isTitleCaseImpl, "!(I)Z"), 184 NATIVE_METHOD(Character, isUnicodeIdentifierPartImpl, "!(I)Z"), 185 NATIVE_METHOD(Character, isUnicodeIdentifierStartImpl, "!(I)Z"), 186 NATIVE_METHOD(Character, isUpperCaseImpl, "!(I)Z"), 187 NATIVE_METHOD(Character, isWhitespaceImpl, "!(I)Z"), 188 NATIVE_METHOD(Character, toLowerCaseImpl, "!(I)I"), 189 NATIVE_METHOD(Character, toTitleCaseImpl, "!(I)I"), 190 NATIVE_METHOD(Character, toUpperCaseImpl, "!(I)I"), 191 NATIVE_METHOD(Character, unicodeBlockForName, "(Ljava/lang/String;)I"), 192 NATIVE_METHOD(Character, unicodeBlockForCodePoint, "!(I)I"), 193 NATIVE_METHOD(Character, unicodeScriptForName, "(Ljava/lang/String;)I"), 194 NATIVE_METHOD(Character, unicodeScriptForCodePoint, "!(I)I"), 195 }; 196 void register_java_lang_Character(JNIEnv* env) { 197 jniRegisterNativeMethods(env, "java/lang/Character", gMethods, NELEM(gMethods)); 198 } 199