• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Character_isLowerCaseImpl(JNIEnv * env,jclass,jint codePoint)33  Character_isLowerCaseImpl(JNIEnv* env, jclass, jint codePoint) {
34    return u_islower(codePoint);
35  }
36  
37  JNIEXPORT jboolean JNICALL
Character_isUpperCaseImpl(JNIEnv * env,jclass,jint codePoint)38  Character_isUpperCaseImpl(JNIEnv* env, jclass, jint codePoint) {
39    return u_isupper(codePoint);
40  }
41  
42  JNIEXPORT jboolean JNICALL
Character_isTitleCaseImpl(JNIEnv * env,jclass,jint codePoint)43  Character_isTitleCaseImpl(JNIEnv* env, jclass, jint codePoint) {
44    return u_istitle(codePoint);
45  }
46  
47  JNIEXPORT jboolean JNICALL
Character_isDigitImpl(JNIEnv * env,jclass,jint codePoint)48  Character_isDigitImpl(JNIEnv* env, jclass, jint codePoint) {
49    return u_isdigit(codePoint);
50  }
51  
52  JNIEXPORT jboolean JNICALL
Character_isLetterImpl(JNIEnv * env,jclass,jint codePoint)53  Character_isLetterImpl(JNIEnv* env, jclass, jint codePoint) {
54    return u_isalpha(codePoint);
55  }
56  
57  JNIEXPORT jboolean JNICALL
Character_isLetterOrDigitImpl(JNIEnv * env,jclass,jint codePoint)58  Character_isLetterOrDigitImpl(JNIEnv* env, jclass, jint codePoint) {
59    return u_isalnum(codePoint);
60  }
61  
62  JNIEXPORT jboolean JNICALL
Character_isAlphabeticImpl(JNIEnv * env,jclass,jint codePoint)63  Character_isAlphabeticImpl(JNIEnv* env, jclass, jint codePoint) {
64    return u_hasBinaryProperty(codePoint, UCHAR_ALPHABETIC);
65  }
66  
67  JNIEXPORT jboolean JNICALL
Character_isIdeographicImpl(JNIEnv * env,jclass,jint codePoint)68  Character_isIdeographicImpl(JNIEnv* env, jclass, jint codePoint) {
69    return u_hasBinaryProperty(codePoint, UCHAR_IDEOGRAPHIC);
70  }
71  
72  JNIEXPORT jint JNICALL
Character_getTypeImpl(JNIEnv * env,jclass,jint codePoint)73  Character_getTypeImpl(JNIEnv* env, jclass, jint codePoint) {
74    return u_charType(codePoint);
75  }
76  
77  JNIEXPORT jboolean JNICALL
Character_isUnicodeIdentifierStartImpl(JNIEnv * env,jclass,jint codePoint)78  Character_isUnicodeIdentifierStartImpl(JNIEnv* env, jclass, jint codePoint) {
79    return u_isIDStart(codePoint);
80  }
81  
82  JNIEXPORT jboolean JNICALL
Character_isUnicodeIdentifierPartImpl(JNIEnv * env,jclass,jint codePoint)83  Character_isUnicodeIdentifierPartImpl(JNIEnv* env, jclass, jint codePoint) {
84    return u_isIDPart(codePoint);
85  }
86  
87  JNIEXPORT jint JNICALL
Character_toLowerCaseImpl(JNIEnv * env,jclass,jint codePoint)88  Character_toLowerCaseImpl(JNIEnv* env, jclass, jint codePoint) {
89    return u_tolower(codePoint);
90  }
91  
92  JNIEXPORT jint JNICALL
Character_toUpperCaseImpl(JNIEnv * env,jclass,jint codePoint)93  Character_toUpperCaseImpl(JNIEnv* env, jclass, jint codePoint) {
94    return u_toupper(codePoint);
95  }
96  
97  JNIEXPORT jint JNICALL
Character_toTitleCaseImpl(JNIEnv * env,jclass,jint codePoint)98  Character_toTitleCaseImpl(JNIEnv* env, jclass, jint codePoint) {
99    return u_totitle(codePoint);
100  }
101  
102  JNIEXPORT jint JNICALL
Character_digitImpl(JNIEnv * env,jclass,jint codePoint,jint radix)103  Character_digitImpl(JNIEnv* env, jclass, jint codePoint, jint radix) {
104    return u_digit(codePoint, radix);
105  }
106  
107  JNIEXPORT jint JNICALL
Character_getNumericValueImpl(JNIEnv * env,jclass,jint codePoint)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
Character_isWhitespaceImpl(JNIEnv * env,jclass,jint codePoint)119  Character_isWhitespaceImpl(JNIEnv* env, jclass, jint codePoint) {
120    return u_isWhitespace(codePoint);
121  }
122  
123  JNIEXPORT jbyte JNICALL
Character_getDirectionalityImpl(JNIEnv * env,jclass,jint codePoint)124  Character_getDirectionalityImpl(JNIEnv* env, jclass, jint codePoint) {
125    return u_charDirection(codePoint);
126  }
127  
128  JNIEXPORT jboolean JNICALL
Character_isMirroredImpl(JNIEnv * env,jclass,jint codePoint)129  Character_isMirroredImpl(JNIEnv* env, jclass, jint codePoint) {
130    return u_isMirrored(codePoint);
131  }
132  
133  JNIEXPORT jboolean JNICALL
Character_isDefinedImpl(JNIEnv * env,jclass,jint codePoint)134  Character_isDefinedImpl(JNIEnv* env, jclass, jint codePoint) {
135    return u_isdefined(codePoint);
136  }
137  
138  JNIEXPORT jboolean JNICALL
Character_isIdentifierIgnorableImpl(JNIEnv * env,jclass,jint codePoint)139  Character_isIdentifierIgnorableImpl(JNIEnv* env, jclass, jint codePoint) {
140      return u_isIDIgnorable(codePoint);
141  }
142  
143  JNIEXPORT jboolean JNICALL
Character_isSpaceCharImpl(JNIEnv *,jclass,jint codePoint)144  Character_isSpaceCharImpl(JNIEnv*, jclass, jint codePoint) {
145      return u_isJavaSpaceChar(codePoint);
146  }
147  
148  JNIEXPORT jstring JNICALL
Character_getNameImpl(JNIEnv * env,jclass,jint codePoint)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  
register_java_lang_Character(JNIEnv * env)189  void register_java_lang_Character(JNIEnv* env) {
190    jniRegisterNativeMethods(env, "java/lang/Character", gMethods, NELEM(gMethods));
191  }
192