Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * This code is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License version 2 only, as
      6  * published by the Free Software Foundation.  Google designates this
      7  * particular file as subject to the "Classpath" exception as provided
      8  * by Google in the LICENSE file that accompanied this code.
      9  *
     10  * This code is distributed in the hope that it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13  * version 2 for more details (a copy is included in the LICENSE file that
     14  * accompanied this code).
     15  *
     16  * You should have received a copy of the GNU General Public License version
     17  * 2 along with this work; if not, write to the Free Software Foundation,
     18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     19  */
     20 
     21 #include "jni.h"
     22 #include "jvm.h"
     23 #include "JNIHelp.h"
     24 #include "unicode/uchar.h"
     25 #include "unicode/uscript.h"
     26 #include <math.h>
     27 #include <stdio.h> // For BUFSIZ
     28 
     29 #define NATIVE_METHOD(className, functionName, signature) \
     30 { #functionName, signature, (void*)(className ## _ ## functionName) }
     31 
     32 JNIEXPORT jboolean JNICALL
     33 Character_isLowerCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     34   return u_islower(codePoint);
     35 }
     36 
     37 JNIEXPORT jboolean JNICALL
     38 Character_isUpperCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     39   return u_isupper(codePoint);
     40 }
     41 
     42 JNIEXPORT jboolean JNICALL
     43 Character_isTitleCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     44   return u_istitle(codePoint);
     45 }
     46 
     47 JNIEXPORT jboolean JNICALL
     48 Character_isDigitImpl(JNIEnv* env, jclass, jint codePoint) {
     49   return u_isdigit(codePoint);
     50 }
     51 
     52 JNIEXPORT jboolean JNICALL
     53 Character_isLetterImpl(JNIEnv* env, jclass, jint codePoint) {
     54   return u_isalpha(codePoint);
     55 }
     56 
     57 JNIEXPORT jboolean JNICALL
     58 Character_isLetterOrDigitImpl(JNIEnv* env, jclass, jint codePoint) {
     59   return u_isalnum(codePoint);
     60 }
     61 
     62 JNIEXPORT jboolean JNICALL
     63 Character_isAlphabeticImpl(JNIEnv* env, jclass, jint codePoint) {
     64   return u_hasBinaryProperty(codePoint, UCHAR_ALPHABETIC);
     65 }
     66 
     67 JNIEXPORT jboolean JNICALL
     68 Character_isIdeographicImpl(JNIEnv* env, jclass, jint codePoint) {
     69   return u_hasBinaryProperty(codePoint, UCHAR_IDEOGRAPHIC);
     70 }
     71 
     72 JNIEXPORT jint JNICALL
     73 Character_getTypeImpl(JNIEnv* env, jclass, jint codePoint) {
     74   return u_charType(codePoint);
     75 }
     76 
     77 JNIEXPORT jboolean JNICALL
     78 Character_isUnicodeIdentifierStartImpl(JNIEnv* env, jclass, jint codePoint) {
     79   return u_isIDStart(codePoint);
     80 }
     81 
     82 JNIEXPORT jboolean JNICALL
     83 Character_isUnicodeIdentifierPartImpl(JNIEnv* env, jclass, jint codePoint) {
     84   return u_isIDPart(codePoint);
     85 }
     86 
     87 JNIEXPORT jint JNICALL
     88 Character_toLowerCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     89   return u_tolower(codePoint);
     90 }
     91 
     92 JNIEXPORT jint JNICALL
     93 Character_toUpperCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     94   return u_toupper(codePoint);
     95 }
     96 
     97 JNIEXPORT jint JNICALL
     98 Character_toTitleCaseImpl(JNIEnv* env, jclass, jint codePoint) {
     99   return u_totitle(codePoint);
    100 }
    101 
    102 JNIEXPORT jint JNICALL
    103 Character_digitImpl(JNIEnv* env, jclass, jint codePoint, jint radix) {
    104   return u_digit(codePoint, radix);
    105 }
    106 
    107 JNIEXPORT jint JNICALL
    108 Character_getNumericValueImpl(JNIEnv* env, jclass, jint codePoint) {
    109   double result = u_getNumericValue(codePoint);
    110   if (result == U_NO_NUMERIC_VALUE) {
    111     return -1;
    112   } else if (result < 0 || floor(result + 0.5) != result) {
    113     return -2;
    114   }
    115   return static_cast<jint>(result);
    116 }
    117 
    118 JNIEXPORT jboolean JNICALL
    119 Character_isWhitespaceImpl(JNIEnv* env, jclass, jint codePoint) {
    120   return u_isWhitespace(codePoint);
    121 }
    122 
    123 JNIEXPORT jbyte JNICALL
    124 Character_getDirectionalityImpl(JNIEnv* env, jclass, jint codePoint) {
    125   return u_charDirection(codePoint);
    126 }
    127 
    128 JNIEXPORT jboolean JNICALL
    129 Character_isMirroredImpl(JNIEnv* env, jclass, jint codePoint) {
    130   return u_isMirrored(codePoint);
    131 }
    132 
    133 JNIEXPORT jboolean JNICALL
    134 Character_isDefinedImpl(JNIEnv* env, jclass, jint codePoint) {
    135   return u_isdefined(codePoint);
    136 }
    137 
    138 JNIEXPORT jboolean JNICALL
    139 Character_isIdentifierIgnorableImpl(JNIEnv* env, jclass, jint codePoint) {
    140     return u_isIDIgnorable(codePoint);
    141 }
    142 
    143 JNIEXPORT jboolean JNICALL
    144 Character_isSpaceCharImpl(JNIEnv*, jclass, jint codePoint) {
    145     return u_isJavaSpaceChar(codePoint);
    146 }
    147 
    148 JNIEXPORT jstring JNICALL
    149 Character_getNameImpl(JNIEnv* env, jclass, jint codePoint) {
    150     // U_UNICODE_CHAR_NAME gives us the modern names for characters. For control characters,
    151     // we need U_EXTENDED_CHAR_NAME to get "NULL" rather than "BASIC LATIN 0" and so on.
    152     // We could just use U_EXTENDED_CHAR_NAME except that it returns strings for characters
    153     // that aren't unassigned but that don't have names, and those strings aren't in the form
    154     // Java specifies.
    155     bool isControl = (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f));
    156     UCharNameChoice nameType = isControl ? U_EXTENDED_CHAR_NAME : U_UNICODE_CHAR_NAME;
    157     UErrorCode status = U_ZERO_ERROR;
    158     char buf[BUFSIZ]; // TODO: is there a more sensible upper bound?
    159     int32_t byteCount = u_charName(codePoint, nameType, &buf[0], sizeof(buf), &status);
    160     return (U_FAILURE(status) || byteCount == 0) ? NULL : env->NewStringUTF(buf);
    161 }
    162 
    163 static JNINativeMethod gMethods[] = {
    164   NATIVE_METHOD(Character, digitImpl, "!(II)I"),
    165   NATIVE_METHOD(Character, getDirectionalityImpl, "!(I)B"),
    166   NATIVE_METHOD(Character, getNameImpl, "(I)Ljava/lang/String;"),
    167   NATIVE_METHOD(Character, getNumericValueImpl, "!(I)I"),
    168   NATIVE_METHOD(Character, getTypeImpl, "!(I)I"),
    169   NATIVE_METHOD(Character, isAlphabeticImpl, "!(I)Z"),
    170   NATIVE_METHOD(Character, isDefinedImpl, "!(I)Z"),
    171   NATIVE_METHOD(Character, isDigitImpl, "!(I)Z"),
    172   NATIVE_METHOD(Character, isIdentifierIgnorableImpl, "!(I)Z"),
    173   NATIVE_METHOD(Character, isIdeographicImpl, "!(I)Z"),
    174   NATIVE_METHOD(Character, isLetterImpl, "!(I)Z"),
    175   NATIVE_METHOD(Character, isLetterOrDigitImpl, "!(I)Z"),
    176   NATIVE_METHOD(Character, isLowerCaseImpl, "!(I)Z"),
    177   NATIVE_METHOD(Character, isMirroredImpl, "!(I)Z"),
    178   NATIVE_METHOD(Character, isSpaceCharImpl, "!(I)Z"),
    179   NATIVE_METHOD(Character, isTitleCaseImpl, "!(I)Z"),
    180   NATIVE_METHOD(Character, isUnicodeIdentifierPartImpl, "!(I)Z"),
    181   NATIVE_METHOD(Character, isUnicodeIdentifierStartImpl, "!(I)Z"),
    182   NATIVE_METHOD(Character, isUpperCaseImpl, "!(I)Z"),
    183   NATIVE_METHOD(Character, isWhitespaceImpl, "!(I)Z"),
    184   NATIVE_METHOD(Character, toLowerCaseImpl, "!(I)I"),
    185   NATIVE_METHOD(Character, toTitleCaseImpl, "!(I)I"),
    186   NATIVE_METHOD(Character, toUpperCaseImpl, "!(I)I"),
    187 };
    188 
    189 void register_java_lang_Character(JNIEnv* env) {
    190   jniRegisterNativeMethods(env, "java/lang/Character", gMethods, NELEM(gMethods));
    191 }
    192