1/* 2 * Copyright (C) 2007 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#include "AndroidSystemNatives.h" 18 19#include <stdlib.h> 20#include <stdio.h> 21#include <string.h> 22 23#include "unicode/uregex.h" 24#include "unicode/utypes.h" 25#include "unicode/parseerr.h" 26 27#include <jni.h> 28#include <JNIHelp.h> 29 30static jchar EMPTY_STRING = 0; 31 32/** 33 * A data structure that ties together an ICU regular expression and the 34 * character data it refers to (but does not have a copy of), so we can 35 * manage memory properly. 36 */ 37struct RegExData { 38 // A pointer to the ICU regular expression 39 URegularExpression* regex; 40 // A pointer to (a copy of) the input text that *we* manage 41 jchar* text; 42}; 43 44static void throwPatternSyntaxException(JNIEnv* env, UErrorCode status, 45 jstring pattern, UParseError error) 46{ 47 jclass clazz = env->FindClass("java/util/regex/PatternSyntaxException"); 48 jmethodID method = env->GetMethodID(clazz, "<init>", 49 "(Ljava/lang/String;Ljava/lang/String;I)V"); 50 51 jstring message = env->NewStringUTF(u_errorName(status)); 52 jthrowable except = (jthrowable)(env->NewObject(clazz, method, message, 53 pattern, error.offset)); 54 env->Throw(except); 55} 56 57static void throwRuntimeException(JNIEnv* env, UErrorCode status) { 58 jniThrowRuntimeException(env, u_errorName(status)); 59} 60 61static void _close(JNIEnv* env, jclass clazz, RegExData* data) 62{ 63 if (data->regex != NULL) { 64 uregex_close(data->regex); 65 } 66 67 if (data->text != &EMPTY_STRING) { 68 delete[] data->text; 69 } 70 71 free(data); 72} 73 74static RegExData* open(JNIEnv* env, jclass clazz, jstring pattern, jint flags) 75{ 76 flags = flags | UREGEX_ERROR_ON_UNKNOWN_ESCAPES; 77 78 RegExData* data = (RegExData*)calloc(sizeof(RegExData), 1); 79 80 UErrorCode status = U_ZERO_ERROR; 81 UParseError error; 82 error.offset = -1; 83 84 jchar const * patternRaw; 85 int patternLen = env->GetStringLength(pattern); 86 if (patternLen == 0) { 87 data->regex = uregex_open(&EMPTY_STRING, -1, flags, &error, &status); 88 } else { 89 jchar const * patternRaw = env->GetStringChars(pattern, NULL); 90 data->regex = uregex_open(patternRaw, patternLen, flags, &error, 91 &status); 92 env->ReleaseStringChars(pattern, patternRaw); 93 } 94 95 if (!U_SUCCESS(status)) { 96 _close(env, clazz, data); 97 throwPatternSyntaxException(env, status, pattern, error); 98 data = NULL; 99 } 100 101 return data; 102} 103 104static RegExData* _clone(JNIEnv* env, jclass clazz, RegExData* data) 105{ 106 UErrorCode status = U_ZERO_ERROR; 107 108 URegularExpression* clonedRegex = uregex_clone(data->regex, &status); 109 if (!U_SUCCESS(status)) { 110 throwRuntimeException(env, status); 111 } 112 113 RegExData* result = (RegExData*)calloc(sizeof(RegExData), 1); 114 result->regex = clonedRegex; 115 116 return result; 117} 118 119static void setText(JNIEnv* env, jclass clazz, RegExData* data, jstring text) 120{ 121 UErrorCode status = U_ZERO_ERROR; 122 123 uregex_setText(data->regex, &EMPTY_STRING, 0, &status); 124 if (!U_SUCCESS(status)) { 125 throwRuntimeException(env, status); 126 return; 127 } 128 129 if (data->text != &EMPTY_STRING) { 130 delete[] data->text; 131 data->text = NULL; 132 } 133 134 int textLen = env->GetStringLength(text); 135 if (textLen == 0) { 136 data->text = &EMPTY_STRING; 137 } else { 138 data->text = new jchar[textLen + 1]; 139 env->GetStringRegion(text, 0, textLen, data->text); 140 data->text[textLen] = 0; 141 } 142 143 uregex_setText(data->regex, data->text, textLen, &status); 144 if (!U_SUCCESS(status)) { 145 throwRuntimeException(env, status); 146 } 147} 148 149static jboolean matches(JNIEnv* env, jclass clazz, RegExData* data, 150 jint startIndex) 151{ 152 UErrorCode status = U_ZERO_ERROR; 153 154 jboolean result = uregex_matches(data->regex, startIndex, &status); 155 if (!U_SUCCESS(status)) { 156 throwRuntimeException(env, status); 157 } 158 159 return result; 160} 161 162static jboolean lookingAt(JNIEnv* env, jclass clazz, RegExData* data, 163 jint startIndex) 164{ 165 UErrorCode status = U_ZERO_ERROR; 166 167 jboolean result = uregex_lookingAt(data->regex, startIndex, &status); 168 if (!U_SUCCESS(status)) { 169 throwRuntimeException(env, status); 170 } 171 172 return result; 173} 174 175static jboolean find(JNIEnv* env, jclass clazz, RegExData* data, 176 jint startIndex) 177{ 178 UErrorCode status = U_ZERO_ERROR; 179 180 jboolean result = uregex_find(data->regex, startIndex, &status); 181 if (!U_SUCCESS(status)) { 182 throwRuntimeException(env, status); 183 } 184 185 return result; 186} 187 188static jboolean findNext(JNIEnv* env, jclass clazz, RegExData* data) 189{ 190 UErrorCode status = U_ZERO_ERROR; 191 192 jboolean result = uregex_findNext(data->regex, &status); 193 if (!U_SUCCESS(status)) { 194 throwRuntimeException(env, status); 195 } 196 197 return result; 198} 199 200static jint groupCount(JNIEnv* env, jclass clazz, RegExData* data) 201{ 202 UErrorCode status = U_ZERO_ERROR; 203 204 jint result = uregex_groupCount(data->regex, &status); 205 if (!U_SUCCESS(status)) { 206 throwRuntimeException(env, status); 207 } 208 209 return result; 210} 211 212static void startEnd(JNIEnv* env, jclass clazz, RegExData* data, 213 jintArray offsets) 214{ 215 UErrorCode status = U_ZERO_ERROR; 216 217 jint * offsetsRaw = env->GetIntArrayElements(offsets, NULL); 218 219 int groupCount = uregex_groupCount(data->regex, &status); 220 for (int i = 0; i <= groupCount && U_SUCCESS(status); i++) { 221 offsetsRaw[2 * i + 0] = uregex_start(data->regex, i, &status); 222 offsetsRaw[2 * i + 1] = uregex_end(data->regex, i, &status); 223 } 224 225 env->ReleaseIntArrayElements(offsets, offsetsRaw, 0); 226 227 if (!U_SUCCESS(status)) { 228 throwRuntimeException(env, status); 229 } 230} 231 232static void setRegion(JNIEnv* env, jclass clazz, RegExData* data, jint start, 233 jint end) 234{ 235 UErrorCode status = U_ZERO_ERROR; 236 uregex_setRegion(data->regex, start, end, &status); 237 if (!U_SUCCESS(status)) { 238 throwRuntimeException(env, status); 239 } 240} 241 242static jint regionStart(JNIEnv* env, jclass clazz, RegExData* data) 243{ 244 UErrorCode status = U_ZERO_ERROR; 245 int result = uregex_regionStart(data->regex, &status); 246 if (!U_SUCCESS(status)) { 247 throwRuntimeException(env, status); 248 } 249 return result; 250} 251 252static jint regionEnd(JNIEnv* env, jclass clazz, RegExData* data) 253{ 254 UErrorCode status = U_ZERO_ERROR; 255 int result = uregex_regionEnd(data->regex, &status); 256 if (!U_SUCCESS(status)) { 257 throwRuntimeException(env, status); 258 } 259 return result; 260} 261 262static void useTransparentBounds(JNIEnv* env, jclass clazz, RegExData* data, 263 jboolean value) 264{ 265 UErrorCode status = U_ZERO_ERROR; 266 uregex_useTransparentBounds(data->regex, value, &status); 267 if (!U_SUCCESS(status)) { 268 throwRuntimeException(env, status); 269 } 270} 271 272static jboolean hasTransparentBounds(JNIEnv* env, jclass clazz, RegExData* data) 273{ 274 UErrorCode status = U_ZERO_ERROR; 275 jboolean result = uregex_hasTransparentBounds(data->regex, &status); 276 if (!U_SUCCESS(status)) { 277 throwRuntimeException(env, status); 278 } 279 return result; 280} 281 282static void useAnchoringBounds(JNIEnv* env, jclass clazz, RegExData* data, 283 jboolean value) 284{ 285 UErrorCode status = U_ZERO_ERROR; 286 uregex_useAnchoringBounds(data->regex, value, &status); 287 if (!U_SUCCESS(status)) { 288 throwRuntimeException(env, status); 289 } 290} 291 292static jboolean hasAnchoringBounds(JNIEnv* env, jclass clazz, RegExData* data) 293{ 294 UErrorCode status = U_ZERO_ERROR; 295 jboolean result = uregex_hasAnchoringBounds(data->regex, &status); 296 if (!U_SUCCESS(status)) { 297 throwRuntimeException(env, status); 298 } 299 return result; 300} 301 302static jboolean hitEnd(JNIEnv* env, jclass clazz, RegExData* data) 303{ 304 UErrorCode status = U_ZERO_ERROR; 305 jboolean result = uregex_hitEnd(data->regex, &status); 306 if (!U_SUCCESS(status)) { 307 throwRuntimeException(env, status); 308 } 309 return result; 310} 311 312static jboolean requireEnd(JNIEnv* env, jclass clazz, RegExData* data) 313{ 314 UErrorCode status = U_ZERO_ERROR; 315 jboolean result = uregex_requireEnd(data->regex, &status); 316 if (!U_SUCCESS(status)) { 317 throwRuntimeException(env, status); 318 } 319 return result; 320} 321 322static void reset(JNIEnv* env, jclass clazz, RegExData* data, jint position) 323{ 324 UErrorCode status = U_ZERO_ERROR; 325 uregex_reset(data->regex, position, &status); 326 if (!U_SUCCESS(status)) { 327 throwRuntimeException(env, status); 328 } 329} 330 331static JNINativeMethod gMethods[] = { 332 { "open", "(Ljava/lang/String;I)I", (void*)open }, 333 { "clone", "(I)I", (void*)_clone }, 334 { "close", "(I)V", (void*)_close }, 335 { "setText", "(ILjava/lang/String;)V", (void*)setText }, 336 { "matches", "(II)Z", (void*)matches }, 337 { "lookingAt", "(II)Z", (void*)lookingAt }, 338 { "find", "(II)Z", (void*)find }, 339 { "findNext", "(I)Z", (void*)findNext }, 340 { "groupCount", "(I)I", (void*)groupCount }, 341 { "startEnd", "(I[I)V", (void*)startEnd }, 342 { "setRegion", "(III)V", (void*)setRegion }, 343 { "regionStart", "(I)I", (void*)regionStart }, 344 { "regionEnd", "(I)I", (void*)regionEnd }, 345 { "useTransparentBounds", "(IZ)V", (void*)useTransparentBounds }, 346 { "hasTransparentBounds", "(I)Z", (void*)hasTransparentBounds }, 347 { "useAnchoringBounds", "(IZ)V", (void*)useAnchoringBounds }, 348 { "hasAnchoringBounds", "(I)Z", (void*)hasAnchoringBounds }, 349 { "hitEnd", "(I)Z", (void*)hitEnd }, 350 { "requireEnd", "(I)Z", (void*)requireEnd }, 351 { "reset", "(II)V", (void*)reset }, 352}; 353int register_com_ibm_icu4jni_regex_NativeRegEx(JNIEnv* env) { 354 return jniRegisterNativeMethods(env, "com/ibm/icu4jni/regex/NativeRegEx", 355 gMethods, NELEM(gMethods)); 356} 357