summaryrefslogtreecommitdiffstats
path: root/icu/src/main/native
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
commitadc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch)
tree6aed8b4923ca428942cbaa7e848d50237a3d31e0 /icu/src/main/native
parent1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff)
downloadlibcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'icu/src/main/native')
-rw-r--r--icu/src/main/native/BidiWrapperInterface.c253
-rw-r--r--icu/src/main/native/BidiWrapperInterface.h132
-rw-r--r--icu/src/main/native/BreakIteratorInterface.c264
-rw-r--r--icu/src/main/native/CharacterInterface.c194
-rw-r--r--icu/src/main/native/CollationInterface.c589
-rw-r--r--icu/src/main/native/CollationInterface.h214
-rw-r--r--icu/src/main/native/ConverterInterface.c1378
-rw-r--r--icu/src/main/native/ConverterInterface.h299
-rw-r--r--icu/src/main/native/DecimalFormatInterface.cpp851
-rw-r--r--icu/src/main/native/ErrorCode.c57
-rw-r--r--icu/src/main/native/ErrorCode.h27
-rw-r--r--icu/src/main/native/RBNFInterface.cpp382
-rw-r--r--icu/src/main/native/RegExInterface.cpp373
-rw-r--r--icu/src/main/native/ResourceInterface.cpp1436
-rw-r--r--icu/src/main/native/sub.mk30
15 files changed, 6479 insertions, 0 deletions
diff --git a/icu/src/main/native/BidiWrapperInterface.c b/icu/src/main/native/BidiWrapperInterface.c
new file mode 100644
index 0000000..2c6b3cd
--- /dev/null
+++ b/icu/src/main/native/BidiWrapperInterface.c
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <unicode/ubidi.h>
+#include <string.h>
+#include "BidiWrapperInterface.h"
+
+typedef struct {
+ UBiDi *pBiDi;
+ void *embeddingLevels;
+} BiDiData;
+
+void check_fail (JNIEnv * env, int err);
+
+JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1open
+ (JNIEnv * env, jclass clazz)
+{
+ BiDiData *data = (BiDiData *)malloc(sizeof(BiDiData));
+ (*data).pBiDi = ubidi_open ();
+ (*data).embeddingLevels = NULL;
+ return (jlong) (data);
+}
+
+JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1close
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ BiDiData *data = (BiDiData *)pBiDi;
+
+ ubidi_close ((*data).pBiDi);
+
+ if ((*data).embeddingLevels != NULL)
+ free((*data).embeddingLevels);
+ free(data);
+}
+
+JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara
+ (JNIEnv * env, jclass clazz, jlong pBiDi, jcharArray text, jint length,
+ jbyte paraLevel, jbyteArray embeddingLevels)
+{
+ UErrorCode err = 0;
+ jchar *_text = NULL;
+ BiDiData *data = (BiDiData *)pBiDi;
+ /* Remembering old embedding levels */
+ void *embLvls = (*data).embeddingLevels;
+
+ _text = (*env)->GetCharArrayElements (env, text, NULL);
+
+ if (embeddingLevels != NULL)
+ {
+ jbyte *el = (*env)->GetByteArrayElements (env, embeddingLevels, NULL);
+ (*data).embeddingLevels = malloc(length);
+ memcpy(((*data).embeddingLevels), el, length);
+ (*env)->ReleaseByteArrayElements (env, embeddingLevels, el, 0);
+ } else
+ {
+ (*data).embeddingLevels = NULL;
+ }
+
+ ubidi_setPara ((*data).pBiDi, _text, length, paraLevel,
+ ((*data).embeddingLevels), &err);
+ check_fail (env, err);
+
+ /* Freeing old embedding levels */
+ if (embLvls != NULL) {
+ free(embLvls);
+ }
+
+ (*env)->ReleaseCharArrayElements (env, text, _text, 0);
+}
+
+JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine
+ (JNIEnv * env, jclass clazz, jlong pBiDi, jint start, jint limit)
+{
+ UErrorCode err = 0;
+ BiDiData *data = (BiDiData *)pBiDi;
+ BiDiData *lineData = (BiDiData *) malloc(sizeof(BiDiData));
+ (*lineData).embeddingLevels = NULL;
+
+ (*lineData).pBiDi = ubidi_openSized (limit - start, 0, &err);
+ check_fail (env, err);
+
+ ubidi_setLine ((*data).pBiDi, start, limit, (*lineData).pBiDi,
+ &err);
+ check_fail (env, err);
+
+ return (jlong) lineData;
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ BiDiData *data = (BiDiData *)pBiDi;
+ return ubidi_getDirection ((*data).pBiDi);
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ BiDiData *data = (BiDiData *)pBiDi;
+ return ubidi_getLength ((*data).pBiDi);
+}
+
+JNIEXPORT jbyte JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ BiDiData *data = (BiDiData *)pBiDi;
+ return ubidi_getParaLevel ((*data).pBiDi);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ UErrorCode err = 0;
+ const UBiDiLevel *levels = NULL;
+ jbyteArray result = NULL;
+ int len = 0;
+ BiDiData *data = (BiDiData *)pBiDi;
+
+ levels = ubidi_getLevels ((*data).pBiDi, &err);
+ check_fail (env, err);
+
+ len = ubidi_getLength ((*data).pBiDi);
+ result = (*env)->NewByteArray (env, len);
+ (*env)->SetByteArrayRegion (env, result, 0, len, (jbyte *) levels);
+
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns
+ (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+ UErrorCode err = 0;
+ BiDiData *data = (BiDiData *)pBiDi;
+
+ int count = ubidi_countRuns ((*data).pBiDi, &err);
+ check_fail (env, err);
+
+ return count;
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns
+ (JNIEnv * env, jclass clz, jlong pBiDi)
+{
+ int runCount = 0;
+ int start = 0;
+ int limit = 0;
+ int i = 0;
+ UBiDiLevel level = 0;
+ jclass run_clazz = 0;
+ jmethodID initID = 0;
+ jobject run = 0;
+ jobjectArray runs;
+ UErrorCode err = 0;
+ BiDiData *data = (BiDiData *)pBiDi;
+
+ run_clazz = (*env)->FindClass (env, "org/apache/harmony/text/BidiRun");
+ initID = (*env)->GetMethodID (env, run_clazz, "<init>", "(III)V");
+
+ runCount = ubidi_countRuns ((*data).pBiDi, &err);
+ check_fail (env, err);
+
+ runs = (*env)->NewObjectArray(env, runCount,run_clazz, NULL);
+ for (i = 0; i < runCount; i++) {
+ ubidi_getLogicalRun((*data).pBiDi, start, &limit, &level);
+ run = (*env)->NewObject (env, run_clazz, initID, start, limit, level);
+ (*env)->SetObjectArrayElement(env, runs, i, run);
+ start = limit;
+ }
+ return runs;
+}
+
+void
+check_fail (JNIEnv * env, int err)
+{
+ char message[] = "ICU Internal Error: ";
+
+ if (U_FAILURE (err))
+ {
+ sprintf (message, "ICU Internal Error: %d", err);
+ jniThrowException(env, "java/lang/RuntimeException",
+ message);
+ }
+}
+
+JNIEXPORT jintArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual
+ (JNIEnv * env, jclass clazz, jbyteArray levels, jint length)
+{
+ UBiDiLevel *local_levels = 0;
+ int *local_indexMap = 0;
+ jintArray result = 0;
+
+ local_indexMap = (int *) malloc(sizeof (int) * length);
+ local_levels = (*env)->GetByteArrayElements (env, levels, NULL);
+
+ ubidi_reorderVisual (local_levels, length, local_indexMap);
+
+ result = (*env)->NewIntArray (env, length);
+ (*env)->SetIntArrayRegion (env, result, 0, length, (jint *) local_indexMap);
+
+ free(local_indexMap);
+ (*env)->ReleaseByteArrayElements (env, levels, local_levels, 0);
+
+ return result;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* NAME , SIGNATURE , FUNCPTR */
+ { "ubidi_open" , "()J" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1open },
+ { "ubidi_close" , "(J)V" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1close },
+ { "ubidi_setPara" , "(J[CIB[B)V" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara },
+ { "ubidi_setLine" , "(JII)J" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine },
+ { "ubidi_getDirection" , "(J)I" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection },
+ { "ubidi_getLength" , "(J)I" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength },
+ { "ubidi_getParaLevel" , "(J)B" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel },
+ { "ubidi_getLevels" , "(J)[B" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels },
+ { "ubidi_countRuns" , "(J)I" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns },
+ { "ubidi_getRuns" , "(J)[Lorg/apache/harmony/text/BidiRun;",
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns },
+ { "ubidi_reorderVisual", "([BI)[I" ,
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual },
+};
+int register_org_apache_harmony_text_BidiWrapper(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "org/apache/harmony/text/BidiWrapper",
+ gMethods, NELEM(gMethods));
+}
diff --git a/icu/src/main/native/BidiWrapperInterface.h b/icu/src/main/native/BidiWrapperInterface.h
new file mode 100644
index 0000000..c73597e
--- /dev/null
+++ b/icu/src/main/native/BidiWrapperInterface.h
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <JNIHelp.h>
+/* Header for class org_apache_harmony_text_BidiWrapper */
+
+#if !defined(_Included_org_apache_harmony_text_BidiWrapper)
+#define _Included_org_apache_harmony_text_BidiWrapper
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_LTR
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_LTR 254L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_RTL
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_RTL 255L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_MAX_EXPLICIT_LEVEL
+#define org_apache_harmony_text_BidiWrapper_UBIDI_MAX_EXPLICIT_LEVEL 61L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_LEVEL_OVERRIDE
+#define org_apache_harmony_text_BidiWrapper_UBIDI_LEVEL_OVERRIDE 128L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_KEEP_BASE_COMBINING
+#define org_apache_harmony_text_BidiWrapper_UBIDI_KEEP_BASE_COMBINING 1L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DO_MIRRORING
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DO_MIRRORING 2L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_INSERT_LRM_FOR_NUMERIC
+#define org_apache_harmony_text_BidiWrapper_UBIDI_INSERT_LRM_FOR_NUMERIC 4L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_REMOVE_BIDI_CONTROLS
+#define org_apache_harmony_text_BidiWrapper_UBIDI_REMOVE_BIDI_CONTROLS 8L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_OUTPUT_REVERSE
+#define org_apache_harmony_text_BidiWrapper_UBIDI_OUTPUT_REVERSE 16L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_LTR
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_LTR 0L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_RTL
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_RTL 1L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_MIXED
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_MIXED 2L
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_open
+ * Signature: ()J
+ */
+ JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1open
+ (JNIEnv *, jclass);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_close
+ * Signature: (J)V
+ */
+ JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1close
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_setPara
+ * Signature: (J[CIB[B)V
+ */
+ JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara
+ (JNIEnv *, jclass, jlong, jcharArray, jint, jbyte, jbyteArray);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_setLine
+ * Signature: (JII)J
+ */
+ JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine
+ (JNIEnv *, jclass, jlong, jint, jint);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_getDirection
+ * Signature: (J)I
+ */
+ JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_getLength
+ * Signature: (J)I
+ */
+ JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_getParaLevel
+ * Signature: (J)B
+ */
+ JNIEXPORT jbyte JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_getLevels
+ * Signature: (J)[B
+ */
+ JNIEXPORT jbyteArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_countRuns
+ * Signature: (J)I
+ */
+ JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_getRuns
+ * Signature: (J)[Lorg/apache/harmony/text/BidiRun;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns
+ (JNIEnv *, jclass, jlong);
+/*
+ * Class: org_apache_harmony_text_BidiWrapper
+ * Method: ubidi_reorderVisual
+ * Signature: ([BI)[I
+ */
+ JNIEXPORT jintArray JNICALL
+ Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual (JNIEnv *, jclass,
+ jbyteArray, jint);
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/icu/src/main/native/BreakIteratorInterface.c b/icu/src/main/native/BreakIteratorInterface.c
new file mode 100644
index 0000000..021ace1
--- /dev/null
+++ b/icu/src/main/native/BreakIteratorInterface.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Internal native functions. All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods. This means that the GC will wait for these functions
+ * to finish. DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "ErrorCode.h"
+#include "unicode/ubrk.h"
+#include "unicode/putil.h"
+#include <stdlib.h>
+
+static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
+
+ const char * locale = ubrk_getAvailable(index);
+
+ return (*env)->NewStringUTF(env, locale);
+
+}
+
+static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
+ return ubrk_countAvailable();
+}
+
+static jint getCharacterInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+ UBreakIterator *iter = ubrk_open(UBRK_CHARACTER, localeChars, NULL, 0, &status);
+
+ (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+
+ if ( icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) iter;
+}
+
+static jint getLineInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+ enum UBreakIteratorType type = UBRK_LINE;
+
+ UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+ (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+
+ if ( icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) iter;
+}
+
+static jint getSentenceInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+ enum UBreakIteratorType type = UBRK_SENTENCE;
+
+ UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+ (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+
+ if ( icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) iter;
+}
+
+static jint getWordInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+ enum UBreakIteratorType type = UBRK_WORD;
+
+ UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+ (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+
+ if ( icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) iter;
+}
+
+static void closeBreakIteratorImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ ubrk_close(bi);
+}
+
+static jint cloneImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ jint buffersize = U_BRK_SAFECLONE_BUFFERSIZE;
+
+ UBreakIterator *iter = ubrk_safeClone(bi, NULL, &buffersize, &status);
+
+ if (icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) iter;
+}
+
+static void setTextImpl(JNIEnv *env, jclass clazz, jint address, jstring text) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ const UChar *strUChars = (*env)->GetStringChars(env, text, NULL);
+ int strLen = (*env)->GetStringLength(env, text);
+
+ ubrk_setText(bi, strUChars, strLen, &status);
+
+ (*env)->ReleaseStringChars(env, text, strUChars);
+
+ icu4jni_error(env, status);
+}
+
+static jboolean isBoundaryImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_isBoundary(bi, offset);
+}
+
+static jint nextImpl(JNIEnv *env, jclass clazz, jint address, jint n) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ if(n < 0) {
+ while(n++ < -1) {
+ ubrk_previous(bi);
+ }
+ return ubrk_previous(bi);
+ } else if(n == 0) {
+ return ubrk_current(bi);
+ } else {
+ while(n-- > 1) {
+ ubrk_next(bi);
+ }
+ return ubrk_next(bi);
+ }
+
+ return -1;
+}
+
+static jint precedingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_preceding(bi, offset);
+}
+
+static jint firstImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_first(bi);
+}
+
+static jint followingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_following(bi, offset);
+}
+
+static jint currentImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_current(bi);
+}
+
+static jint previousImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_previous(bi);
+}
+
+static jint lastImpl(JNIEnv *env, jclass clazz, jint address) {
+
+ UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+ return ubrk_last(bi);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "getAvailableLocalesImpl", "(I)Ljava/lang/String;",
+ (void*) getAvailableLocalesImpl },
+ { "getAvailableLocalesCountImpl", "()I",
+ (void*) getAvailableLocalesCountImpl },
+ { "getCharacterInstanceImpl", "(Ljava/lang/String;)I",
+ (void*) getCharacterInstanceImpl },
+ { "getLineInstanceImpl", "(Ljava/lang/String;)I",
+ (void*) getLineInstanceImpl },
+ { "getSentenceInstanceImpl", "(Ljava/lang/String;)I",
+ (void*) getSentenceInstanceImpl },
+ { "getWordInstanceImpl", "(Ljava/lang/String;)I",
+ (void*) getWordInstanceImpl },
+ { "closeBreakIteratorImpl", "(I)V",
+ (void*) closeBreakIteratorImpl },
+ { "cloneImpl", "(I)I",
+ (void*) cloneImpl },
+ { "setTextImpl", "(ILjava/lang/String;)V",
+ (void*) setTextImpl },
+ { "isBoundaryImpl", "(II)Z",
+ (void*) isBoundaryImpl },
+ { "nextImpl", "(II)I",
+ (void*) nextImpl },
+ { "precedingImpl", "(II)I",
+ (void*) precedingImpl },
+ { "firstImpl", "(I)I",
+ (void*) firstImpl },
+ { "lastImpl", "(I)I",
+ (void*) lastImpl },
+ { "currentImpl", "(I)I",
+ (void*) currentImpl },
+ { "followingImpl", "(II)I",
+ (void*) followingImpl },
+ { "previousImpl", "(I)I",
+ (void*) previousImpl },
+};
+int register_com_ibm_icu4jni_text_NativeBreakIterator(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/ibm/icu4jni/text/NativeBreakIterator",
+ gMethods, NELEM(gMethods));
+}
diff --git a/icu/src/main/native/CharacterInterface.c b/icu/src/main/native/CharacterInterface.c
new file mode 100644
index 0000000..70e9f29
--- /dev/null
+++ b/icu/src/main/native/CharacterInterface.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Internal native functions. All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods. This means that the GC will wait for these functions
+ * to finish. DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/uchar.h"
+#include <stdlib.h>
+#include <math.h>
+
+static jint digitImpl(JNIEnv *env, jclass clazz, jint codePoint, jint radix) {
+ return u_digit(codePoint, radix);
+}
+
+static jint getTypeImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_charType(codePoint);
+}
+
+static jbyte getDirectionalityImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_charDirection (codePoint);
+}
+
+static jboolean isMirroredImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isMirrored (codePoint);
+}
+
+static jint getNumericValueImpl(JNIEnv *env, jclass clazz, jint codePoint){
+ // The letters A-Z in their uppercase ('\u0041' through '\u005A'),
+ // lowercase ('\u0061' through '\u007A'),
+ // and full width variant ('\uFF21' through '\uFF3A'
+ // and '\uFF41' through '\uFF5A') forms
+ // have numeric values from 10 through 35. This is independent of the
+ // Unicode specification, which does not assign numeric values to these
+ // char values.
+ if (codePoint >= 0x41 && codePoint <= 0x5A) {
+ return codePoint - 0x37;
+ }
+ if (codePoint >= 0x61 && codePoint <= 0x7A) {
+ return codePoint - 0x57;
+ }
+ if (codePoint >= 0xFF21 && codePoint <= 0xFF3A) {
+ return codePoint - 0xFF17;
+ }
+ if (codePoint >= 0xFF41 && codePoint <= 0xFF5A) {
+ return codePoint - 0xFF37;
+ }
+
+ double result = u_getNumericValue(codePoint);
+
+ if (result == U_NO_NUMERIC_VALUE) {
+ return -1;
+ } else if (result < 0 || floor(result + 0.5) != result) {
+ return -2;
+ }
+
+ return result;
+}
+
+static jboolean isDefinedValueImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isdefined(codePoint);
+}
+
+static jboolean isDigitImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isdigit(codePoint);
+}
+
+static jboolean isIdentifierIgnorableImpl(JNIEnv *env, jclass clazz,
+ jint codePoint) {
+
+ // Java also returns TRUE for U+0085 Next Line (it omits U+0085 from whitespace ISO controls)
+ if(codePoint == 0x0085) {
+ return JNI_TRUE;
+ }
+
+ return u_isIDIgnorable(codePoint);
+}
+
+static jboolean isLetterImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isalpha(codePoint);
+}
+
+static jboolean isLetterOrDigitImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isalnum(codePoint);
+}
+
+static jboolean isSpaceCharImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isJavaSpaceChar(codePoint);
+}
+
+static jboolean isTitleCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_istitle(codePoint);
+}
+
+static jboolean isUnicodeIdentifierPartImpl(JNIEnv *env, jclass clazz,
+ jint codePoint) {
+ return u_isIDPart(codePoint);
+}
+
+static jboolean isUnicodeIdentifierStartImpl(JNIEnv *env, jclass clazz,
+ jint codePoint) {
+ return u_isIDStart(codePoint);
+}
+
+static jboolean isWhitespaceImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+
+ // Java omits U+0085
+ if(codePoint == 0x0085) {
+ return JNI_FALSE;
+ }
+
+ return u_isWhitespace(codePoint);
+}
+
+static jint toLowerCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_tolower(codePoint);
+}
+
+static jint toTitleCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_totitle(codePoint);
+}
+
+static jint toUpperCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_toupper(codePoint);
+}
+
+static jboolean isUpperCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_isupper(codePoint);
+}
+
+static jboolean isLowerCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+ return u_islower(codePoint);
+}
+
+static int forName(JNIEnv *env, jclass clazz, jstring blockName) {
+ const char *bName = (*env)->GetStringUTFChars(env, blockName, NULL);
+ int result = u_getPropertyValueEnum(UCHAR_BLOCK, bName);
+ (*env)->ReleaseStringUTFChars(env, blockName, bName);
+ return result;
+}
+
+static int codeBlock(JNIEnv *env, jclass clazz, jint codePoint) {
+ return ublock_getCode(codePoint);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "digitImpl", "(II)I", (void*) digitImpl },
+ { "getTypeImpl", "(I)I", (void*) getTypeImpl },
+ { "getDirectionalityImpl", "(I)B", (void*) getDirectionalityImpl },
+ { "isMirroredImpl", "(I)Z", (void*) isMirroredImpl },
+ { "getNumericValueImpl", "(I)I", (void*) getNumericValueImpl },
+ { "isDefinedValueImpl", "(I)Z", (void*) isDefinedValueImpl },
+ { "isDigitImpl", "(I)Z", (void*) isDigitImpl },
+ { "isIdentifierIgnorableImpl", "(I)Z", (void*) isIdentifierIgnorableImpl },
+ { "isLetterImpl", "(I)Z", (void*) isLetterImpl },
+ { "isLetterOrDigitImpl", "(I)Z", (void*) isLetterOrDigitImpl },
+ { "isSpaceCharImpl", "(I)Z", (void*) isSpaceCharImpl },
+ { "isTitleCaseImpl", "(I)Z", (void*) isTitleCaseImpl },
+ { "isUnicodeIdentifierPartImpl", "(I)Z",
+ (void*) isUnicodeIdentifierPartImpl },
+ { "isUnicodeIdentifierStartImpl", "(I)Z",
+ (void*) isUnicodeIdentifierStartImpl },
+ { "isWhitespaceImpl", "(I)Z", (void*) isWhitespaceImpl },
+ { "toLowerCaseImpl", "(I)I", (void*) toLowerCaseImpl },
+ { "toTitleCaseImpl", "(I)I", (void*) toTitleCaseImpl },
+ { "toUpperCaseImpl", "(I)I", (void*) toUpperCaseImpl },
+ { "isUpperCaseImpl", "(I)Z", (void*) isUpperCaseImpl },
+ { "isLowerCaseImpl", "(I)Z", (void*) isLowerCaseImpl },
+ { "forname", "(Ljava/lang/String;)I", (void*) forName },
+ { "codeblock", "(I)I", (void*) codeBlock }
+};
+
+int register_com_ibm_icu4jni_lang_UCharacter(JNIEnv *env) {
+ return jniRegisterNativeMethods(env, "com/ibm/icu4jni/lang/UCharacter",
+ gMethods, NELEM(gMethods));
+}
+
+
diff --git a/icu/src/main/native/CollationInterface.c b/icu/src/main/native/CollationInterface.c
new file mode 100644
index 0000000..86246ac
--- /dev/null
+++ b/icu/src/main/native/CollationInterface.c
@@ -0,0 +1,589 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "ErrorCode.h"
+#include "unicode/ucol.h"
+#include "unicode/ucoleitr.h"
+#include "ucol_imp.h"
+
+
+/**
+* Closing a C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C UCollator
+*/
+static void closeCollator(JNIEnv *env, jclass obj,
+ jint address) {
+
+ UCollator *collator = (UCollator *)(int)address;
+ ucol_close(collator);
+}
+
+
+/**
+* Close a C collation element iterator.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collation element iterator to close.
+*/
+static void closeElements(JNIEnv *env, jclass obj,
+ jint address) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ ucol_closeElements(iterator);
+}
+
+/**
+* Compare two strings.
+* The strings will be compared using the normalization mode and options
+* specified in openCollator or openCollatorFromRules
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the c collator
+* @param source The source string.
+* @param target The target string.
+* @return result of the comparison, UCOL_EQUAL, UCOL_GREATER or UCOL_LESS
+*/
+static jint compare(JNIEnv *env, jclass obj, jint address,
+ jstring source, jstring target) {
+
+ const UCollator *collator = (const UCollator *)(int)address;
+ jint result = -2;
+ if(collator){
+ jsize srclength = (*env)->GetStringLength(env, source);
+ const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
+ if(srcstr){
+ jsize tgtlength = (*env)->GetStringLength(env, target);
+ const UChar *tgtstr = (const UChar *)(*env)->GetStringCritical(env,target,0);
+ if(tgtstr){
+ result = ucol_strcoll(collator, srcstr, srclength, tgtstr, tgtlength);
+ (*env)->ReleaseStringCritical(env, source, srcstr);
+ (*env)->ReleaseStringCritical(env, target, tgtstr);
+ return result;
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ return result;
+}
+
+/**
+* Universal attribute getter
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param type type of attribute to be set
+* @return attribute value
+* @exception thrown when error occurs while getting attribute value
+*/
+static jint getAttribute(JNIEnv *env, jclass obj, jint address,
+ jint type) {
+
+ const UCollator *collator = (const UCollator *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ if(collator){
+ jint result = (jint)ucol_getAttribute(collator, (UColAttribute)type,
+ &status);
+ if (icu4jni_error(env, status) != FALSE){
+ return (jint)UCOL_DEFAULT;
+ }
+ return result;
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ return (jint)UCOL_DEFAULT;
+}
+
+/**
+* Create a CollationElementIterator object that will iterator over the elements
+* in a string, using the collation rules defined in this RuleBasedCollatorJNI
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator
+* @param source string to iterate over
+* @return address of C collationelement
+*/
+static jint getCollationElementIterator(JNIEnv *env,
+ jclass obj, jint address, jstring source) {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCollator *collator = (UCollator *)(int)address;
+ jint result=0;
+ if(collator){
+ jsize srclength = (*env)->GetStringLength(env, source);
+ const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
+ if(srcstr){
+ result = (jint)(ucol_openElements(collator, srcstr, srclength, &status));
+
+ (*env)->ReleaseStringCritical(env, source, srcstr);
+ icu4jni_error(env, status);
+ }else{
+ icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ }else{
+ icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ return result;
+}
+
+/**
+* Get the maximum length of any expansion sequences that end with the specified
+* comparison order.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator containing the text.
+* @param order collation order returned by previous or next.
+* @return maximum length of any expansion sequences ending with the specified
+* order or 1 if collation order does not occur at the end of any
+* expansion sequence.
+*/
+static jint getMaxExpansion(JNIEnv *env, jclass obj,
+ jint address, jint order) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ return ucol_getMaxExpansion(iterator, order);
+}
+
+/**
+* Get the normalization mode for this object.
+* The normalization mode influences how strings are compared.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collator
+* @return normalization mode; one of the values from NormalizerEnum
+*/
+static jint getNormalization(JNIEnv *env, jclass obj,
+ jint address) {
+
+ UErrorCode status = U_ZERO_ERROR;
+ const UCollator *collator = (const UCollator *)(int)address;
+ if(U_FAILURE(status)){
+ icu4jni_error(env, status);
+ }
+ return (jint)ucol_getAttribute(collator,UCOL_NORMALIZATION_MODE,&status);
+
+}
+
+/**
+* Set the normalization mode for this object.
+* The normalization mode influences how strings are compared.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collator
+* @param mode the normalization mode
+*/
+static void setNormalization(JNIEnv *env, jclass obj, jint address,
+ jint mode) {
+
+ UErrorCode status = U_ZERO_ERROR;
+ const UCollator *collator = (const UCollator *)(int)address;
+ if(U_FAILURE(status)){
+ icu4jni_error(env, status);
+ }
+ ucol_setAttribute(collator,UCOL_NORMALIZATION_MODE,mode,&status);
+}
+
+
+/**
+* Get the offset of the current source character.
+* This is an offset into the text of the character containing the current
+* collation elements.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param addresss of the C collation elements iterator to query.
+* @return offset of the current source character.
+*/
+static jint getOffset(JNIEnv *env, jclass obj, jint address) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ return ucol_getOffset(iterator);
+}
+
+/**
+* Get the collation rules from a UCollator.
+* The rules will follow the rule syntax.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address the address of the C collator
+* @return collation rules.
+*/
+static jstring getRules(JNIEnv *env, jclass obj,
+ jint address) {
+
+ const UCollator *collator = (const UCollator *)(int)address;
+ int32_t length=0;
+ const UChar *rules = ucol_getRules(collator, &length);
+ return (*env)->NewString(env, rules, length);
+}
+
+/**
+* Get a sort key for the argument string
+* Sort keys may be compared using java.util.Arrays.equals
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param source string for key to be generated
+* @return sort key
+*/
+static jbyteArray getSortKey(JNIEnv *env, jclass obj,
+ jint address, jstring source) {
+
+ const UCollator *collator = (const UCollator *)(int)address;
+ jbyteArray result;
+ if(collator && source){
+ // BEGIN android-added
+ if(!source) {
+ return NULL;
+ }
+ // END android-added
+ jsize srclength = (*env)->GetStringLength(env, source);
+ const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source, 0);
+ if(srcstr){
+// BEGIN android-changed
+ uint8_t bytearray[UCOL_MAX_BUFFER * 2];
+ uint8_t *largerbytearray = NULL;
+ uint8_t *usedbytearray = bytearray;
+
+ jint bytearraysize = ucol_getSortKey(collator, srcstr, srclength, bytearray,
+ sizeof(bytearray) - 1);
+
+ if (bytearraysize > sizeof(bytearray) - 1) {
+ // didn't fit, try again with a larger buffer.
+ largerbytearray = malloc(bytearraysize + 1);
+ usedbytearray = largerbytearray;
+ bytearraysize = ucol_getSortKey(collator, srcstr, srclength, largerbytearray,
+ bytearraysize);
+ }
+
+ (*env)->ReleaseStringCritical(env, source, srcstr);
+
+ if (bytearraysize == 0) {
+ free(largerbytearray);
+ return NULL;
+ }
+
+ /* no problem converting uint8_t to int8_t, gives back the correct value
+ * tried and tested
+ */
+ result = (*env)->NewByteArray(env, bytearraysize);
+ (*env)->SetByteArrayRegion(env, result, 0, bytearraysize, usedbytearray);
+ free(largerbytearray);
+// END android-changed
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ return result;
+}
+
+/**
+* Returns a hash of this collation object
+* Note this method is not complete, it only returns 0 at the moment.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator
+* @return hash of this collation object
+*/
+static jint hashCode(JNIEnv *env, jclass obj, jint address) {
+
+ UCollator *collator = (UCollator *)(int)address;
+ int32_t length=0;
+ const UChar *rules = ucol_getRules(collator, &length);
+ /* temporary commented out
+ * return uhash_hashUCharsN(rules, length);
+ */
+ return 0;
+}
+
+/**
+* Get the ordering priority of the next collation element in the text.
+* A single character may contain more than one collation element.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address if C collation elements containing the text.
+* @return next collation elements ordering, otherwise returns NULLORDER if an
+* error has occured or if the end of string has been reached
+*/
+static jint next(JNIEnv *env, jclass obj, jint address) {
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ jint result = ucol_next(iterator, &status);
+
+ icu4jni_error(env, status);
+ return result;
+}
+
+/**
+* Opening a new C UCollator with the default locale.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollator__(JNIEnv *env, jclass obj) {
+ jint result;
+ UErrorCode status = U_ZERO_ERROR;
+
+ result = (jint)ucol_open(NULL, &status);
+ if ( icu4jni_error(env, status) != FALSE)
+ return 0;
+
+ return result;
+}
+
+
+/**
+* Opening a new C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param locale name
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollator__Ljava_lang_String_2(JNIEnv *env,
+ jclass obj, jstring locale) {
+
+ /* this will be null terminated */
+ const char *localestr = (*env)->GetStringUTFChars(env, locale, 0);
+ jint result=0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ if(localestr){
+ result = (jint)ucol_open(localestr, &status);
+ (*env)->ReleaseStringUTFChars(env, locale, localestr);
+ icu4jni_error(env, status);
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ return result;
+}
+
+/**
+* Opening a new C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be
+* handled by the caller. Hence if the caller has a existing collator, it is his
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param rules set of collation rules
+* @param normalizationmode normalization mode
+* @param strength collation strength
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollatorFromRules(JNIEnv *env, jclass obj,
+ jstring rules, jint normalizationmode, jint strength) {
+
+ jsize ruleslength = (*env)->GetStringLength(env, rules);
+ const UChar *rulestr = (const UChar *)(*env)->GetStringCritical(env,rules, 0);
+ UErrorCode status = U_ZERO_ERROR;
+ jint result = 0;
+ if(rulestr){
+ result = (jint)ucol_openRules(rulestr, ruleslength,
+ (UColAttributeValue)normalizationmode,
+ (UCollationStrength)strength, NULL, &status);
+
+ (*env)->ReleaseStringCritical(env, rules, rulestr);
+ icu4jni_error(env, status);
+ }else{
+ icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ return result;
+}
+
+/**
+* Get the ordering priority of the previous collation element in the text.
+* A single character may contain more than one collation element.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator containing the text.
+* @return previous collation element ordering, otherwise returns NULLORDER if
+* an error has occured or if the start of string has been reached
+* @exception thrown when retrieval of previous collation element fails.
+*/
+static jint previous(JNIEnv *env, jclass obj, jint address) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ jint result = ucol_previous(iterator, &status);
+
+ icu4jni_error(env, status);
+ return result;
+}
+
+
+/**
+* Reset the collation elements to their initial state.
+* This will move the 'cursor' to the beginning of the text.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collation element iterator to reset.
+*/
+static void reset(JNIEnv *env, jclass obj, jint address) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ ucol_reset(iterator);
+}
+
+/**
+* Thread safe cloning operation
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator to be cloned
+* @return address of the new clone
+* @exception thrown when error occurs while cloning
+*/
+static jint safeClone(JNIEnv *env, jclass obj, jint address) {
+
+ const UCollator *collator = (const UCollator *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ jint result;
+ jint buffersize = U_COL_SAFECLONE_BUFFERSIZE;
+
+ result = (jint)ucol_safeClone(collator, NULL, &buffersize, &status);
+
+ if ( icu4jni_error(env, status) != FALSE) {
+ return 0;
+ }
+
+ return result;
+}
+
+/**
+* Universal attribute setter.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param type type of attribute to be set
+* @param value attribute value
+* @exception thrown when error occurs while setting attribute value
+*/
+static void setAttribute(JNIEnv *env, jclass obj, jint address,
+ jint type, jint value) {
+
+ UCollator *collator = (UCollator *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ ucol_setAttribute(collator, (UColAttribute)type, (UColAttributeValue)value,
+ &status);
+ icu4jni_error(env, status);
+}
+
+/**
+* Set the offset of the current source character.
+* This is an offset into the text of the character to be processed.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator to set.
+* @param offset The desired character offset.
+* @exception thrown when offset setting fails
+*/
+static void setOffset(JNIEnv *env, jclass obj, jint address,
+ jint offset) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+
+ ucol_setOffset(iterator, offset, &status);
+ icu4jni_error(env, status);
+}
+
+/**
+* Set the text containing the collation elements.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator to be set
+* @param source text containing the collation elements.
+* @exception thrown when error occurs while setting offset
+*/
+static void setText(JNIEnv *env, jclass obj, jint address,
+ jstring source) {
+
+ UCollationElements *iterator = (UCollationElements *)(int)address;
+ UErrorCode status = U_ZERO_ERROR;
+ int strlength = (*env)->GetStringLength(env, source);
+ const UChar *str = (const UChar *)(*env)->GetStringCritical(env, source, 0);
+
+ ucol_setText(iterator, str, strlength, &status);
+ (*env)->ReleaseStringCritical(env, source, str);
+
+ icu4jni_error(env, status);
+}
+
+// BEGIN android-added
+static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
+
+ const char * locale = ucol_getAvailable(index);
+
+ return (*env)->NewStringUTF(env, locale);
+
+}
+
+static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
+ return ucol_countAvailable();
+}
+// END android-added
+
+/*
+ * JNI registratio
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ // BEGIN android-added
+ { "getAvailableLocalesImpl", "(I)Ljava/lang/String;", (void*) getAvailableLocalesImpl },
+ { "getAvailableLocalesCountImpl", "()I", (void*) getAvailableLocalesCountImpl },
+ // END android-added
+ { "openCollator", "()I", (void*) openCollator__ },
+ { "openCollator", "(Ljava/lang/String;)I", (void*) openCollator__Ljava_lang_String_2 },
+ { "openCollatorFromRules", "(Ljava/lang/String;II)I", (void*) openCollatorFromRules },
+ { "closeCollator", "(I)V", (void*) closeCollator },
+ { "compare", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) compare },
+ { "getNormalization", "(I)I", (void*) getNormalization },
+ { "setNormalization", "(II)V", (void*) setNormalization },
+ { "getRules", "(I)Ljava/lang/String;", (void*) getRules },
+ { "getSortKey", "(ILjava/lang/String;)[B", (void*) getSortKey },
+ { "setAttribute", "(III)V", (void*) setAttribute },
+ { "getAttribute", "(II)I", (void*) getAttribute },
+ { "safeClone", "(I)I", (void*) safeClone },
+ { "getCollationElementIterator", "(ILjava/lang/String;)I", (void*) getCollationElementIterator },
+ { "hashCode", "(I)I", (void*) hashCode },
+ { "closeElements", "(I)V", (void*) closeElements },
+ { "reset", "(I)V", (void*) reset },
+ { "next", "(I)I", (void*) next },
+ { "previous", "(I)I", (void*) previous },
+ { "getMaxExpansion", "(II)I", (void*) getMaxExpansion },
+ { "setText", "(ILjava/lang/String;)V", (void*) setText },
+ { "getOffset", "(I)I", (void*) getOffset },
+ { "setOffset", "(II)V", (void*) setOffset }
+};
+
+int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv *_env) {
+ return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/text/NativeCollation",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/icu/src/main/native/CollationInterface.h b/icu/src/main/native/CollationInterface.h
new file mode 100644
index 0000000..bdb4b67
--- /dev/null
+++ b/icu/src/main/native/CollationInterface.h
@@ -0,0 +1,214 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class CollationInterface */
+
+#ifndef _Included_com_ibm_icu4jni_text_NativeCollation
+#define _Included_com_ibm_icu4jni_text_NativeCollation
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: closeCollator
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_closeCollator
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: closeElements
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_closeElements
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: compare
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_compare
+ (JNIEnv *, jclass, jlong, jstring, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getAttribute
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getAttribute
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getCollationElementIterator
+ * Signature: (JLjava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getCollationElementIterator
+ (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getMaxExpansion
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getMaxExpansion
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getNormalization
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getNormalization
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getOffset
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getOffset
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getRules
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getRules
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: getSortKey
+ * Signature: (JLjava/lang/String;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getSortKey
+ (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: hashCode
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_hashCode
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: next
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_next
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: openCollator
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollator__
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: openCollator
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollator__Ljava_lang_String_2
+ (JNIEnv *, jclass, jstring);
+
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: openCollatorFromRules
+ * Signature: (Ljava/lang/String;II)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollatorFromRules
+ (JNIEnv *, jclass, jstring, jint, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: previous
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_previous
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: primaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_primaryOrder
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: reset
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_reset
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: safeClone
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_safeClone
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: secondaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_secondaryOrder
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: setAttribute
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setAttribute
+ (JNIEnv *, jclass, jlong, jint, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: setOffset
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setOffset
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: setText
+ * Signature: (JLjava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setText
+ (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_text_NativeCollation
+ * Method: tertiaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_tertiaryOrder
+ (JNIEnv *, jclass, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/icu/src/main/native/ConverterInterface.c b/icu/src/main/native/ConverterInterface.c
new file mode 100644
index 0000000..d7f5c9b
--- /dev/null
+++ b/icu/src/main/native/ConverterInterface.c
@@ -0,0 +1,1378 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+/*
+ * @(#) icujniinterface.c 1.2 00/10/11
+ *
+ * (C) Copyright IBM Corp. 2000 - All Rights Reserved
+ * A JNI wrapper to ICU native converter Interface
+ * @author: Ram Viswanadha
+ */
+
+#include "ConverterInterface.h"
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/utypes.h" /* Basic ICU data types */
+#include "unicode/ucnv.h" /* C Converter API */
+#include "unicode/ustring.h" /* some more string functions*/
+#include "unicode/ucnv_cb.h" /* for callback functions */
+#include "unicode/uset.h" /* for contains function */
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+
+// BEGIN android-removed
+// #define UTF_16BE "UTF-16BE"
+// #define UTF_16 "UTF-16"
+// END android-removed
+
+/* Prototype of callback for substituting user settable sub chars */
+void JNI_TO_U_CALLBACK_SUBSTITUTE
+ (const void *,UConverterToUnicodeArgs *,const char* ,int32_t ,UConverterCallbackReason ,UErrorCode * );
+
+/**
+ * Opens the ICU converter
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle buffer to recieve ICU's converter address
+ * @param converterName name of the ICU converter
+ */
+static jlong openConverter (JNIEnv *env, jclass jClass, jstring converterName) {
+
+ UConverter* conv=NULL;
+ UErrorCode errorCode = U_ZERO_ERROR;
+
+ const char* cnvName= (const char*) (*env)->GetStringUTFChars(env, converterName,NULL);
+ if(cnvName) {
+ int count = (*env)->GetStringUTFLength(env,converterName);
+
+ conv = ucnv_open(cnvName,&errorCode);
+ }
+ (*env)->ReleaseStringUTFChars(env, converterName,cnvName);
+
+ if (icu4jni_error(env, errorCode) != FALSE) {
+ return 0;
+ }
+
+ return (jlong) conv;
+}
+
+/**
+ * Closes the ICU converter
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ */
+static void closeConverter (JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)(long)handle;
+ if(cnv) {
+ // BEGIN android-added
+ // Free up any contexts created in setCallback[Encode|Decode]()
+ UConverterToUCallback toAction;
+ UConverterFromUCallback fromAction;
+ void * context1 = NULL;
+ void * context2 = NULL;
+ ucnv_getToUCallBack(cnv, &toAction, &context1);
+ ucnv_getFromUCallBack(cnv, &fromAction, &context2);
+ // END android-added
+ ucnv_close(cnv);
+ // BEGIN android-added
+ if (context1 != NULL) {
+ free(context1);
+ }
+ if (context2 != NULL) {
+ free(context2);
+ }
+ // END android-added
+ }
+}
+
+/**
+ * Sets the substution mode for from Unicode conversion. Currently only
+ * two modes are supported: substitute or report
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param mode the mode to set
+ */
+static jint setSubstitutionModeCharToByte (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
+
+ UConverter* conv = (UConverter*)(long)handle;
+ UErrorCode errorCode =U_ZERO_ERROR;
+
+ if(conv) {
+
+ UConverterFromUCallback fromUOldAction ;
+ void* fromUOldContext;
+ void* fromUNewContext=NULL;
+ if(mode) {
+
+ ucnv_setFromUCallBack(conv,
+ UCNV_FROM_U_CALLBACK_SUBSTITUTE,
+ fromUNewContext,
+ &fromUOldAction,
+ (const void**)&fromUOldContext,
+ &errorCode);
+
+ }
+ else{
+
+ ucnv_setFromUCallBack(conv,
+ UCNV_FROM_U_CALLBACK_STOP,
+ fromUNewContext,
+ &fromUOldAction,
+ (const void**)&fromUOldContext,
+ &errorCode);
+
+ }
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+/**
+ * Sets the substution mode for to Unicode conversion. Currently only
+ * two modes are supported: substitute or report
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param mode the mode to set
+ */
+static jint setSubstitutionModeByteToChar (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
+
+ UConverter* conv = (UConverter*)handle;
+ UErrorCode errorCode =U_ZERO_ERROR;
+
+ if(conv) {
+
+ UConverterToUCallback toUOldAction ;
+ void* toUOldContext;
+ void* toUNewContext=NULL;
+ if(mode) {
+
+ ucnv_setToUCallBack(conv,
+ UCNV_TO_U_CALLBACK_SUBSTITUTE,
+ toUNewContext,
+ &toUOldAction,
+ (const void**)&toUOldContext,
+ &errorCode);
+
+ }
+ else{
+
+ ucnv_setToUCallBack(conv,
+ UCNV_TO_U_CALLBACK_STOP,
+ toUNewContext,
+ &toUOldAction,
+ (const void**)&toUOldContext,
+ &errorCode);
+
+ }
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+/**
+ * Converts a buffer of Unicode code units to target encoding
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param source buffer of Unicode chars to convert
+ * @param sourceEnd limit of the source buffer
+ * @param target buffer to recieve the converted bytes
+ * @param targetEnd the limit of the target buffer
+ * @param data buffer to recieve state of the current conversion
+ * @param flush boolean that specifies end of source input
+ */
+static jint convertCharToByte(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+ if(myData) {
+ jint* sourceOffset = &myData[0];
+ jint* targetOffset = &myData[1];
+ const jchar* uSource =(jchar*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+ if(uSource) {
+ jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+ if(uTarget) {
+ const jchar* mySource = uSource+ *sourceOffset;
+ const UChar* mySourceLimit= uSource+sourceEnd;
+ char* cTarget=uTarget+ *targetOffset;
+ const char* cTargetLimit=uTarget+targetEnd;
+
+ ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
+ mySourceLimit,NULL,(UBool) flush, &errorCode);
+
+ *sourceOffset = (jint) (mySource - uSource)-*sourceOffset;
+ *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
+ if(U_FAILURE(errorCode)) {
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+
+static jint encode(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+ UErrorCode ec = convertCharToByte(env,jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
+ UConverter* cnv = (UConverter*)handle;
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+
+ if(cnv && myData) {
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ myData[3] = ucnv_fromUCountPending(cnv, &errorCode);
+
+ if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND) {
+ int8_t count =32;
+ UChar invalidUChars[32];
+ ucnv_getInvalidUChars(cnv,invalidUChars,&count,&errorCode);
+
+ if(U_SUCCESS(errorCode)) {
+ myData[2] = count;
+ }
+ }
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return ec;
+}
+
+/**
+ * Converts a buffer of encoded bytes to Unicode code units
+ * @param env environment handle for JNI
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param source buffer of Unicode chars to convert
+ * @param sourceEnd limit of the source buffer
+ * @param target buffer to recieve the converted bytes
+ * @param targetEnd the limit of the target buffer
+ * @param data buffer to recieve state of the current conversion
+ * @param flush boolean that specifies end of source input
+ */
+static jint convertByteToChar(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+ if(myData) {
+ jint* sourceOffset = &myData[0];
+ jint* targetOffset = &myData[1];
+
+ const jbyte* uSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+ if(uSource) {
+ jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+ if(uTarget) {
+ const jbyte* mySource = uSource+ *sourceOffset;
+ const char* mySourceLimit= uSource+sourceEnd;
+ UChar* cTarget=uTarget+ *targetOffset;
+ const UChar* cTargetLimit=uTarget+targetEnd;
+
+ ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
+ mySourceLimit,NULL,(UBool) flush, &errorCode);
+
+ *sourceOffset = mySource - uSource - *sourceOffset ;
+ *targetOffset = cTarget - uTarget - *targetOffset;
+ if(U_FAILURE(errorCode)) {
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+
+static jint decode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+ jint ec = convertByteToChar(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
+
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+ UConverter* cnv = (UConverter*)handle;
+
+ if(myData && cnv) {
+ UErrorCode errorCode = U_ZERO_ERROR;
+ myData[3] = ucnv_toUCountPending(cnv, &errorCode);
+
+ if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND ) {
+ char invalidChars[32] = {'\0'};
+ int8_t len = 32;
+ ucnv_getInvalidChars(cnv,invalidChars,&len,&errorCode);
+
+ if(U_SUCCESS(errorCode)) {
+ myData[2] = len;
+ }
+ }
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return ec;
+}
+static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ ucnv_resetToUnicode(cnv);
+ }
+}
+
+static void resetCharToByte(JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ ucnv_resetFromUnicode(cnv);
+ }
+
+}
+
+static jint countInvalidBytes (JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
+
+ UConverter* cnv = (UConverter*)handle;
+ UErrorCode errorCode = U_ZERO_ERROR;
+ if(cnv) {
+ char invalidChars[32];
+
+ jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
+ if(len) {
+ ucnv_getInvalidChars(cnv,invalidChars,(int8_t*)len,&errorCode);
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+
+}
+
+
+static jint countInvalidChars(JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ UChar invalidUChars[32];
+ if(cnv) {
+ jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
+ if(len) {
+ ucnv_getInvalidUChars(cnv,invalidUChars,(int8_t*)len,&errorCode);
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+
+}
+
+static jint getMaxBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ return (jint)ucnv_getMaxCharSize(cnv);
+ }
+ return -1;
+}
+
+static jint getMinBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ return (jint)ucnv_getMinCharSize(cnv);
+ }
+ return -1;
+}
+static jfloat getAveBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ jfloat max = (jfloat)ucnv_getMaxCharSize(cnv);
+ jfloat min = (jfloat)ucnv_getMinCharSize(cnv);
+ return (jfloat) ( (max+min)/2 );
+ }
+ return -1;
+}
+static jint flushByteToChar(JNIEnv *env, jclass jClass,jlong handle, jcharArray target, jint targetEnd, jintArray data) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ jbyte source ='\0';
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+ if(myData) {
+ jint* targetOffset = &myData[1];
+ jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+ if(uTarget) {
+ const jbyte* mySource =&source;
+ const char* mySourceLimit=&source;
+ UChar* cTarget=uTarget+ *targetOffset;
+ const UChar* cTargetLimit=uTarget+targetEnd;
+
+ ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
+ mySourceLimit,NULL,TRUE, &errorCode);
+
+
+ *targetOffset = (jint) ((jchar*)cTarget - uTarget)- *targetOffset;
+ if(U_FAILURE(errorCode)) {
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+
+static jint flushCharToByte (JNIEnv *env, jclass jClass, jlong handle, jbyteArray target, jint targetEnd, jintArray data) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ jchar source = '\0';
+ if(cnv) {
+ jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+ if(myData) {
+ jint* targetOffset = &myData[1];
+ jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+ if(uTarget) {
+ const jchar* mySource = &source;
+ const UChar* mySourceLimit= &source;
+ char* cTarget=uTarget+ *targetOffset;
+ const char* cTargetLimit=uTarget+targetEnd;
+
+ ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
+ mySourceLimit,NULL,TRUE, &errorCode);
+
+
+ *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
+ if(U_FAILURE(errorCode)) {
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+
+void toChars(const UChar* us, char* cs, int32_t length) {
+ UChar u;
+ while(length>0) {
+ u=*us++;
+ *cs++=(char)u;
+ --length;
+ }
+}
+static jint setSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle, jbyteArray subChars, jint length) {
+
+ UConverter* cnv = (UConverter*) handle;
+ UErrorCode errorCode = U_ZERO_ERROR;
+ if(cnv) {
+ jbyte* u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
+ if(u_subChars) {
+ char* mySubChars= (char*)malloc(sizeof(char)*length);
+ toChars((UChar*)u_subChars,&mySubChars[0],length);
+ ucnv_setSubstChars(cnv,mySubChars, (char)length,&errorCode);
+ if(U_FAILURE(errorCode)) {
+ (*env)->ReleasePrimitiveArrayCritical(env,subChars,mySubChars,0);
+ return errorCode;
+ }
+ free(mySubChars);
+ }
+ else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0);
+ return errorCode;
+ }
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return errorCode;
+}
+
+
+#define VALUE_STRING_LENGTH 32
+
+typedef struct{
+ int length;
+ UChar subChars[256];
+ UBool stopOnIllegal;
+}SubCharStruct;
+
+
+static UErrorCode
+setToUCallbackSubs(UConverter* cnv,UChar* subChars, int32_t length,UBool stopOnIllegal ) {
+ SubCharStruct* substitutionCharS = (SubCharStruct*) malloc(sizeof(SubCharStruct));
+ UErrorCode errorCode = U_ZERO_ERROR;
+ if(substitutionCharS) {
+ UConverterToUCallback toUOldAction;
+ void* toUOldContext=NULL;
+ void* toUNewContext=NULL ;
+ if(subChars) {
+ u_strncpy(substitutionCharS->subChars,subChars,length);
+ }else{
+ substitutionCharS->subChars[length++] =0xFFFD;
+ }
+ substitutionCharS->subChars[length]=0;
+ substitutionCharS->length = length;
+ substitutionCharS->stopOnIllegal = stopOnIllegal;
+ toUNewContext = substitutionCharS;
+
+ ucnv_setToUCallBack(cnv,
+ JNI_TO_U_CALLBACK_SUBSTITUTE,
+ toUNewContext,
+ &toUOldAction,
+ (const void**)&toUOldContext,
+ &errorCode);
+
+ if(toUOldContext) {
+ SubCharStruct* temp = (SubCharStruct*) toUOldContext;
+ free(temp);
+ }
+
+ return errorCode;
+ }
+ return U_MEMORY_ALLOCATION_ERROR;
+}
+static jint setSubstitutionChars(JNIEnv *env, jclass jClass, jlong handle, jcharArray subChars, jint length) {
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*) handle;
+ jchar* u_subChars=NULL;
+ if(cnv) {
+ if(subChars) {
+ int len = (*env)->GetArrayLength(env,subChars);
+ u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
+ if(u_subChars) {
+ errorCode = setToUCallbackSubs(cnv,u_subChars,len,FALSE);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0);
+ return errorCode;
+ }
+ }
+ return U_ILLEGAL_ARGUMENT_ERROR;
+}
+
+
+void JNI_TO_U_CALLBACK_SUBSTITUTE( const void *context, UConverterToUnicodeArgs *toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode * err) {
+
+ if(context) {
+ SubCharStruct* temp = (SubCharStruct*)context;
+ if( temp) {
+ if(temp->stopOnIllegal==FALSE) {
+ if (reason > UCNV_IRREGULAR) {
+ return;
+ }
+ /* reset the error */
+ *err = U_ZERO_ERROR;
+ ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
+ }else{
+ if(reason != UCNV_UNASSIGNED) {
+ /* the caller must have set
+ * the error code accordingly
+ */
+ return;
+ }else{
+ *err = U_ZERO_ERROR;
+ ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
+ return;
+ }
+ }
+ }
+ }
+ return;
+}
+
+static jboolean canEncode(JNIEnv *env, jclass jClass, jlong handle, jint codeUnit) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ UChar source[3];
+ UChar *mySource=source;
+ const UChar* sourceLimit = (codeUnit<0x010000) ? &source[1] : &source[2];
+ char target[5];
+ char *myTarget = target;
+ const char* targetLimit = &target[4];
+ int i=0;
+ UTF_APPEND_CHAR(&source[0],i,2,codeUnit);
+
+ ucnv_fromUnicode(cnv,&myTarget,targetLimit,
+ (const UChar**)&mySource,
+ sourceLimit,NULL, TRUE,&errorCode);
+
+ if(U_SUCCESS(errorCode)) {
+ return (jboolean)TRUE;
+ }
+ }
+ return (jboolean)FALSE;
+}
+
+
+static jboolean canDecode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source) {
+
+ UErrorCode errorCode =U_ZERO_ERROR;
+ UConverter* cnv = (UConverter*)handle;
+ if(cnv) {
+ jint len = (*env)->GetArrayLength(env,source);
+ jbyte* cSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+ if(cSource) {
+ const jbyte* cSourceLimit = cSource+len;
+
+ /* Assume that we need at most twice the length of source */
+ UChar* target = (UChar*) malloc(sizeof(UChar)* (len<<1));
+ UChar* targetLimit = target + (len<<1);
+ if(target) {
+ ucnv_toUnicode(cnv,&target,targetLimit,
+ (const char**)&cSource,
+ cSourceLimit,NULL, TRUE,&errorCode);
+
+ if(U_SUCCESS(errorCode)) {
+ free(target);
+ (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);
+ return (jboolean)TRUE;
+ }
+ }
+ free(target);
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);
+ }
+ return (jboolean)FALSE;
+}
+
+static jint countAvailable(JNIEnv *env, jclass jClass) {
+ return ucnv_countAvailable();
+}
+
+int32_t copyString(char* dest, int32_t destCapacity, int32_t startIndex,
+ const char* src, UErrorCode* status) {
+ int32_t srcLen = 0, i=0;
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ if(dest == NULL || src == NULL || destCapacity < startIndex) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ srcLen = strlen(src);
+ if(srcLen >= destCapacity) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ return 0;
+ }
+ for(i=0; i < srcLen; i++) {
+ dest[startIndex++] = src[i];
+ }
+ /* null terminate the buffer */
+ dest[startIndex] = 0; /* no bounds check already made sure that we have enough room */
+ return startIndex;
+}
+
+int32_t getJavaCanonicalName1(const char* icuCanonicalName,
+ char* canonicalName, int32_t capacity,
+ UErrorCode* status) {
+ /*
+ If a charset listed in the IANA Charset Registry is supported by an implementation
+ of the Java platform then its canonical name must be the name listed in the registry.
+ Many charsets are given more than one name in the registry, in which case the registry
+ identifies one of the names as MIME-preferred. If a charset has more than one registry
+ name then its canonical name must be the MIME-preferred name and the other names in
+ the registry must be valid aliases. If a supported charset is not listed in the IANA
+ registry then its canonical name must begin with one of the strings "X-" or "x-".
+ */
+ int32_t retLen = 0;
+ const char* cName = NULL;
+ /* find out the alias with MIME tag */
+ if((cName =ucnv_getStandardName(icuCanonicalName, "MIME", status)) != NULL) {
+ retLen = copyString(canonicalName, capacity, 0, cName, status);
+ /* find out the alias with IANA tag */
+ }else if((cName =ucnv_getStandardName(icuCanonicalName, "IANA", status)) != NULL) {
+ retLen = copyString(canonicalName, capacity, 0, cName, status);
+ }else {
+ /*
+ check to see if an alias already exists with x- prefix, if yes then
+ make that the canonical name
+ */
+ int32_t aliasNum = ucnv_countAliases(icuCanonicalName,status);
+ int32_t i=0;
+ const char* name;
+ for(i=0;i<aliasNum;i++) {
+ name = ucnv_getAlias(icuCanonicalName,(uint16_t)i, status);
+ if(name != NULL && name[0]=='x' && name[1]=='-') {
+ retLen = copyString(canonicalName, capacity, 0, name, status);
+ break;
+ }
+ }
+ /* last resort just append x- to any of the alias and
+ make it the canonical name */
+ if(retLen == 0 && U_SUCCESS(*status)) {
+ name = ucnv_getStandardName(icuCanonicalName, "UTR22", status);
+ if(name == NULL && strchr(icuCanonicalName, ',')!= NULL) {
+ name = ucnv_getAlias(icuCanonicalName, 1, status);
+ if(*status == U_INDEX_OUTOFBOUNDS_ERROR) {
+ *status = U_ZERO_ERROR;
+ }
+ }
+ /* if there is no UTR22 canonical name .. then just return itself*/
+ if(name == NULL) {
+ name = icuCanonicalName;
+ }
+ if(capacity >= 2) {
+ strcpy(canonicalName,"x-");
+ }
+ retLen = copyString(canonicalName, capacity, 2, name, status);
+ }
+ }
+ return retLen;
+}
+
+static jobjectArray getAvailable(JNIEnv *env, jclass jClass) {
+
+ jobjectArray ret;
+ int32_t i = 0;
+ int32_t num = ucnv_countAvailable();
+ UErrorCode error = U_ZERO_ERROR;
+ const char* name =NULL;
+ char canonicalName[256]={0};
+ ret= (jobjectArray)(*env)->NewObjectArray( env,num,
+ (*env)->FindClass(env,"java/lang/String"),
+ (*env)->NewStringUTF(env,""));
+
+ for(i=0;i<num;i++) {
+ name = ucnv_getAvailableName(i);
+ getJavaCanonicalName1(name, canonicalName, 256, &error);
+#if DEBUG
+ if(U_FAILURE(error)) {
+ printf("An error occurred retrieving index %i. Error: %s. \n", i, u_errorName(error));
+ }
+
+ printf("canonical name for %s\n", canonicalName);
+#endif
+ // BEGIN android-changed
+ jstring canonName = (*env)->NewStringUTF(env,canonicalName);
+ (*env)->SetObjectArrayElement(env,ret,i,canonName);
+ (*env)->DeleteLocalRef(env, canonName);
+ // END android-changed
+ /*printf("canonical name : %s at %i\n", name,i); */
+ canonicalName[0]='\0';/* nul terminate */
+ }
+ return (ret);
+}
+
+static jint countAliases(JNIEnv *env, jclass jClass,jstring enc) {
+
+ UErrorCode error = U_ZERO_ERROR;
+ jint num =0;
+ const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+
+ if(encName) {
+ num = ucnv_countAliases(encName,&error);
+ }
+
+ (*env)->ReleaseStringUTFChars(env,enc,encName);
+
+ return num;
+}
+
+
+static jobjectArray getAliases(JNIEnv *env, jclass jClass, jstring enc) {
+
+ jobjectArray ret=NULL;
+ int32_t aliasNum = 0;
+ UErrorCode error = U_ZERO_ERROR;
+ const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+ int i=0;
+ int j=0;
+ const char* aliasArray[50];
+ // BEGIN android-removed
+ // int32_t utf16AliasNum = 0;
+ // END android-removed
+
+
+ if(encName) {
+ const char* myEncName = encName;
+ aliasNum = ucnv_countAliases(myEncName,&error);
+
+ // BEGIN android-removed
+ // /* special case for UTF-16. In java UTF-16 is always BE*/
+ // if(strcmp(myEncName, UTF_16BE)==0) {
+ // utf16AliasNum=ucnv_countAliases(UTF_16,&error);
+ // }
+ // END android-removed
+
+ if(aliasNum==0 && encName[0] == 0x78 /*x*/ && encName[1]== 0x2d /*-*/) {
+ myEncName = encName+2;
+ aliasNum = ucnv_countAliases(myEncName,&error);
+ }
+ if(U_SUCCESS(error)) {
+ for(i=0,j=0;i<aliasNum;i++) {
+ const char* name = ucnv_getAlias(myEncName,(uint16_t)i,&error);
+ if(strchr(name,'+')==0 && strchr(name,',')==0) {
+ aliasArray[j++]= name;
+ }
+ }
+
+ // BEGIN android-removed
+ // if(utf16AliasNum>0) {
+ // for(i=0;i<utf16AliasNum;i++) {
+ // const char* name = ucnv_getAlias(UTF_16,(uint16_t)i,&error);
+ // if(strchr(name,'+')==0 && strchr(name,',')==0) {
+ // aliasArray[j++]= name;
+ // }
+ // }
+ // }
+ // END android-removed
+
+ ret = (jobjectArray)(*env)->NewObjectArray(env,j,
+ (*env)->FindClass(env,"java/lang/String"),
+ (*env)->NewStringUTF(env,""));
+ for(;--j>=0;) {
+ // BEGIN android-changed
+ jstring alias = (*env)->NewStringUTF(env, aliasArray[j]);
+ (*env)->SetObjectArrayElement(env, ret, j, alias);
+ (*env)->DeleteLocalRef(env, alias);
+ // END android-changed
+ }
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env,enc,encName);
+
+ return (ret);
+}
+
+static jstring getCanonicalName(JNIEnv *env, jclass jClass,jstring enc) {
+
+ UErrorCode error = U_ZERO_ERROR;
+ const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+ const char* canonicalName = "";
+ // BEGIN android-changed
+ jstring ret = NULL;
+ if(encName) {
+ canonicalName = ucnv_getAlias(encName,0,&error);
+ if(canonicalName !=NULL && strstr(canonicalName,",")!=0) {
+ canonicalName = ucnv_getAlias(canonicalName,1,&error);
+ }
+ ret = ((*env)->NewStringUTF(env, canonicalName));
+ (*env)->ReleaseStringUTFChars(env,enc,encName);
+ }
+ // END android-changed
+ return ret;
+}
+
+static jstring getICUCanonicalName(JNIEnv *env, jclass jClass, jstring enc) {
+
+ UErrorCode error = U_ZERO_ERROR;
+ const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+ const char* canonicalName = NULL;
+ jstring ret = NULL;
+ if(encName) {
+ // BEGIN android-removed
+ // if(strcmp(encName,"UTF-16")==0) {
+ // ret = ((*env)->NewStringUTF(env,UTF_16BE));
+ // }else
+ // END android-removed
+ if((canonicalName = ucnv_getCanonicalName(encName, "MIME", &error))!=NULL) {
+ ret = ((*env)->NewStringUTF(env, canonicalName));
+ }else if((canonicalName = ucnv_getCanonicalName(encName, "IANA", &error))!=NULL) {
+ ret = ((*env)->NewStringUTF(env, canonicalName));
+ }else if((canonicalName = ucnv_getCanonicalName(encName, "", &error))!=NULL) {
+ ret = ((*env)->NewStringUTF(env, canonicalName));
+ }else if((canonicalName = ucnv_getAlias(encName, 0, &error)) != NULL) {
+ /* we have some aliases in the form x-blah .. match those first */
+ ret = ((*env)->NewStringUTF(env, canonicalName));
+ }else if( ret ==NULL && strstr(encName, "x-") == encName) {
+ /* check if the converter can be opened with the encName given */
+ UConverter* conv = NULL;
+ error = U_ZERO_ERROR;
+ conv = ucnv_open(encName+2, &error);
+ if(conv!=NULL) {
+ ret = ((*env)->NewStringUTF(env, encName+2));
+ }else{
+ /* unsupported encoding */
+ ret = ((*env)->NewStringUTF(env, ""));
+ }
+ ucnv_close(conv);
+ }else{
+ /* unsupported encoding */
+ ret = ((*env)->NewStringUTF(env, ""));
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env,enc,encName);
+ return ret;
+}
+
+static jstring getJavaCanonicalName2(JNIEnv *env, jclass jClass, jstring icuCanonName) {
+ /*
+ If a charset listed in the IANA Charset Registry is supported by an implementation
+ of the Java platform then its canonical name must be the name listed in the registry.
+ Many charsets are given more than one name in the registry, in which case the registry
+ identifies one of the names as MIME-preferred. If a charset has more than one registry
+ name then its canonical name must be the MIME-preferred name and the other names in
+ the registry must be valid aliases. If a supported charset is not listed in the IANA
+ registry then its canonical name must begin with one of the strings "X-" or "x-".
+ */
+ UErrorCode error = U_ZERO_ERROR;
+ const char* icuCanonicalName = (*env)->GetStringUTFChars(env,icuCanonName,NULL);
+ char cName[UCNV_MAX_CONVERTER_NAME_LENGTH] = {0};
+ jstring ret;
+ if(icuCanonicalName && icuCanonicalName[0] != 0) {
+ getJavaCanonicalName1(icuCanonicalName, cName, UCNV_MAX_CONVERTER_NAME_LENGTH, &error);
+ }
+ ret = ((*env)->NewStringUTF(env, cName));
+ (*env)->ReleaseStringUTFChars(env,icuCanonName,icuCanonicalName);
+ return ret;
+}
+
+#define SUBS_ARRAY_CAPACITY 256
+typedef struct{
+ int length;
+ char subChars[SUBS_ARRAY_CAPACITY];
+ UConverterFromUCallback onUnmappableInput;
+ UConverterFromUCallback onMalformedInput;
+}EncoderCallbackContext;
+
+void CHARSET_ENCODER_CALLBACK(const void *context,
+ UConverterFromUnicodeArgs *fromArgs,
+ const UChar* codeUnits,
+ int32_t length,
+ UChar32 codePoint,
+ UConverterCallbackReason reason,
+ UErrorCode * status) {
+ if(context) {
+ EncoderCallbackContext* ctx = (EncoderCallbackContext*)context;
+
+ if(ctx) {
+ UConverterFromUCallback realCB = NULL;
+ switch(reason) {
+ case UCNV_UNASSIGNED:
+ realCB = ctx->onUnmappableInput;
+ break;
+ case UCNV_ILLEGAL:/*malformed input*/
+ case UCNV_IRREGULAR:/*malformed input*/
+ realCB = ctx->onMalformedInput;
+ break;
+ /*
+ case UCNV_RESET:
+ ucnv_resetToUnicode(args->converter);
+ break;
+ case UCNV_CLOSE:
+ ucnv_close(args->converter);
+ break;
+ case UCNV_CLONE:
+ ucnv_clone(args->clone);
+ */
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if(realCB==NULL) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ realCB(context, fromArgs, codeUnits, length, codePoint, reason, status);
+ }
+ }
+}
+
+void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void *context,
+ UConverterFromUnicodeArgs *fromArgs,
+ const UChar* codeUnits,
+ int32_t length,
+ UChar32 codePoint,
+ UConverterCallbackReason reason,
+ UErrorCode * err) {
+ if(context) {
+ EncoderCallbackContext* temp = (EncoderCallbackContext*)context;
+ *err = U_ZERO_ERROR;
+ ucnv_cbFromUWriteBytes(fromArgs,temp->subChars ,temp->length , 0, err);
+ }
+ return;
+}
+
+UConverterFromUCallback getFromUCallback(int32_t mode) {
+ switch(mode) {
+ default: /* falls through */
+ case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
+ return UCNV_FROM_U_CALLBACK_STOP;
+ case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
+ return UCNV_FROM_U_CALLBACK_SKIP ;
+ case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
+ return JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER;
+ }
+}
+
+static jint setCallbackEncode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) {
+
+ UConverter* conv = (UConverter*)handle;
+ UErrorCode errorCode =U_ZERO_ERROR;
+
+ if(conv) {
+
+ UConverterFromUCallback fromUOldAction = NULL;
+ void* fromUOldContext = NULL;
+ EncoderCallbackContext* fromUNewContext=NULL;
+ UConverterFromUCallback fromUNewAction=NULL;
+ jbyte* sub = (jbyte*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
+ ucnv_getFromUCallBack(conv, &fromUOldAction, &fromUOldContext);
+
+ /* fromUOldContext can only be DecodeCallbackContext since
+ the converter created is private data for the decoder
+ and callbacks can only be set via this method!
+ */
+ if(fromUOldContext==NULL) {
+ fromUNewContext = (EncoderCallbackContext*) malloc(sizeof(EncoderCallbackContext));
+ fromUNewAction = CHARSET_ENCODER_CALLBACK;
+ }else{
+ fromUNewContext = fromUOldContext;
+ fromUNewAction = fromUOldAction;
+ fromUOldAction = NULL;
+ fromUOldContext = NULL;
+ }
+ fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput);
+ fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput);
+ // BEGIN android-changed
+ if(sub!=NULL) {
+ fromUNewContext->length = length;
+ strncpy(fromUNewContext->subChars, sub, length);
+ (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ // END android-changed
+
+ ucnv_setFromUCallBack(conv,
+ fromUNewAction,
+ fromUNewContext,
+ &fromUOldAction,
+ (const void**)&fromUOldContext,
+ &errorCode);
+
+
+ return errorCode;
+ }
+ return U_ILLEGAL_ARGUMENT_ERROR;
+}
+
+typedef struct{
+ int length;
+ UChar subUChars[256];
+ UConverterToUCallback onUnmappableInput;
+ UConverterToUCallback onMalformedInput;
+}DecoderCallbackContext;
+
+void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void *context,
+ UConverterToUnicodeArgs *toArgs,
+ const char* codeUnits,
+ int32_t length,
+ UConverterCallbackReason reason,
+ UErrorCode * err) {
+ if(context) {
+ DecoderCallbackContext* temp = (DecoderCallbackContext*)context;
+ *err = U_ZERO_ERROR;
+ ucnv_cbToUWriteUChars(toArgs,temp->subUChars ,temp->length , 0, err);
+ }
+ return;
+}
+
+UConverterToUCallback getToUCallback(int32_t mode) {
+ switch(mode) {
+ default: /* falls through */
+ case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
+ return UCNV_TO_U_CALLBACK_STOP;
+ case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
+ return UCNV_TO_U_CALLBACK_SKIP ;
+ case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
+ return JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER;
+ }
+}
+
+void CHARSET_DECODER_CALLBACK(const void *context,
+ UConverterToUnicodeArgs *args,
+ const char* codeUnits,
+ int32_t length,
+ UConverterCallbackReason reason,
+ UErrorCode *status ) {
+
+ if(context) {
+ DecoderCallbackContext* ctx = (DecoderCallbackContext*)context;
+
+ if(ctx) {
+ UConverterToUCallback realCB = NULL;
+ switch(reason) {
+ case UCNV_UNASSIGNED:
+ realCB = ctx->onUnmappableInput;
+ break;
+ case UCNV_ILLEGAL:/*malformed input*/
+ case UCNV_IRREGULAR:/*malformed input*/
+ realCB = ctx->onMalformedInput;
+ break;
+ /*
+ case UCNV_RESET:
+ ucnv_resetToUnicode(args->converter);
+ break;
+ case UCNV_CLOSE:
+ ucnv_close(args->converter);
+ break;
+ case UCNV_CLONE:
+ ucnv_clone(args->clone);
+ */
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if(realCB==NULL) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ realCB(context, args, codeUnits, length, reason, status);
+ }
+ }
+}
+
+static jint setCallbackDecode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) {
+
+ UConverter* conv = (UConverter*)handle;
+ UErrorCode errorCode =U_ZERO_ERROR;
+ if(conv) {
+
+ UConverterToUCallback toUOldAction ;
+ void* toUOldContext;
+ DecoderCallbackContext* toUNewContext = NULL;
+ UConverterToUCallback toUNewAction = NULL;
+ jchar* sub = (jchar*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
+
+ ucnv_getToUCallBack(conv, &toUOldAction, &toUOldContext);
+
+ /* toUOldContext can only be DecodeCallbackContext since
+ the converter created is private data for the decoder
+ and callbacks can only be set via this method!
+ */
+ if(toUOldContext==NULL) {
+ toUNewContext = (DecoderCallbackContext*) malloc(sizeof(DecoderCallbackContext));
+ toUNewAction = CHARSET_DECODER_CALLBACK;
+ }else{
+ toUNewContext = toUOldContext;
+ toUNewAction = toUOldAction;
+ toUOldAction = NULL;
+ toUOldContext = NULL;
+ }
+ toUNewContext->onMalformedInput = getToUCallback(onMalformedInput);
+ toUNewContext->onUnmappableInput = getToUCallback(onUnmappableInput);
+ // BEGIN android-changed
+ if(sub!=NULL) {
+ toUNewContext->length = length;
+ u_strncpy(toUNewContext->subUChars, sub, length);
+ (*env)->ReleasePrimitiveArrayCritical(env,subChars, sub, 0);
+ }else{
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ // END android-changed
+ ucnv_setToUCallBack(conv,
+ toUNewAction,
+ toUNewContext,
+ &toUOldAction,
+ (const void**)&toUOldContext,
+ &errorCode);
+
+ return errorCode;
+ }
+ return U_ILLEGAL_ARGUMENT_ERROR;
+}
+
+static jlong safeClone(JNIEnv *env, jclass jClass, jlong src) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ jint buffersize = U_CNV_SAFECLONE_BUFFERSIZE;
+
+ UConverter* conv=NULL;
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UConverter* source = (UConverter*) src;
+
+ if(source) {
+ conv = ucnv_safeClone(source, NULL, &buffersize, &errorCode);
+ }
+
+ if (icu4jni_error(env, errorCode) != FALSE) {
+ return NULL;
+ }
+
+ return conv;
+}
+
+static jint getMaxCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
+ /*
+ * currently we know that max number of chars per byte is 2
+ */
+ return 2;
+}
+
+static jfloat getAveCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
+ jfloat ret = 0;
+ ret = (jfloat)( 1/(jfloat)getMaxBytesPerChar(env, jClass, handle));
+ return ret;
+}
+
+void toUChars(const char* cs, UChar* us, int32_t length) {
+ char c;
+ while(length>0) {
+ c=*cs++;
+ *us++=(char)c;
+ --length;
+ }
+}
+
+static jbyteArray getSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle) {
+
+ const UConverter * cnv = (const UConverter *) handle;
+ UErrorCode status = U_ZERO_ERROR;
+ char subBytes[10];
+ int8_t len =(char)10;
+ jbyteArray arr;
+ if(cnv) {
+ ucnv_getSubstChars(cnv,subBytes,&len,&status);
+ if(U_SUCCESS(status)) {
+ arr = ((*env)->NewByteArray(env, len));
+ if(arr) {
+ (*env)->SetByteArrayRegion(env,arr,0,len,(jbyte*)subBytes);
+ }
+ return arr;
+ }
+ }
+ return ((*env)->NewByteArray(env, 0));
+}
+
+static jboolean contains( JNIEnv *env, jclass jClass, jlong handle1, jlong handle2) {
+ UErrorCode status = U_ZERO_ERROR;
+ const UConverter * cnv1 = (const UConverter *) handle1;
+ const UConverter * cnv2 = (const UConverter *) handle2;
+ USet* set1;
+ USet* set2;
+ UBool bRet = 0;
+
+ if(cnv1 != NULL && cnv2 != NULL) {
+ /* open charset 1 */
+ set1 = uset_open(1, 2);
+ ucnv_getUnicodeSet(cnv1, set1, UCNV_ROUNDTRIP_SET, &status);
+
+ if(U_SUCCESS(status)) {
+ /* open charset 2 */
+ status = U_ZERO_ERROR;
+ set2 = uset_open(1, 2);
+ ucnv_getUnicodeSet(cnv2, set2, UCNV_ROUNDTRIP_SET, &status);
+
+ /* contains? */
+ if(U_SUCCESS(status)) {
+ bRet = uset_containsAll(set1, set2);
+ uset_close(set2);
+ }
+ uset_close(set1);
+ }
+ }
+ return bRet;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "convertByteToChar", "(J[BI[CI[IZ)I", (void*) convertByteToChar },
+ { "decode", "(J[BI[CI[IZ)I", (void*) decode },
+ { "convertCharToByte", "(J[CI[BI[IZ)I", (void*) convertCharToByte },
+ { "encode", "(J[CI[BI[IZ)I", (void*) encode },
+ { "flushCharToByte", "(J[BI[I)I", (void*) flushCharToByte },
+ { "flushByteToChar", "(J[CI[I)I", (void*) flushByteToChar },
+ { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter },
+ { "resetByteToChar", "(J)V", (void*) resetByteToChar },
+ { "resetCharToByte", "(J)V", (void*) resetCharToByte },
+ { "closeConverter", "(J)V", (void*) closeConverter },
+ { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars },
+ { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes },
+ { "setSubstitutionModeCharToByte", "(JZ)I", (void*) setSubstitutionModeCharToByte },
+ { "setSubstitutionModeByteToChar", "(JZ)I", (void*) setSubstitutionModeByteToChar },
+ { "countInvalidBytes", "(J[I)I", (void*) countInvalidBytes },
+ { "countInvalidChars", "(J[I)I", (void*) countInvalidChars },
+ { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar },
+ { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar },
+ { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar },
+ { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte },
+ { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte },
+ { "contains", "(JJ)Z", (void*) contains },
+ { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes },
+ { "canEncode", "(JI)Z", (void*) canEncode },
+ { "canDecode", "(J[B)Z", (void*) canDecode },
+ { "countAvailable", "()I", (void*) countAvailable },
+ { "getAvailable", "()[Ljava/lang/String;", (void*) getAvailable },
+ { "countAliases", "(Ljava/lang/String;)I", (void*) countAliases },
+ { "getAliases", "(Ljava/lang/String;)[Ljava/lang/String;", (void*) getAliases },
+ { "getCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCanonicalName },
+ { "getICUCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getICUCanonicalName },
+ { "getJavaCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getJavaCanonicalName2 },
+ { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode },
+ { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode },
+ { "safeClone", "(J)J", (void*) safeClone }
+};
+
+int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv *_env) {
+ return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/charset/NativeConverter",
+ gMethods, NELEM(gMethods));
+}
+
+
diff --git a/icu/src/main/native/ConverterInterface.h b/icu/src/main/native/ConverterInterface.h
new file mode 100644
index 0000000..e9dbf6b
--- /dev/null
+++ b/icu/src/main/native/ConverterInterface.h
@@ -0,0 +1,299 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_ibm_icu4jni_converters_NativeConverter */
+
+#ifndef _Included_com_ibm_icu4jni_converters_NativeConverter
+#define _Included_com_ibm_icu4jni_converters_NativeConverter
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK 0L
+#undef com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK 1L
+#undef com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK 2L
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: convertByteToChar
+ * Signature: (J[BI[CI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_convertByteToChar
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jcharArray, jint, jintArray, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: decode
+ * Signature: (J[BI[CI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_decode
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jcharArray, jint, jintArray, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: convertCharToByte
+ * Signature: (J[CI[BI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_convertCharToByte
+ (JNIEnv *, jclass, jlong, jcharArray, jint, jbyteArray, jint, jintArray, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: encode
+ * Signature: (J[CI[BI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_encode
+ (JNIEnv *, jclass, jlong, jcharArray, jint, jbyteArray, jint, jintArray, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: flushCharToByte
+ * Signature: (J[BI[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_flushCharToByte
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jintArray);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: flushByteToChar
+ * Signature: (J[CI[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_flushByteToChar
+ (JNIEnv *, jclass, jlong, jcharArray, jint, jintArray);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: openConverter
+ * Signature: ([JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_openConverter
+ (JNIEnv *, jclass, jlongArray, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: resetByteToChar
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_resetByteToChar
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: resetCharToByte
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_resetCharToByte
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: closeConverter
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_closeConverter
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setSubstitutionChars
+ * Signature: (J[CI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionChars
+ (JNIEnv *, jclass, jlong, jcharArray, jint);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setSubstitutionBytes
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionBytes
+ (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setSubstitutionModeCharToByte
+ * Signature: (JZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionModeCharToByte
+ (JNIEnv *, jclass, jlong, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setSubstitutionModeByteToChar
+ * Signature: (JZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionModeByteToChar
+ (JNIEnv *, jclass, jlong, jboolean);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: countInvalidBytes
+ * Signature: (J[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countInvalidBytes
+ (JNIEnv *, jclass, jlong, jintArray);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: countInvalidChars
+ * Signature: (J[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countInvalidChars
+ (JNIEnv *, jclass, jlong, jintArray);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getMaxBytesPerChar
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMaxBytesPerChar
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getMinBytesPerChar
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMinBytesPerChar
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getAveBytesPerChar
+ * Signature: (J)F
+ */
+JNIEXPORT jfloat JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAveBytesPerChar
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getMaxCharsPerByte
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMaxCharsPerByte
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getAveCharsPerByte
+ * Signature: (J)F
+ */
+JNIEXPORT jfloat JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAveCharsPerByte
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: contains
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_contains
+ (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getSubstitutionBytes
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getSubstitutionBytes
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: canEncode
+ * Signature: (JI)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_canEncode
+ (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: canDecode
+ * Signature: (J[B)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_canDecode
+ (JNIEnv *, jclass, jlong, jbyteArray);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: countAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countAvailable
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getAvailable
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAvailable
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: countAliases
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countAliases
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getAliases
+ * Signature: (Ljava/lang/String;)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAliases
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getCanonicalName
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getICUCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getICUCanonicalName
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: getJavaCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getJavaCanonicalName
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setCallbackDecode
+ * Signature: (JII[CI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setCallbackDecode
+ (JNIEnv *, jclass, jlong, jint, jint, jcharArray, jint);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: setCallbackEncode
+ * Signature: (JII[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setCallbackEncode
+ (JNIEnv *, jclass, jlong, jint, jint, jbyteArray, jint);
+
+/*
+ * Class: com_ibm_icu4jni_converters_NativeConverter
+ * Method: safeClone
+ * Signature: (J[J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_safeClone
+ (JNIEnv *, jclass, jlong, jlongArray);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/icu/src/main/native/DecimalFormatInterface.cpp b/icu/src/main/native/DecimalFormatInterface.cpp
new file mode 100644
index 0000000..6221826
--- /dev/null
+++ b/icu/src/main/native/DecimalFormatInterface.cpp
@@ -0,0 +1,851 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Internal native functions. All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods. This means that the GC will wait for these functions
+ * to finish. DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/unum.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "digitlst.h"
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+#include "cutils/log.h"
+
+#define LOG_TAG "DecimalFormatInterface"
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+ const char *emsg = u_errorName(errorcode);
+ jclass exception;
+
+ if (U_FAILURE(errorcode)) {// errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+ switch (errorcode) {
+ case U_ILLEGAL_ARGUMENT_ERROR :
+ exception = env->FindClass("java/lang/IllegalArgumentException");
+ break;
+ case U_INDEX_OUTOFBOUNDS_ERROR :
+ case U_BUFFER_OVERFLOW_ERROR :
+ exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+ break;
+ case U_UNSUPPORTED_ERROR :
+ exception = env->FindClass("java/lang/UnsupportedOperationException");
+ break;
+ default :
+ exception = env->FindClass("java/lang/RuntimeException");
+ }
+
+ return (env->ThrowNew(exception, emsg) != 0);
+ }
+ return 0;
+}
+
+static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
+ jstring pattern) {
+
+ // the errorcode returned by unum_open
+ UErrorCode status = U_ZERO_ERROR;
+
+ // prepare the pattern string for the call to unum_open
+ const UChar *pattChars = env->GetStringChars(pattern, NULL);
+ int pattLen = env->GetStringLength(pattern);
+
+ // prepare the locale string for the call to unum_open
+ const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+ // open a default type number format
+ UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen,
+ localeChars, NULL, &status);
+
+ // release the allocated strings
+ env->ReleaseStringChars(pattern, pattChars);
+ env->ReleaseStringUTFChars(locale, localeChars);
+
+ // check for an error
+ if ( icuError(env, status) != FALSE) {
+ return 0;
+ }
+
+ // return the handle to the number format
+ return (long) fmt;
+}
+
+static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ // close this number format
+ unum_close(fmt);
+}
+
+static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol,
+ jstring text) {
+
+ // the errorcode returned by unum_setSymbol
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ // prepare the symbol string for the call to unum_setSymbol
+ const UChar *textChars = env->GetStringChars(text, NULL);
+ int textLen = env->GetStringLength(text);
+
+ // set the symbol
+ unum_setSymbol(fmt, (UNumberFormatSymbol) symbol, textChars, textLen,
+ &status);
+
+ // release previously allocated space
+ env->ReleaseStringChars(text, textChars);
+
+ // check if an error occured
+ icuError(env, status);
+}
+
+static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
+
+ uint32_t resultlength, reslenneeded;
+
+ // the errorcode returned by unum_getSymbol
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ UChar* result = NULL;
+ resultlength=0;
+
+ // find out how long the result will be
+ reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result,
+ resultlength, &status);
+
+ result = NULL;
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+ resultlength=reslenneeded+1;
+ result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result,
+ resultlength, &status);
+ }
+ if (icuError(env, status) != FALSE) {
+ return NULL;
+ }
+
+ jstring res = env->NewString(result, reslenneeded);
+
+ free(result);
+
+ return res;
+}
+
+static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol,
+ jint value) {
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ unum_setAttribute(fmt, (UNumberFormatAttribute) symbol, value);
+}
+
+static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ int res = unum_getAttribute(fmt, (UNumberFormatAttribute) symbol);
+
+ return res;
+}
+
+static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol,
+ jstring text) {
+
+ // the errorcode returned by unum_setTextAttribute
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ const UChar *textChars = env->GetStringChars(text, NULL);
+ int textLen = env->GetStringLength(text);
+
+ unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars,
+ textLen, &status);
+
+ env->ReleaseStringChars(text, textChars);
+
+ icuError(env, status);
+}
+
+static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr,
+ jint symbol) {
+
+ uint32_t resultlength, reslenneeded;
+
+ // the errorcode returned by unum_getTextAttribute
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ UChar* result = NULL;
+ resultlength=0;
+
+ // find out how long the result will be
+ reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol,
+ result, resultlength, &status);
+
+ result = NULL;
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+ resultlength=reslenneeded+1;
+ result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ reslenneeded=unum_getTextAttribute(fmt,
+ (UNumberFormatTextAttribute) symbol, result, resultlength,
+ &status);
+ }
+ if (icuError(env, status) != FALSE) {
+ return NULL;
+ }
+
+ jstring res = env->NewString(result, reslenneeded);
+
+ free(result);
+
+ return res;
+}
+
+static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr,
+ jboolean localized, jstring pattern) {
+
+ // the errorcode returned by unum_applyPattern
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ const UChar *pattChars = env->GetStringChars(pattern, NULL);
+ int pattLen = env->GetStringLength(pattern);
+
+ unum_applyPattern(fmt, localized, pattChars, pattLen, NULL, &status);
+
+ env->ReleaseStringChars(pattern, pattChars);
+
+ icuError(env, status);
+}
+
+static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr,
+ jboolean localized) {
+
+ uint32_t resultlength, reslenneeded;
+
+ // the errorcode returned by unum_toPattern
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the pointer to the number format
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ UChar* result = NULL;
+ resultlength=0;
+
+ // find out how long the result will be
+ reslenneeded=unum_toPattern(fmt, localized, result, resultlength, &status);
+
+ result = NULL;
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+ resultlength=reslenneeded+1;
+ result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ reslenneeded=unum_toPattern(fmt, localized, result, resultlength,
+ &status);
+ }
+ if (icuError(env, status) != FALSE) {
+ return NULL;
+ }
+
+ jstring res = env->NewString(result, reslenneeded);
+
+ free(result);
+
+ return res;
+}
+
+static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value,
+ jobject field, jstring fieldType, jobject attributes) {
+
+ const char * fieldPositionClassName = "java/text/FieldPosition";
+ const char * stringBufferClassName = "java/lang/StringBuffer";
+ jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+ jclass stringBufferClass = env->FindClass(stringBufferClassName);
+ jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setBeginIndex", "(I)V");
+ jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setEndIndex", "(I)V");
+ jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
+ "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+ const char * fieldName = NULL;
+
+ if(fieldType != NULL) {
+ fieldName = env->GetStringUTFChars(fieldType, NULL);
+ }
+
+ uint32_t reslenneeded;
+ int64_t val = value;
+ UChar *result = NULL;
+
+ FieldPosition fp;
+ fp.setField(FieldPosition::DONT_CARE);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ DecimalFormat::AttrBuffer attrBuffer = NULL;
+ attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
+ attrBuffer->bufferSize = 128;
+ attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
+ attrBuffer->buffer[0] = '\0';
+
+ DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+ UnicodeString *res = new UnicodeString();
+
+ fmt->format(val, *res, fp, attrBuffer);
+
+ reslenneeded = res->extract(NULL, 0, status);
+
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+
+ result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
+
+ res->extract(result, reslenneeded + 1, status);
+ }
+ if (icuError(env, status) != FALSE) {
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ free(result);
+ delete(res);
+ return NULL;
+ }
+
+ int attrLength = 0;
+
+ attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+ if(strlen(attrBuffer->buffer) > 0) {
+
+ // check if we want to get all attributes
+ if(attributes != NULL) {
+ jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1); // cut off the leading ';'
+ env->CallObjectMethod(attributes, appendMethodID, attrString);
+ }
+
+ // check if we want one special attribute returned in the given FieldPos
+ if(fieldName != NULL && field != NULL) {
+ const char *delimiter = ";";
+ int begin;
+ int end;
+ char * resattr;
+ resattr = strtok(attrBuffer->buffer, delimiter);
+
+ while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+ resattr = strtok(NULL, delimiter);
+ }
+
+ if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+ resattr = strtok(NULL, delimiter);
+ begin = (int) strtol(resattr, NULL, 10);
+ resattr = strtok(NULL, delimiter);
+ end = (int) strtol(resattr, NULL, 10);
+
+ env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+ env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+ }
+ }
+ }
+
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+
+ jstring resulting = env->NewString(result, reslenneeded);
+
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ free(result);
+ delete(res);
+
+ return resulting;
+}
+
+static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value,
+ jobject field, jstring fieldType, jobject attributes) {
+
+ const char * fieldPositionClassName = "java/text/FieldPosition";
+ const char * stringBufferClassName = "java/lang/StringBuffer";
+ jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+ jclass stringBufferClass = env->FindClass(stringBufferClassName);
+ jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setBeginIndex", "(I)V");
+ jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setEndIndex", "(I)V");
+ jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
+ "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+ const char * fieldName = NULL;
+
+ if(fieldType != NULL) {
+ fieldName = env->GetStringUTFChars(fieldType, NULL);
+ }
+
+ uint32_t reslenneeded;
+ double val = value;
+ UChar *result = NULL;
+
+ FieldPosition fp;
+ fp.setField(FieldPosition::DONT_CARE);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ DecimalFormat::AttrBuffer attrBuffer = NULL;
+ attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
+ attrBuffer->bufferSize = 128;
+ attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
+ attrBuffer->buffer[0] = '\0';
+
+ DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+ UnicodeString *res = new UnicodeString();
+
+ fmt->format(val, *res, fp, attrBuffer);
+
+ reslenneeded = res->extract(NULL, 0, status);
+
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+
+ result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
+
+ res->extract(result, reslenneeded + 1, status);
+
+ }
+ if (icuError(env, status) != FALSE) {
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ free(result);
+ delete(res);
+ return NULL;
+ }
+
+ int attrLength = 0;
+
+ attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+ if(strlen(attrBuffer->buffer) > 0) {
+
+ // check if we want to get all attributes
+ if(attributes != NULL) {
+ jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1); // cut off the leading ';'
+ env->CallObjectMethod(attributes, appendMethodID, attrString);
+ }
+
+ // check if we want one special attribute returned in the given FieldPos
+ if(fieldName != NULL && field != NULL) {
+ const char *delimiter = ";";
+ int begin;
+ int end;
+ char * resattr;
+ resattr = strtok(attrBuffer->buffer, delimiter);
+
+ while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+ resattr = strtok(NULL, delimiter);
+ }
+
+ if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+ resattr = strtok(NULL, delimiter);
+ begin = (int) strtol(resattr, NULL, 10);
+ resattr = strtok(NULL, delimiter);
+ end = (int) strtol(resattr, NULL, 10);
+
+ env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+ env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+ }
+ }
+ }
+
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+
+ jstring resulting = env->NewString(result, reslenneeded);
+
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ free(result);
+ delete(res);
+
+ return resulting;
+}
+
+static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value,
+ jobject field, jstring fieldType, jobject attributes, jint scale) {
+
+ // const char * valueUTF = env->GetStringUTFChars(value, NULL);
+ // LOGI("ENTER formatDigitList: %s, scale: %d", valueUTF, scale);
+ // env->ReleaseStringUTFChars(value, valueUTF);
+
+ if (scale < 0) {
+ icuError(env, U_ILLEGAL_ARGUMENT_ERROR);
+ return NULL;
+ }
+
+ const char * fieldName = NULL;
+ if(fieldType != NULL) {
+ fieldName = env->GetStringUTFChars(fieldType, NULL);
+ }
+
+ uint32_t reslenneeded;
+
+ // prepare digit list
+
+ const char *valueChars = env->GetStringUTFChars(value, NULL);
+
+ bool isInteger = (scale == 0);
+ bool isPositive = (*valueChars != '-');
+
+ // skip the '-' if the number is negative
+ const char *digits = (isPositive ? valueChars : valueChars + 1);
+ int length = strlen(digits);
+
+ // The length of our digit list buffer must be the actual string length + 3,
+ // because ICU will append some additional characters at the head and at the
+ // tail of the string, in order to keep strtod() happy:
+ //
+ // - The sign "+" or "-" is appended at the head
+ // - The exponent "e" and the "\0" terminator is appended at the tail
+ //
+ // In retrospect, the changes to ICU's DigitList that were necessary for
+ // big numbers look a bit hacky. It would make sense to rework all this
+ // once ICU 4.x has been integrated into Android. Ideally, big number
+ // support would make it into ICU itself, so we don't need our private
+ // fix anymore.
+ DigitList digitList(length + 3);
+ digitList.fCount = length;
+ strcpy(digitList.fDigits, digits);
+ env->ReleaseStringUTFChars(value, valueChars);
+
+ digitList.fDecimalAt = digitList.fCount - scale;
+ digitList.fIsPositive = isPositive;
+ digitList.fRoundingMode = DecimalFormat::kRoundHalfUp;
+
+ UChar *result = NULL;
+
+ FieldPosition fp;
+ fp.setField(FieldPosition::DONT_CARE);
+ fp.setBeginIndex(0);
+ fp.setEndIndex(0);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ DecimalFormat::AttributeBuffer *attrBuffer = NULL;
+ attrBuffer = (DecimalFormat::AttributeBuffer *) calloc(sizeof(DecimalFormat::AttributeBuffer), 1);
+ attrBuffer->bufferSize = 128;
+ attrBuffer->buffer = (char *) calloc(129 * sizeof(char), 1);
+
+ DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+ UnicodeString res;
+
+ fmt->subformat(res, fp, attrBuffer, digitList, isInteger);
+
+ reslenneeded = res.extract(NULL, 0, status);
+
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+
+ result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
+
+ res.extract(result, reslenneeded + 1, status);
+
+ if (icuError(env, status) != FALSE) {
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+ free(result);
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ return NULL;
+ }
+
+ } else {
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ return NULL;
+ }
+
+ int attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+ if(attrLength > 1) {
+
+ // check if we want to get all attributes
+ if(attributes != NULL) {
+ // prepare the classes and method ids
+ const char * stringBufferClassName = "java/lang/StringBuffer";
+ jclass stringBufferClass = env->FindClass(stringBufferClassName);
+ jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
+ "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+ jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1); // cut off the leading ';'
+ env->CallObjectMethod(attributes, appendMethodID, attrString);
+ }
+
+ // check if we want one special attribute returned in the given FieldPos
+ if(fieldName != NULL && field != NULL) {
+ const char *delimiter = ";";
+ int begin;
+ int end;
+ char * resattr;
+ resattr = strtok(attrBuffer->buffer, delimiter);
+
+ while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+ resattr = strtok(NULL, delimiter);
+ }
+
+ if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+
+ // prepare the classes and method ids
+ const char * fieldPositionClassName =
+ "java/text/FieldPosition";
+ jclass fieldPositionClass = env->FindClass(
+ fieldPositionClassName);
+ jmethodID setBeginIndexMethodID = env->GetMethodID(
+ fieldPositionClass, "setBeginIndex", "(I)V");
+ jmethodID setEndIndexMethodID = env->GetMethodID(
+ fieldPositionClass, "setEndIndex", "(I)V");
+
+
+ resattr = strtok(NULL, delimiter);
+ begin = (int) strtol(resattr, NULL, 10);
+ resattr = strtok(NULL, delimiter);
+ end = (int) strtol(resattr, NULL, 10);
+
+ env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+ env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+ }
+ }
+ }
+
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+
+ jstring resulting = env->NewString(result, reslenneeded);
+
+ free(attrBuffer->buffer);
+ free(attrBuffer);
+ free(result);
+ // const char * resultUTF = env->GetStringUTFChars(resulting, NULL);
+ // LOGI("RETURN formatDigitList: %s", resultUTF);
+ // env->ReleaseStringUTFChars(resulting, resultUTF);
+
+ return resulting;
+}
+
+static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
+ jobject position) {
+
+ const char * textUTF = env->GetStringUTFChars(text, NULL);
+ env->ReleaseStringUTFChars(text, textUTF);
+
+ const char * parsePositionClassName = "java/text/ParsePosition";
+ const char * longClassName = "java/lang/Long";
+ const char * doubleClassName = "java/lang/Double";
+ const char * bigDecimalClassName = "java/math/BigDecimal";
+ const char * bigIntegerClassName = "java/math/BigInteger";
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ jchar *str = (UChar *)env->GetStringChars(text, NULL);
+ int strlength = env->GetStringLength(text);
+
+ jclass parsePositionClass = env->FindClass(parsePositionClassName);
+ jclass longClass = env->FindClass(longClassName);
+ jclass doubleClass = env->FindClass(doubleClassName);
+ jclass bigDecimalClass = env->FindClass(bigDecimalClassName);
+ jclass bigIntegerClass = env->FindClass(bigIntegerClassName);
+
+ jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass,
+ "getIndex", "()I");
+ jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass,
+ "setIndex", "(I)V");
+ jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass,
+ "setErrorIndex", "(I)V");
+
+ jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
+ jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
+ jmethodID bigDecimalInitMethodID = env->GetMethodID(bigDecimalClass, "<init>", "(Ljava/math/BigInteger;I)V");
+ jmethodID bigIntegerInitMethodID = env->GetMethodID(bigIntegerClass, "<init>", "(Ljava/lang/String;)V");
+ jmethodID doubleValueMethodID = env->GetMethodID(bigDecimalClass, "doubleValue", "()D");
+
+ bool resultAssigned;
+ int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+
+ // make sure the ParsePosition is valid. Actually icu4c would parse a number
+ // correctly even if the parsePosition is set to -1, but since the RI fails
+ // for that case we have to fail too
+ if(parsePos < 0 || parsePos > strlength) {
+ return NULL;
+ }
+
+ Formattable res;
+
+ const UnicodeString src((UChar*)str, strlength, strlength);
+ ParsePosition pp;
+
+ pp.setIndex(parsePos);
+
+ DigitList digits;
+
+ ((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits);
+
+ env->ReleaseStringChars(text, str);
+
+ if(pp.getErrorIndex() == -1) {
+ parsePos = pp.getIndex();
+ } else {
+ env->CallVoidMethod(position, setErrorIndexMethodID,
+ (jint) pp.getErrorIndex());
+ return NULL;
+ }
+
+ Formattable::Type numType;
+ numType = res.getType();
+ UErrorCode fmtStatus;
+
+ double resultDouble;
+ long resultLong;
+ int64_t resultInt64;
+ UnicodeString resultString;
+ jstring resultStr;
+ int resLength;
+ const char * resultUTF;
+ jobject resultObject1, resultObject2;
+ jdouble doubleTest;
+ jchar * result;
+
+ if (resultAssigned)
+ {
+ switch(numType) {
+ case Formattable::kDouble:
+ resultDouble = res.getDouble();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(doubleClass, dblInitMethodID,
+ (jdouble) resultDouble);
+ case Formattable::kLong:
+ resultLong = res.getLong();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID,
+ (jlong) resultLong);
+ case Formattable::kInt64:
+ resultInt64 = res.getInt64();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID,
+ (jlong) resultInt64);
+ default:
+ return NULL;
+ }
+ }
+ else
+ {
+ int scale = digits.fCount - digits.fDecimalAt;
+ // ATTENTION: Abuse of Implementation Knowlegde!
+ digits.fDigits[digits.fCount] = 0;
+ if (digits.fIsPositive) {
+ resultStr = env->NewStringUTF(digits.fDigits);
+ } else {
+ if (digits.fCount == 0) {
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(doubleClass, dblInitMethodID, (jdouble)-0);
+ } else {
+ // ATTENTION: Abuse of Implementation Knowlegde!
+ *(digits.fDigits - 1) = '-';
+ resultStr = env->NewStringUTF(digits.fDigits - 1);
+ }
+ }
+
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+
+ resultObject1 = env->NewObject(bigIntegerClass, bigIntegerInitMethodID, resultStr);
+ resultObject2 = env->NewObject(bigDecimalClass, bigDecimalInitMethodID, resultObject1, scale);
+ return resultObject2;
+ }
+}
+
+static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ UNumberFormat *result = unum_clone(fmt, &status);
+
+ if(icuError(env, status) != FALSE) {
+ return 0;
+ }
+
+ return (long) result;
+
+}
+
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) openDecimalFormatImpl},
+ {"closeDecimalFormatImpl", "(I)V", (void*) closeDecimalFormatImpl},
+ {"setSymbol", "(IILjava/lang/String;)V", (void*) setSymbol},
+ {"getSymbol", "(II)Ljava/lang/String;", (void*) getSymbol},
+ {"setAttribute", "(III)V", (void*) setAttribute},
+ {"getAttribute", "(II)I", (void*) getAttribute},
+ {"setTextAttribute", "(IILjava/lang/String;)V", (void*) setTextAttribute},
+ {"getTextAttribute", "(II)Ljava/lang/String;", (void*) getTextAttribute},
+ {"applyPatternImpl", "(IZLjava/lang/String;)V", (void*) applyPatternImpl},
+ {"toPatternImpl", "(IZ)Ljava/lang/String;", (void*) toPatternImpl},
+ {"format",
+ "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
+ (void*) formatLong},
+ {"format",
+ "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
+ (void*) formatDouble},
+ {"format",
+ "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;",
+ (void*) formatDigitList},
+ {"parse",
+ "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;",
+ (void*) parse},
+ {"cloneImpl", "(I)I", (void*) cloneImpl}
+};
+int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods,
+ NELEM(gMethods));
+}
diff --git a/icu/src/main/native/ErrorCode.c b/icu/src/main/native/ErrorCode.c
new file mode 100644
index 0000000..b3e43cd
--- /dev/null
+++ b/icu/src/main/native/ErrorCode.c
@@ -0,0 +1,57 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+#include "ErrorCode.h"
+
+/* private data members ----------------------------------------------------*/
+
+/**
+* Name of the java runtime exception classes
+*/
+#define ILLEGALARGUMENTEXCEPTION_ "java/lang/IllegalArgumentException"
+#define ARRAYINDEXOUTOFBOUNDSEXCEPTION_ "java/lang/ArrayIndexOutOfBoundsException"
+#define UNSUPPORTEDOPERATIONEXCEPTION_ "java/lang/UnsupportedOperationException"
+#define RUNTIMEEXCEPTION_ "java/lang/RuntimeException"
+
+/* public methods ---------------------------------------------------------*/
+
+/**
+* Checks if an error has occured.
+* Throws a generic Java RuntimeException if an error has occured.
+* @param env JNI environment variable
+* @param errorcode code to determine if it is an erro
+* @return 0 if errorcode is not an error, 1 if errorcode is an error, but the
+* creation of the exception to be thrown fails
+* @exception thrown if errorcode represents an error
+*/
+UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode)
+{
+ const char *emsg = u_errorName(errorcode);
+ jclass exception;
+
+ if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+ switch (errorcode) {
+ case U_ILLEGAL_ARGUMENT_ERROR :
+ exception = (*env)->FindClass(env, ILLEGALARGUMENTEXCEPTION_);
+ break;
+ case U_INDEX_OUTOFBOUNDS_ERROR :
+ case U_BUFFER_OVERFLOW_ERROR :
+ exception = (*env)->FindClass(env, ARRAYINDEXOUTOFBOUNDSEXCEPTION_);
+ break;
+ case U_UNSUPPORTED_ERROR :
+ exception = (*env)->FindClass(env, UNSUPPORTEDOPERATIONEXCEPTION_);
+ break;
+ default :
+ exception = (*env)->FindClass(env, RUNTIMEEXCEPTION_);
+ }
+
+ return ((*env)->ThrowNew(env, exception, emsg) != 0);
+ }
+ return 0;
+}
diff --git a/icu/src/main/native/ErrorCode.h b/icu/src/main/native/ErrorCode.h
new file mode 100644
index 0000000..a5bbfc6
--- /dev/null
+++ b/icu/src/main/native/ErrorCode.h
@@ -0,0 +1,27 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*******************************************************************************
+*/
+
+#ifndef ERRORCODE_H
+#define ERRORCODE_H
+
+#include <jni.h>
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+
+/**
+* Checks if an error has occured.
+* Throws a generic Java RuntimeException if an error has occured.
+* @param env JNI environment variable
+* @param errorcode code to determine if it is an erro
+* @return 0 if errorcode is not an error, 1 if errorcode is an error, but the
+* creation of the exception to be thrown fails
+* @exception thrown if errorcode represents an error
+*/
+UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode);
+
+#endif
diff --git a/icu/src/main/native/RBNFInterface.cpp b/icu/src/main/native/RBNFInterface.cpp
new file mode 100644
index 0000000..d9bf460
--- /dev/null
+++ b/icu/src/main/native/RBNFInterface.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/numfmt.h"
+#include "unicode/rbnf.h"
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+ const char *emsg = u_errorName(errorcode);
+ jclass exception;
+
+ if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+ switch (errorcode) {
+ case U_ILLEGAL_ARGUMENT_ERROR :
+ exception = env->FindClass("java/lang/IllegalArgumentException");
+ break;
+ case U_INDEX_OUTOFBOUNDS_ERROR :
+ case U_BUFFER_OVERFLOW_ERROR :
+ exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+ break;
+ case U_UNSUPPORTED_ERROR :
+ exception = env->FindClass("java/lang/UnsupportedOperationException");
+ break;
+ default :
+ exception = env->FindClass("java/lang/RuntimeException");
+ }
+
+ return (env->ThrowNew(exception, emsg) != 0);
+ }
+ return 0;
+}
+
+static jint openRBNFImpl1(JNIEnv* env, jclass clazz,
+ jint type, jstring locale) {
+
+ // LOGI("ENTER openRBNFImpl1");
+
+ // the errorcode returned by unum_open
+ UErrorCode status = U_ZERO_ERROR;
+
+ // prepare the locale string for the call to unum_open
+ const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+ URBNFRuleSetTag style;
+ if(type == 0) {
+ style = URBNF_SPELLOUT;
+ } else if(type == 1) {
+ style = URBNF_ORDINAL;
+ } else if(type == 2) {
+ style = URBNF_DURATION;
+ } else if(type == 3) {
+ style = URBNF_COUNT;
+ } else {
+ icuError(env, U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ Locale loc = Locale::createFromName(localeChars);
+
+ // open a default type number format
+ RuleBasedNumberFormat *fmt = new RuleBasedNumberFormat(style, loc, status);
+
+ // release the allocated strings
+ env->ReleaseStringUTFChars(locale, localeChars);
+
+ // check for an error
+ if ( icuError(env, status) != FALSE) {
+ return 0;
+ }
+
+ // return the handle to the number format
+ return (long) fmt;
+
+}
+
+static jint openRBNFImpl2(JNIEnv* env, jclass clazz,
+ jstring rule, jstring locale) {
+
+ // LOGI("ENTER openRBNFImpl2");
+
+ // the errorcode returned by unum_open
+ UErrorCode status = U_ZERO_ERROR;
+
+ // prepare the pattern string for the call to unum_open
+ const UChar *ruleChars = env->GetStringChars(rule, NULL);
+ int ruleLen = env->GetStringLength(rule);
+
+ // prepare the locale string for the call to unum_open
+ const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+ // open a rule based number format
+ UNumberFormat *fmt = unum_open(UNUM_PATTERN_RULEBASED, ruleChars, ruleLen,
+ localeChars, NULL, &status);
+
+ // release the allocated strings
+ env->ReleaseStringChars(rule, ruleChars);
+ env->ReleaseStringUTFChars(locale, localeChars);
+
+ // check for an error
+ if ( icuError(env, status) != FALSE) {
+ return 0;
+ }
+
+ // return the handle to the number format
+ return (long) fmt;
+
+}
+
+static void closeRBNFImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+ // LOGI("ENTER closeRBNFImpl");
+
+ // get the pointer to the number format
+ RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+ // close this number format
+ delete fmt;
+}
+
+static jstring formatLongRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jlong value,
+ jobject field, jstring fieldType, jobject attributes) {
+
+ // LOGI("ENTER formatLongRBNFImpl");
+
+ const char * fieldPositionClassName = "java/text/FieldPosition";
+ const char * stringBufferClassName = "java/lang/StringBuffer";
+ jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+ jclass stringBufferClass = env->FindClass(stringBufferClassName);
+ jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setBeginIndex", "(I)V");
+ jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setEndIndex", "(I)V");
+ jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
+ "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+ const char * fieldName = NULL;
+
+ if(fieldType != NULL) {
+ fieldName = env->GetStringUTFChars(fieldType, NULL);
+ }
+
+ uint32_t reslenneeded;
+ int64_t val = value;
+ UChar *result = NULL;
+
+ FieldPosition fp;
+ fp.setField(FieldPosition::DONT_CARE);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+ UnicodeString res;
+
+ fmt->format(val, res, fp);
+
+ reslenneeded = res.extract(NULL, 0, status);
+
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+
+ result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
+
+ res.extract(result, reslenneeded + 1, status);
+ }
+ if (icuError(env, status) != FALSE) {
+ free(result);
+ return NULL;
+ }
+
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+
+ jstring resulting = env->NewString(result, reslenneeded);
+
+ free(result);
+
+ return resulting;
+}
+
+static jstring formatDoubleRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jdouble value,
+ jobject field, jstring fieldType, jobject attributes) {
+
+ // LOGI("ENTER formatDoubleRBNFImpl");
+
+ const char * fieldPositionClassName = "java/text/FieldPosition";
+ const char * stringBufferClassName = "java/lang/StringBuffer";
+ jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+ jclass stringBufferClass = env->FindClass(stringBufferClassName);
+ jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setBeginIndex", "(I)V");
+ jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
+ "setEndIndex", "(I)V");
+ jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
+ "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+ const char * fieldName = NULL;
+
+ if(fieldType != NULL) {
+ fieldName = env->GetStringUTFChars(fieldType, NULL);
+ }
+
+ uint32_t reslenneeded;
+ double val = value;
+ UChar *result = NULL;
+
+ FieldPosition fp;
+ fp.setField(FieldPosition::DONT_CARE);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+ UnicodeString res;
+
+ fmt->format(val, res, fp);
+
+ reslenneeded = res.extract(NULL, 0, status);
+
+ if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status=U_ZERO_ERROR;
+
+ result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
+
+ res.extract(result, reslenneeded + 1, status);
+ }
+ if (icuError(env, status) != FALSE) {
+ free(result);
+ return NULL;
+ }
+
+ if(fieldType != NULL) {
+ env->ReleaseStringUTFChars(fieldType, fieldName);
+ }
+
+ jstring resulting = env->NewString(result, reslenneeded);
+
+ free(result);
+
+ return resulting;
+}
+
+static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text,
+ jobject position, jboolean lenient) {
+
+ // LOGI("ENTER parseRBNFImpl");
+
+ const char * parsePositionClassName = "java/text/ParsePosition";
+ const char * longClassName = "java/lang/Long";
+ const char * doubleClassName = "java/lang/Double";
+
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+ jchar *str = (UChar *)env->GetStringChars(text, NULL);
+ int strlength = env->GetStringLength(text);
+
+ jclass parsePositionClass = env->FindClass(parsePositionClassName);
+ jclass longClass = env->FindClass(longClassName);
+ jclass doubleClass = env->FindClass(doubleClassName);
+
+ jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass,
+ "getIndex", "()I");
+ jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass,
+ "setIndex", "(I)V");
+ jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass,
+ "setErrorIndex", "(I)V");
+
+ jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
+ jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
+
+ int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+
+ // make sure the ParsePosition is valid. Actually icu4c would parse a number
+ // correctly even if the parsePosition is set to -1, but since the RI fails
+ // for that case we have to fail too
+ if(parsePos < 0 || parsePos > strlength) {
+ return NULL;
+ }
+
+ Formattable res;
+
+ const UnicodeString src((UChar*)str, strlength, strlength);
+ ParsePosition pp;
+
+ pp.setIndex(parsePos);
+
+ if(lenient) {
+ unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_TRUE);
+ }
+
+ ((const NumberFormat*)fmt)->parse(src, res, pp);
+
+ if(lenient) {
+ unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_FALSE);
+ }
+
+ env->ReleaseStringChars(text, str);
+
+ if(pp.getErrorIndex() == -1) {
+ parsePos = pp.getIndex();
+ } else {
+ env->CallVoidMethod(position, setErrorIndexMethodID,
+ (jint) pp.getErrorIndex());
+ return NULL;
+ }
+
+ Formattable::Type numType;
+ numType = res.getType();
+ UErrorCode fmtStatus;
+
+ double resultDouble;
+ long resultLong;
+ int64_t resultInt64;
+
+ switch(numType) {
+ case Formattable::kDouble:
+ resultDouble = res.getDouble();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(doubleClass, dblInitMethodID,
+ (jdouble) resultDouble);
+ case Formattable::kLong:
+ resultLong = res.getLong();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID,
+ (jlong) resultLong);
+ case Formattable::kInt64:
+ resultInt64 = res.getInt64();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID,
+ (jlong) resultInt64);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"openRBNFImpl", "(ILjava/lang/String;)I", (void*) openRBNFImpl1},
+ {"openRBNFImpl", "(Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) openRBNFImpl2},
+ {"closeRBNFImpl", "(I)V", (void*) closeRBNFImpl},
+ {"formatRBNFImpl",
+ "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
+ (void*) formatLongRBNFImpl},
+ {"formatRBNFImpl",
+ "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
+ (void*) formatDoubleRBNFImpl},
+ {"parseRBNFImpl",
+ "(ILjava/lang/String;Ljava/text/ParsePosition;Z)Ljava/lang/Number;",
+ (void*) parseRBNFImpl},
+};
+int register_com_ibm_icu4jni_text_NativeRBNF(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "com/ibm/icu4jni/text/RuleBasedNumberFormat", gMethods,
+ NELEM(gMethods));
+}
diff --git a/icu/src/main/native/RegExInterface.cpp b/icu/src/main/native/RegExInterface.cpp
new file mode 100644
index 0000000..afa5cc4
--- /dev/null
+++ b/icu/src/main/native/RegExInterface.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "unicode/uregex.h"
+#include "unicode/utypes.h"
+#include "unicode/parseerr.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+static jchar EMPTY_STRING = 0;
+
+/**
+ * A data structure that ties together an ICU regular expression and the
+ * character data it refers to (but does not have a copy of), so we can
+ * manage memory properly.
+ */
+typedef struct RegExDataStruct {
+ // A pointer to the ICU regular expression
+ URegularExpression* regex;
+ // A pointer to (a copy of) the input text that *we* manage
+ jchar* text;
+} RegExData;
+
+static void throwPatternSyntaxException(JNIEnv* env, UErrorCode status,
+ jstring pattern, UParseError error)
+{
+ jclass clazz = env->FindClass("java/util/regex/PatternSyntaxException");
+ jmethodID method = env->GetMethodID(clazz, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;I)V");
+
+ jstring message = env->NewStringUTF(u_errorName(status));
+ jthrowable except = (jthrowable)(env->NewObject(clazz, method, message,
+ pattern, error.offset));
+ env->Throw(except);
+}
+
+static void throwRuntimeException(JNIEnv* env, UErrorCode status)
+{
+ jniThrowException(env, "java/lang/RuntimeException", u_errorName(status));
+}
+
+static void _close(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ if (data->regex != NULL) {
+ uregex_close(data->regex);
+ }
+
+ if (data->text != NULL && data->text != &EMPTY_STRING) {
+ free(data->text);
+ }
+
+ free(data);
+}
+
+static RegExData* open(JNIEnv* env, jclass clazz, jstring pattern, jint flags)
+{
+ flags = flags | UREGEX_ERROR_ON_UNKNOWN_ESCAPES;
+
+ RegExData* data = (RegExData*)calloc(sizeof(RegExData), 1);
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError error;
+ error.offset = -1;
+
+ jchar const * patternRaw;
+ int patternLen = env->GetStringLength(pattern);
+ if (patternLen == 0) {
+ data->regex = uregex_open(&EMPTY_STRING, -1, flags, &error, &status);
+ } else {
+ jchar const * patternRaw = env->GetStringChars(pattern, NULL);
+ data->regex = uregex_open(patternRaw, patternLen, flags, &error,
+ &status);
+ env->ReleaseStringChars(pattern, patternRaw);
+ }
+
+ if (!U_SUCCESS(status)) {
+ _close(env, clazz, data);
+ throwPatternSyntaxException(env, status, pattern, error);
+ data = NULL;
+ }
+
+ return data;
+}
+
+static RegExData* _clone(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ URegularExpression* clonedRegex = uregex_clone(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ RegExData* result = (RegExData*)calloc(sizeof(RegExData), 1);
+ result->regex = clonedRegex;
+
+ return result;
+}
+
+static void setText(JNIEnv* env, jclass clazz, RegExData* data, jstring text)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ uregex_setText(data->regex, &EMPTY_STRING, 0, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ return;
+ }
+
+ if (data->text != NULL && data->text != &EMPTY_STRING) {
+ free(data->text);
+ data->text = NULL;
+ }
+
+ int textLen = env->GetStringLength(text);
+ if (textLen == 0) {
+ data->text = &EMPTY_STRING;
+ } else {
+ jchar const * textRaw = env->GetStringChars(text, NULL);
+ data->text = (jchar*)malloc((textLen + 1) * sizeof(jchar));
+ memcpy(data->text, textRaw, textLen * sizeof(jchar));
+ data->text[textLen] = 0;
+ env->ReleaseStringChars(text, textRaw);
+ }
+
+ uregex_setText(data->regex, data->text, textLen, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+static jboolean matches(JNIEnv* env, jclass clazz, RegExData* data,
+ jint startIndex)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jboolean result = uregex_matches(data->regex, startIndex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ return result;
+}
+
+static jboolean lookingAt(JNIEnv* env, jclass clazz, RegExData* data,
+ jint startIndex)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jboolean result = uregex_lookingAt(data->regex, startIndex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ return result;
+}
+
+static jboolean find(JNIEnv* env, jclass clazz, RegExData* data,
+ jint startIndex)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jboolean result = uregex_find(data->regex, startIndex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ return result;
+}
+
+static jboolean findNext(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jboolean result = uregex_findNext(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ return result;
+}
+
+static jint groupCount(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jint result = uregex_groupCount(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+
+ return result;
+}
+
+static void startEnd(JNIEnv* env, jclass clazz, RegExData* data,
+ jintArray offsets)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ jint * offsetsRaw = env->GetIntArrayElements(offsets, NULL);
+
+ int groupCount = uregex_groupCount(data->regex, &status);
+ for (int i = 0; i <= groupCount && U_SUCCESS(status); i++) {
+ offsetsRaw[2 * i + 0] = uregex_start(data->regex, i, &status);
+ offsetsRaw[2 * i + 1] = uregex_end(data->regex, i, &status);
+ }
+
+ env->ReleaseIntArrayElements(offsets, offsetsRaw, 0);
+
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+static void setRegion(JNIEnv* env, jclass clazz, RegExData* data, jint start,
+ jint end)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ uregex_setRegion(data->regex, start, end, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+static jint regionStart(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int result = uregex_regionStart(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static jint regionEnd(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int result = uregex_regionEnd(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static void useTransparentBounds(JNIEnv* env, jclass clazz, RegExData* data,
+ jboolean value)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ uregex_useTransparentBounds(data->regex, value, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+static jboolean hasTransparentBounds(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ jboolean result = uregex_hasTransparentBounds(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static void useAnchoringBounds(JNIEnv* env, jclass clazz, RegExData* data,
+ jboolean value)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ uregex_useAnchoringBounds(data->regex, value, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+static jboolean hasAnchoringBounds(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ jboolean result = uregex_hasAnchoringBounds(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static jboolean hitEnd(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ jboolean result = uregex_hitEnd(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static jboolean requireEnd(JNIEnv* env, jclass clazz, RegExData* data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ jboolean result = uregex_requireEnd(data->regex, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+ return result;
+}
+
+static void reset(JNIEnv* env, jclass clazz, RegExData* data, jint position)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ uregex_reset(data->regex, position, &status);
+ if (!U_SUCCESS(status)) {
+ throwRuntimeException(env, status);
+ }
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ { "open", "(Ljava/lang/String;I)I", (void*)open },
+ { "clone", "(I)I", (void*)_clone },
+ { "close", "(I)V", (void*)_close },
+ { "setText", "(ILjava/lang/String;)V", (void*)setText },
+ { "matches", "(II)Z", (void*)matches },
+ { "lookingAt", "(II)Z", (void*)lookingAt },
+ { "find", "(II)Z", (void*)find },
+ { "findNext", "(I)Z", (void*)findNext },
+ { "groupCount", "(I)I", (void*)groupCount },
+ { "startEnd", "(I[I)V", (void*)startEnd },
+ { "setRegion", "(III)V", (void*)setRegion },
+ { "regionStart", "(I)I", (void*)regionStart },
+ { "regionEnd", "(I)I", (void*)regionEnd },
+ { "useTransparentBounds", "(IZ)V", (void*)useTransparentBounds },
+ { "hasTransparentBounds", "(I)Z", (void*)hasTransparentBounds },
+ { "useAnchoringBounds", "(IZ)V", (void*)useAnchoringBounds },
+ { "hasAnchoringBounds", "(I)Z", (void*)hasAnchoringBounds },
+ { "hitEnd", "(I)Z", (void*)hitEnd },
+ { "requireEnd", "(I)Z", (void*)requireEnd },
+ { "reset", "(II)V", (void*)reset }
+};
+
+extern "C" int register_com_ibm_icu4jni_regex_NativeRegEx(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("com/ibm/icu4jni/regex/NativeRegEx");
+ if (clazz == NULL) {
+ return -1;
+ }
+
+ if (env->RegisterNatives(clazz, sMethods, NELEM(sMethods)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/icu/src/main/native/ResourceInterface.cpp b/icu/src/main/native/ResourceInterface.cpp
new file mode 100644
index 0000000..5f9d442
--- /dev/null
+++ b/icu/src/main/native/ResourceInterface.cpp
@@ -0,0 +1,1436 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ucal.h"
+#include "unicode/gregocal.h"
+#include "unicode/ucurr.h"
+#include "unicode/calendar.h"
+#include "unicode/datefmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/uclean.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/strenum.h"
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+#include "ErrorCode.h"
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+jclass string_class;
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+ const char *emsg = u_errorName(errorcode);
+ jclass exception;
+
+ if (U_FAILURE(errorcode)) {
+ switch (errorcode) {
+ case U_ILLEGAL_ARGUMENT_ERROR :
+ exception = env->FindClass("java/lang/IllegalArgumentException");
+ break;
+ case U_INDEX_OUTOFBOUNDS_ERROR :
+ case U_BUFFER_OVERFLOW_ERROR :
+ exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+ break;
+ case U_UNSUPPORTED_ERROR :
+ exception = env->FindClass("java/lang/UnsupportedOperationException");
+ break;
+ default :
+ exception = env->FindClass("java/lang/RuntimeException");
+ }
+
+ return (env->ThrowNew(exception, emsg) != 0);
+ }
+ return 0;
+}
+
+static Locale getLocale(JNIEnv *env, jstring locale) {
+ const char *name = env->GetStringUTFChars(locale, NULL);
+ Locale result = Locale::createFromName(name);
+ env->ReleaseStringUTFChars(locale, name);
+ return result;
+}
+
+static jstring getJStringFromUnicodeString(JNIEnv *env, UnicodeString string) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ int stringLength = string.length();
+ jchar *res = (jchar *) malloc(sizeof(jchar) * (stringLength + 1));
+ string.extract(res, stringLength+1, status);
+ if(U_FAILURE(status)) {
+ free(res);
+ LOGI("Error getting string for getJStringFromUnicodeString");
+ status = U_ZERO_ERROR;
+ return NULL;
+ }
+ jstring result = env->NewString(res, stringLength);
+ free(res);
+ return result;
+}
+
+static void addObject(JNIEnv *env, jobjectArray result, const char *keyStr, jobject elem, int index) {
+ jclass objArray_class = env->FindClass("java/lang/Object");
+ jobjectArray element = env->NewObjectArray(2, objArray_class, NULL);
+ jstring key = env->NewStringUTF(keyStr);
+ env->SetObjectArrayElement(element, 0, key);
+ env->SetObjectArrayElement(element, 1, elem);
+ env->SetObjectArrayElement(result, index, element);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(element);
+}
+
+static jint getFractionDigitsNative(JNIEnv* env, jclass clazz,
+ jstring currencyCode) {
+ // LOGI("ENTER getFractionDigitsNative");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ NumberFormat *fmt = NumberFormat::createCurrencyInstance(status);
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ const jchar *cCode = env->GetStringChars(currencyCode, NULL);
+ fmt->setCurrency(cCode, status);
+ env->ReleaseStringChars(currencyCode, cCode);
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ // for CurrencyFormats the minimum and maximum fraction digits are the same.
+ int result = fmt->getMinimumFractionDigits();
+ delete(fmt);
+ return result;
+}
+
+static jstring getCurrencyCodeNative(JNIEnv* env, jclass clazz,
+ jstring key) {
+ // LOGI("ENTER getCurrencyCodeNative");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UResourceBundle *supplData = ures_openDirect(NULL, "supplementalData", &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *currencyMap = ures_getByKey(supplData, "CurrencyMap", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(supplData);
+ return NULL;
+ }
+
+ const char *keyChars = env->GetStringUTFChars(key, NULL);
+ UResourceBundle *currency = ures_getByKey(currencyMap, keyChars, NULL, &status);
+ env->ReleaseStringUTFChars(key, keyChars);
+ if(U_FAILURE(status)) {
+ ures_close(currencyMap);
+ ures_close(supplData);
+ return NULL;
+ }
+
+ UResourceBundle *currencyElem = ures_getByIndex(currency, 0, NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(currency);
+ ures_close(currencyMap);
+ ures_close(supplData);
+ return env->NewStringUTF("None");
+ }
+
+ // check if there is a to date. If there is, the currency isn't used anymore.
+ UResourceBundle *currencyTo = ures_getByKey(currencyElem, "to", NULL, &status);
+ if(!U_FAILURE(status)) {
+ // return and let the ResourceBundle throw an exception
+ ures_close(currencyElem);
+ ures_close(currency);
+ ures_close(currencyMap);
+ ures_close(supplData);
+ return NULL;
+ }
+ status = U_ZERO_ERROR;
+ ures_close(currencyTo);
+
+ UResourceBundle *currencyId = ures_getByKey(currencyElem, "id", NULL, &status);
+ if(U_FAILURE(status)) {
+ // No id defined for this country
+ ures_close(currencyElem);
+ ures_close(currency);
+ ures_close(currencyMap);
+ ures_close(supplData);
+ return env->NewStringUTF("None");
+ }
+
+ int length;
+ const jchar *id = ures_getString(currencyId, &length, &status);
+ if(U_FAILURE(status)) {
+ ures_close(currencyId);
+ ures_close(currencyElem);
+ ures_close(currency);
+ ures_close(currencyMap);
+ ures_close(supplData);
+ return env->NewStringUTF("None");
+ }
+
+ ures_close(currencyId);
+ ures_close(currencyElem);
+ ures_close(currency);
+ ures_close(currencyMap);
+ ures_close(supplData);
+
+ if(length == 0) {
+ return env->NewStringUTF("None");
+ }
+ return env->NewString(id, length);
+}
+
+static jstring getCurrencySymbolNative(JNIEnv* env, jclass clazz,
+ jstring locale, jstring currencyCode) {
+ // LOGI("ENTER getCurrencySymbolNative");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *locName = env->GetStringUTFChars(locale, NULL);
+ UResourceBundle *root = ures_open(NULL, locName, &status);
+ env->ReleaseStringUTFChars(locale, locName);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *rootElems = ures_getByKey(root, "Currencies", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(root);
+ return NULL;
+ }
+
+ const char *currName = env->GetStringUTFChars(currencyCode, NULL);
+ UResourceBundle *currencyElems = ures_getByKey(rootElems, currName, NULL, &status);
+ env->ReleaseStringUTFChars(currencyCode, currName);
+ if(U_FAILURE(status)) {
+ ures_close(rootElems);
+ ures_close(root);
+ return NULL;
+ }
+
+ int currSymbL;
+ const jchar *currSymbU = ures_getStringByIndex(currencyElems, 0, &currSymbL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(currencyElems);
+ ures_close(rootElems);
+ ures_close(root);
+ return NULL;
+ }
+
+ ures_close(currencyElems);
+ ures_close(rootElems);
+ ures_close(root);
+
+ if(currSymbL == 0) {
+ return NULL;
+ }
+ return env->NewString(currSymbU, currSymbL);
+}
+
+static jstring getDisplayCountryNative(JNIEnv* env, jclass clazz,
+ jstring targetLocale, jstring locale) {
+ // LOGI("ENTER getDisplayCountryNative");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ Locale loc = getLocale(env, locale);
+ Locale targetLoc = getLocale(env, targetLocale);
+
+ UnicodeString string;
+ targetLoc.getDisplayCountry(loc, string);
+
+ jstring result = getJStringFromUnicodeString(env, string);
+
+ return result;
+}
+
+static jstring getDisplayLanguageNative(JNIEnv* env, jclass clazz,
+ jstring targetLocale, jstring locale) {
+ // LOGI("ENTER getDisplayLanguageNative");
+
+ Locale loc = getLocale(env, locale);
+ Locale targetLoc = getLocale(env, targetLocale);
+
+ UnicodeString string;
+ targetLoc.getDisplayLanguage(loc, string);
+
+ jstring result = getJStringFromUnicodeString(env, string);
+
+ return result;
+}
+
+static jstring getDisplayVariantNative(JNIEnv* env, jclass clazz,
+ jstring targetLocale, jstring locale) {
+ // LOGI("ENTER getDisplayVariantNative");
+
+ Locale loc = getLocale(env, locale);
+ Locale targetLoc = getLocale(env, targetLocale);
+
+ UnicodeString string;
+ targetLoc.getDisplayVariant(loc, string);
+
+ jstring result = getJStringFromUnicodeString(env, string);
+
+ return result;
+}
+
+static jstring getISO3CountryNative(JNIEnv* env, jclass clazz, jstring locale) {
+ // LOGI("ENTER getISO3CountryNative");
+
+ Locale loc = getLocale(env, locale);
+
+ const char *string = loc.getISO3Country();
+
+ jstring result = env->NewStringUTF(string);
+
+ return result;
+}
+
+static jstring getISO3LanguageNative(JNIEnv* env, jclass clazz, jstring locale) {
+ // LOGI("ENTER getISO3LanguageNative");
+
+ Locale loc = getLocale(env, locale);
+
+ const char *string = loc.getISO3Language();
+
+ jstring result = env->NewStringUTF(string);
+
+ return result;
+}
+
+static jobjectArray getISOCountriesNative(JNIEnv* env, jclass clazz) {
+ // LOGI("ENTER getISOCountriesNative");
+
+ const char* const* strings = Locale::getISOCountries();
+
+ int count = 0;
+ while(strings[count] != NULL) {
+ count++;
+ }
+
+ jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+ jstring res;
+ for(int i = 0; i < count; i++) {
+ res = env->NewStringUTF(strings[i]);
+ env->SetObjectArrayElement(result, i, res);
+ env->DeleteLocalRef(res);
+ }
+ return result;
+}
+
+static jobjectArray getISOLanguagesNative(JNIEnv* env, jclass clazz) {
+ // LOGI("ENTER getISOLanguagesNative");
+
+ const char* const* strings = Locale::getISOLanguages();
+
+ const char *string = strings[0];
+
+ int count = 0;
+ while(strings[count] != NULL) {
+ count++;
+ }
+
+ jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+ jstring res;
+ for(int i = 0; i < count; i++) {
+ res = env->NewStringUTF(strings[i]);
+ env->SetObjectArrayElement(result, i, res);
+ env->DeleteLocalRef(res);
+ }
+ return result;
+}
+
+static jobjectArray getAvailableLocalesNative(JNIEnv* env, jclass clazz) {
+ // LOGI("ENTER getAvailableLocalesNative");
+
+ int count = uloc_countAvailable();
+
+ jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+ jstring res;
+ const char * string;
+ for(int i = 0; i < count; i++) {
+ string = uloc_getAvailable(i);
+ res = env->NewStringUTF(string);
+ env->SetObjectArrayElement(result, i, res);
+ env->DeleteLocalRef(res);
+ }
+
+ return result;
+}
+
+static void getTimeZonesNative(JNIEnv* env, jclass clazz,
+ jobjectArray outerArray, jstring locale) {
+ // LOGI("ENTER getTimeZonesNative");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ jobjectArray zoneIdArray;
+ jobjectArray longStdTimeArray;
+ jobjectArray shortStdTimeArray;
+ jobjectArray longDlTimeArray;
+ jobjectArray shortDlTimeArray;
+
+ jstring content;
+ jstring strObj;
+ const jchar *res;
+ UnicodeString resU;
+ jint length;
+ const UnicodeString *zoneID;
+ DateFormat *df;
+
+ UnicodeString longPattern("zzzz","");
+ UnicodeString shortPattern("z","");
+
+ Locale loc = getLocale(env, locale);
+
+ SimpleDateFormat longFormat(longPattern, loc, status);
+ SimpleDateFormat shortFormat(shortPattern, loc, status);
+
+
+ zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0);
+ longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1);
+ shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2);
+ longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3);
+ shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4);
+
+ int count = env->GetArrayLength(zoneIdArray);
+
+ TimeZone* zones[count];
+
+ // get all timezone objects
+ for(int i = 0; i < count; i++) {
+ strObj = (jstring) env->GetObjectArrayElement(zoneIdArray, i);
+ length = env->GetStringLength(strObj);
+ res = env->GetStringChars(strObj, NULL);
+ const UnicodeString zoneID((UChar *)res, length);
+ env->ReleaseStringChars(strObj, res);
+ zones[i] = TimeZone::createTimeZone(zoneID);
+ env->DeleteLocalRef(strObj);
+ }
+
+ // 15th January 2008
+ UDate date1 = 1203105600000.0;
+ // 15th July 2008
+ UDate date2 = 1218826800000.0;
+
+ for (int i = 0; i < count; i++) {
+ TimeZone *tz = zones[i];
+ longFormat.setTimeZone(*tz);
+ shortFormat.setTimeZone(*tz);
+
+ int32_t daylightOffset;
+ int32_t rawOffset;
+ UDate standardDate;
+ UDate daylightSavingDate;
+ tz->getOffset(date1, false, rawOffset, daylightOffset, status);
+ if (daylightOffset != 0) {
+ // The Timezone is reporting that we are in daylight time
+ // for the winter date. The dates are for the wrong hemisphere,
+ // swap them.
+ standardDate = date2;
+ daylightSavingDate = date1;
+ } else {
+ standardDate = date1;
+ daylightSavingDate = date2;
+ }
+
+ UnicodeString shortDayLight;
+ UnicodeString longDayLight;
+ UnicodeString shortStandard;
+ UnicodeString longStandard;
+
+ shortFormat.format(daylightSavingDate, shortDayLight);
+ content = getJStringFromUnicodeString(env, shortDayLight);
+ env->SetObjectArrayElement(shortDlTimeArray, i, content);
+ env->DeleteLocalRef(content);
+
+ shortFormat.format(standardDate, shortStandard);
+ content = getJStringFromUnicodeString(env, shortStandard);
+ env->SetObjectArrayElement(shortStdTimeArray, i, content);
+ env->DeleteLocalRef(content);
+
+ longFormat.format (daylightSavingDate, longDayLight);
+ content = getJStringFromUnicodeString(env, longDayLight);
+ env->SetObjectArrayElement(longDlTimeArray, i, content);
+ env->DeleteLocalRef(content);
+
+ longFormat.format (standardDate, longStandard);
+ content = getJStringFromUnicodeString(env, longStandard);
+ env->SetObjectArrayElement(longStdTimeArray, i, content);
+ env->DeleteLocalRef(content);
+ delete(tz);
+ }
+}
+
+
+
+
+static jstring getDisplayTimeZoneNative(JNIEnv* env, jclass clazz,
+ jstring zoneID, jboolean isDST, jint style, jstring localeID) {
+
+ // Build TimeZone object
+ const jchar* idChars = env->GetStringChars(zoneID, NULL);
+ jint idLength = env->GetStringLength(zoneID);
+ UnicodeString idString((UChar*)idChars, idLength);
+ TimeZone* zone = TimeZone::createTimeZone(idString);
+ env->ReleaseStringChars(zoneID, idChars);
+
+ // Build Locale object (can we rely on zero termination of JNI result?)
+ const char* localeChars = env->GetStringUTFChars(localeID, NULL);
+ jint localeLength = env->GetStringLength(localeID);
+ Locale locale = Locale::createFromName(localeChars);
+
+ // Try to get the display name of the TimeZone according to the Locale
+ UnicodeString buffer;
+ zone->getDisplayName((UBool)isDST, (style == 0 ? TimeZone::SHORT : TimeZone::LONG), locale, buffer);
+ const UChar* tempChars = buffer.getBuffer();
+ int tempLength = buffer.length();
+ jstring result = env->NewString((jchar*)tempChars, tempLength);
+ env->ReleaseStringUTFChars(localeID, localeChars);
+
+ // Clean up everything
+ delete(zone);
+
+ return result;
+}
+
+static void getDayInitVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ // get the First day of week and the minimal days in first week numbers
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "DateTimeElements", NULL, &status);
+ if(U_FAILURE(status)) {
+ return;
+ }
+
+ int intVectSize;
+ const int *result;
+ result = ures_getIntVector(gregorianElems, &intVectSize, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return;
+ }
+
+ if(intVectSize == 2) {
+ values[0] = result[0];
+ values[1] = result[1];
+ }
+
+ ures_close(gregorianElems);
+
+}
+
+static jobjectArray getAmPmMarkers(JNIEnv *env, UResourceBundle *gregorian) {
+
+ jobjectArray amPmMarkers;
+ jstring pmU, amU;
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UResourceBundle *gregorianElems;
+
+ gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ int lengthAm, lengthPm;
+
+ ures_resetIterator(gregorianElems);
+
+ const jchar* am = ures_getStringByIndex(gregorianElems, 0, &lengthAm, &status);
+ const jchar* pm = ures_getStringByIndex(gregorianElems, 1, &lengthPm, &status);
+
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ amPmMarkers = env->NewObjectArray(2, string_class, NULL);
+ amU = env->NewString(am, lengthAm);
+ env->SetObjectArrayElement(amPmMarkers, 0, amU);
+ env->DeleteLocalRef(amU);
+ pmU = env->NewString(pm, lengthPm);
+ env->SetObjectArrayElement(amPmMarkers, 1, pmU);
+ env->DeleteLocalRef(pmU);
+ ures_close(gregorianElems);
+
+ return amPmMarkers;
+}
+
+static jobjectArray getEras(JNIEnv* env, UResourceBundle *gregorian) {
+
+ jobjectArray eras;
+ jstring eraU;
+ const jchar* era;
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UResourceBundle *gregorianElems;
+ UResourceBundle *eraElems;
+
+ gregorianElems = ures_getByKey(gregorian, "eras", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ eraElems = ures_getByKey(gregorianElems, "abbreviated", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ int eraLength;
+
+ int eraCount = ures_getSize(eraElems);
+ eras = env->NewObjectArray(eraCount, string_class, NULL);
+
+ ures_resetIterator(eraElems);
+ for(int i = 0; i < eraCount; i++) {
+ era = ures_getStringByIndex(eraElems, i, &eraLength, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ ures_close(eraElems);
+ return NULL;
+ }
+ eraU = env->NewString(era, eraLength);
+ env->SetObjectArrayElement(eras, i, eraU);
+ env->DeleteLocalRef(eraU);
+ }
+ ures_close(eraElems);
+ ures_close(gregorianElems);
+
+ return eras;
+}
+
+static jobjectArray getMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const jchar* month;
+ jstring monthU;
+
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "wide", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ int monthNameLength;
+ ures_resetIterator(monthNameElemsFormat);
+ int monthCount = ures_getSize(monthNameElemsFormat);
+ jobjectArray months = env->NewObjectArray(monthCount + 1, string_class, NULL);
+ for(int i = 0; i < monthCount; i++) {
+ month = ures_getStringByIndex(monthNameElemsFormat, i, &monthNameLength, &status);
+ if(U_FAILURE(status)) {
+ ures_close(monthNameElemsFormat);
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+ monthU = env->NewString(month, monthNameLength);
+ env->SetObjectArrayElement(months, i, monthU);
+ env->DeleteLocalRef(monthU);
+ }
+
+ monthU = env->NewStringUTF("");
+ env->SetObjectArrayElement(months, monthCount, monthU);
+ env->DeleteLocalRef(monthU);
+
+ ures_close(monthNameElemsFormat);
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return months;
+}
+
+static jobjectArray getShortMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const jchar* shortMonth;
+ jstring shortMonthU;
+
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "abbreviated", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ int shortMonthNameLength;
+ ures_resetIterator(monthNameElemsFormat);
+ int shortMonthCount = ures_getSize(monthNameElemsFormat);
+ // the array length is +1 because the harmony locales had an empty string at the end of their month name array
+ jobjectArray shortMonths = env->NewObjectArray(shortMonthCount + 1, string_class, NULL);
+ for(int i = 0; i < shortMonthCount; i++) {
+ shortMonth = ures_getStringByIndex(monthNameElemsFormat, i, &shortMonthNameLength, &status);
+ if(U_FAILURE(status)) {
+ ures_close(monthNameElemsFormat);
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+ shortMonthU = env->NewString(shortMonth, shortMonthNameLength);
+ env->SetObjectArrayElement(shortMonths, i, shortMonthU);
+ env->DeleteLocalRef(shortMonthU);
+ }
+
+ shortMonthU = env->NewStringUTF("");
+ env->SetObjectArrayElement(shortMonths, shortMonthCount, shortMonthU);
+ env->DeleteLocalRef(shortMonthU);
+
+ ures_close(monthNameElemsFormat);
+ ures_close(monthNameElems);
+ ures_close(gregorianElems);
+ return shortMonths;
+}
+
+static jobjectArray getWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const jchar* day;
+ jstring dayU;
+
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "wide", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ int dayNameLength;
+ ures_resetIterator(dayNameElemsFormat);
+ int dayCount = ures_getSize(dayNameElemsFormat);
+ jobjectArray weekdays = env->NewObjectArray(dayCount + 1, string_class, NULL);
+ // first entry in the weekdays array is an empty string
+ env->SetObjectArrayElement(weekdays, 0, env->NewStringUTF(""));
+ for(int i = 0; i < dayCount; i++) {
+ day = ures_getStringByIndex(dayNameElemsFormat, i, &dayNameLength, &status);
+ if(U_FAILURE(status)) {
+ ures_close(dayNameElemsFormat);
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+ dayU = env->NewString(day, dayNameLength);
+ env->SetObjectArrayElement(weekdays, i + 1, dayU);
+ env->DeleteLocalRef(dayU);
+ }
+
+ ures_close(dayNameElemsFormat);
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return weekdays;
+
+}
+
+static jobjectArray getShortWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const jchar* shortDay;
+ jstring shortDayU;
+
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "abbreviated", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+
+ int shortDayNameLength;
+ ures_resetIterator(dayNameElemsFormat);
+ int shortDayCount = ures_getSize(dayNameElemsFormat);
+ jobjectArray shortWeekdays = env->NewObjectArray(shortDayCount + 1, string_class, NULL);
+ env->SetObjectArrayElement(shortWeekdays, 0, env->NewStringUTF(""));
+ for(int i = 0; i < shortDayCount; i++) {
+ shortDay = ures_getStringByIndex(dayNameElemsFormat, i, &shortDayNameLength, &status);
+ if(U_FAILURE(status)) {
+ ures_close(dayNameElemsFormat);
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return NULL;
+ }
+ shortDayU = env->NewString(shortDay, shortDayNameLength);
+ env->SetObjectArrayElement(shortWeekdays, i + 1, shortDayU);
+ env->DeleteLocalRef(shortDayU);
+ }
+
+ ures_close(dayNameElemsFormat);
+ ures_close(dayNameElems);
+ ures_close(gregorianElems);
+ return shortWeekdays;
+}
+
+static jstring getDecimalPatternChars(JNIEnv *env, UResourceBundle *rootElems) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ int zeroL, digitL, decSepL, groupL, listL, percentL, permillL, expL, currSepL, minusL;
+ int patternLength;
+
+ jchar *patternChars;
+
+ const jchar* zero = ures_getStringByIndex(rootElems, 4, &zeroL, &status);
+
+ const jchar* digit = ures_getStringByIndex(rootElems, 5, &digitL, &status);
+
+ const jchar* decSep = ures_getStringByIndex(rootElems, 0, &decSepL, &status);
+
+ const jchar* group = ures_getStringByIndex(rootElems, 1, &groupL, &status);
+
+ const jchar* list = ures_getStringByIndex(rootElems, 2, &listL, &status);
+
+ const jchar* percent = ures_getStringByIndex(rootElems, 3, &percentL, &status);
+
+ const jchar* permill = ures_getStringByIndex(rootElems, 8, &permillL, &status);
+
+ const jchar* exp = ures_getStringByIndex(rootElems, 7, &expL, &status);
+
+ const jchar* currSep = ures_getStringByIndex(rootElems, 0, &currSepL, &status);
+
+ const jchar* minus = ures_getStringByIndex(rootElems, 6, &minusL, &status);
+
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+
+ patternChars = (jchar *) malloc(11 * sizeof(jchar));
+
+ patternChars[0] = 0;
+
+ u_strncat(patternChars, zero, 1);
+ u_strncat(patternChars, digit, 1);
+ u_strncat(patternChars, decSep, 1);
+ u_strncat(patternChars, group, 1);
+ u_strncat(patternChars, list, 1);
+ u_strncat(patternChars, percent, 1);
+ u_strncat(patternChars, permill, 1);
+ u_strncat(patternChars, exp, 1);
+ u_strncat(patternChars, currSep, 1);
+ u_strncat(patternChars, minus, 1);
+
+ jstring decimalPatternChars = env->NewString(patternChars, 10);
+
+ free(patternChars);
+
+ return decimalPatternChars;
+}
+
+static jstring getIntCurrencyCode(JNIEnv *env, jclass clazz, jstring locale) {
+
+ const char *locStr = env->GetStringUTFChars(locale, NULL);
+ char country[3] = {0,0,0};
+
+ // getting the 2 character country name
+ if(strlen(locStr) < 5) {
+ env->ReleaseStringUTFChars(locale, locStr);
+ return NULL;
+ }
+ if(locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
+ env->ReleaseStringUTFChars(locale, locStr);
+ return NULL;
+ }
+ country[0] = locStr[3];
+ country[1] = locStr[4];
+
+ env->ReleaseStringUTFChars(locale, locStr);
+
+ return getCurrencyCodeNative(env, clazz, env->NewStringUTF(country));
+}
+
+static jstring getCurrencySymbol(JNIEnv *env, jclass clazz, jstring locale, jstring intCurrencySymbol) {
+
+ jstring result = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
+ if(result == intCurrencySymbol) {
+ return NULL;
+ }
+ return result;
+
+}
+
+static jobjectArray getContentImpl(JNIEnv* env, jclass clazz,
+ jstring locale, jboolean needsTZ) {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *loc = env->GetStringUTFChars(locale, NULL);
+ UResourceBundle *root = ures_openU(NULL, loc, &status);
+
+ env->ReleaseStringUTFChars(locale, loc);
+ if(U_FAILURE(status)) {
+ LOGI("Error getting resources");
+ status = U_ZERO_ERROR;
+ return NULL;
+ }
+
+
+
+ jclass obj_class = env->FindClass("java/lang/Object");
+ jclass integer_class = env->FindClass("java/lang/Integer");
+ jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
+ jobjectArray result;
+
+ jobject firstDayOfWeek = NULL;
+ jobject minimalDaysInFirstWeek = NULL;
+ jobjectArray amPmMarkers = NULL;
+ jobjectArray eras = NULL;
+ jstring localPatternChars = NULL;
+ jobjectArray weekdays = NULL;
+ jobjectArray shortWeekdays = NULL;
+ jobjectArray months = NULL;
+ jobjectArray shortMonths = NULL;
+ jstring time_SHORT = NULL;
+ jstring time_MEDIUM = NULL;
+ jstring time_LONG = NULL;
+ jstring time_FULL = NULL;
+ jstring date_SHORT = NULL;
+ jstring date_MEDIUM = NULL;
+ jstring date_LONG = NULL;
+ jstring date_FULL = NULL;
+ jstring decimalPatternChars = NULL;
+ jstring naN = NULL;
+ jstring infinity = NULL;
+ jstring currencySymbol = NULL;
+ jstring intCurrencySymbol = NULL;
+ jstring numberPattern = NULL;
+ jstring integerPattern = NULL;
+ jstring currencyPattern = NULL;
+ jstring percentPattern = NULL;
+ jobjectArray zones = NULL;
+
+ int counter = 0;
+
+ int firstDayVals[2] = {-1, -1};
+
+ const jchar* nan = (const jchar *)NULL;
+ const jchar* inf = (const jchar *)NULL;
+ int nanL, infL;
+
+
+ UResourceBundle *gregorian;
+ UResourceBundle *gregorianElems;
+ UResourceBundle *rootElems;
+
+
+
+
+ // get the resources needed
+ rootElems = ures_getByKey(root, "calendar", NULL, &status);
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ gregorian = ures_getByKey(rootElems, "gregorian", NULL, &status);
+ if(U_FAILURE(status)) {
+ ures_close(rootElems);
+ return NULL;
+ }
+
+
+
+ // adding the first day of week and minimal days in first week values
+ getDayInitVector(env, gregorian, firstDayVals);
+ if((firstDayVals[0] != -1) && (firstDayVals[1] != -1)) {
+ firstDayOfWeek = env->NewObject(integer_class, integerInit, firstDayVals[0]);
+ minimalDaysInFirstWeek = env->NewObject(integer_class, integerInit, firstDayVals[1]);
+ // adding First_Day and Minimal_Days integer to the result
+ counter += 2;
+ }
+
+
+ // adding ampm string array to the result");
+ amPmMarkers = getAmPmMarkers(env, gregorian);
+ if(amPmMarkers != NULL) {
+ counter++;
+ }
+
+
+ // adding eras string array to the result
+ eras = getEras(env, gregorian);
+ if(eras != NULL) {
+ counter++;
+ }
+
+
+ // local pattern chars are initially always the same
+ localPatternChars = env->NewStringUTF("GyMdkHmsSEDFwWahKzZ");
+ // adding local pattern chars string to the result
+ counter++;
+
+
+ // adding month names string array to the result
+ months = getMonthNames(env, gregorian);
+ if(months != NULL) {
+ counter++;
+ }
+
+
+ // adding short month names string array to the result
+ shortMonths = getShortMonthNames(env, gregorian);
+ if(shortMonths != NULL) {
+ counter++;
+ }
+
+
+ // adding day names string array to the result
+ weekdays = getWeekdayNames(env, gregorian);
+ if(weekdays != NULL) {
+ counter++;
+ }
+
+
+ // adding short day names string array to the result
+ shortWeekdays = getShortWeekdayNames(env, gregorian);
+ if(shortWeekdays != NULL) {
+ counter++;
+ }
+
+ const UChar *pattern;
+ jchar check[2] = {0, 0};
+ u_uastrcpy(check, "v");
+ jchar replacement[2] = {0, 0};
+ u_uastrcpy(replacement, "z");
+ jchar *pos;
+ jchar *patternCopy;
+ int patternLength;
+
+ // adding date and time format patterns to the result
+ gregorianElems = ures_getByKey(gregorian, "DateTimePatterns", NULL, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+
+ pattern = ures_getStringByIndex(gregorianElems, 0, &patternLength, &status);
+ // there are some patterns in icu that use the pattern character 'v'
+ // java doesn't accept this, so it gets replaced by 'z' which has
+ // about the same result as 'v', the timezone name.
+ // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
+ // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
+ patternCopy = (jchar *) malloc((patternLength + 1) * sizeof(jchar));
+ u_strcpy(patternCopy, pattern);
+ if(U_FAILURE(status)) {
+ free(patternCopy);
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ while((pos = u_strchr(patternCopy, check[0])) != NULL) {
+ u_memset(pos, replacement[0], 1);
+ }
+ time_FULL = env->NewString(patternCopy, patternLength);
+ free(patternCopy);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 1, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ time_LONG = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 2, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ time_MEDIUM = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 3, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ time_SHORT = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 4, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ date_FULL = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 5, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ date_LONG = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 6, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ date_MEDIUM = env->NewString(pattern, patternLength);
+ counter++;
+
+ pattern = ures_getStringByIndex(gregorianElems, 7, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto endOfCalendar;
+ }
+ date_SHORT = env->NewString(pattern, patternLength);
+ counter++;
+
+
+endOfCalendar:
+
+ if(gregorianElems != NULL) {
+ ures_close(gregorianElems);
+ }
+ ures_close(gregorian);
+ ures_close(rootElems);
+
+
+ rootElems = ures_getByKey(root, "NumberElements", NULL, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ }
+
+ if(ures_getSize(rootElems) >= 11) {
+
+ // adding decimal pattern chars to the result
+ decimalPatternChars = getDecimalPatternChars(env, rootElems);
+ if(decimalPatternChars != NULL) {
+ counter++;
+ }
+
+ // adding NaN pattern char to the result
+ nan = ures_getStringByIndex(rootElems, 10, &nanL, &status);
+ if(U_SUCCESS(status)) {
+ naN = env->NewString(nan, nanL);
+ counter++;
+ }
+ status = U_ZERO_ERROR;
+
+ // adding infinity pattern char to the result
+ inf = ures_getStringByIndex(rootElems, 9, &infL, &status);
+ if(U_SUCCESS(status)) {
+ infinity = env->NewString(inf, infL);
+ counter++;
+ }
+ status = U_ZERO_ERROR;
+ }
+
+ ures_close(rootElems);
+
+
+ // adding intl currency code to result
+ intCurrencySymbol = getIntCurrencyCode(env, clazz, locale);
+ if(intCurrencySymbol != NULL) {
+ // adding currency symbol to result
+ currencySymbol = getCurrencySymbol(env, clazz, locale, intCurrencySymbol);
+ } else {
+ intCurrencySymbol = env->NewStringUTF("XXX");
+ }
+ if(currencySymbol == NULL) {
+ currencySymbol = env->NewStringUTF("\u00a4");
+ }
+ counter += 2;
+
+
+ // adding number format patterns to the result
+ int numOfEntries;
+ int decSepOffset;
+ NumberFormat *nf;
+ jchar *tmpPattern;
+
+ rootElems = ures_getByKey(root, "NumberPatterns", NULL, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ goto zones;
+ }
+
+ numOfEntries = ures_getSize(rootElems);
+ if(numOfEntries < 3) {
+ ures_close(rootElems);
+ goto zones;
+ }
+
+ // number pattern
+ pattern = ures_getStringByIndex(rootElems, 0, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ ures_close(rootElems);
+ goto zones;
+ }
+ numberPattern = env->NewString(pattern, patternLength);
+ counter++;
+
+ // integer pattern derived from number pattern
+ // We need to convert a C string literal to a UChar string for u_strcspn.
+ static const char c_decSep[] = ".";
+ UChar decSep[sizeof(c_decSep)];
+ u_charsToUChars(c_decSep, decSep, sizeof(c_decSep));
+ decSepOffset = u_strcspn(pattern, decSep);
+ tmpPattern = (jchar *) malloc((decSepOffset + 1) * sizeof(jchar));
+ u_strncpy(tmpPattern, pattern, decSepOffset);
+ integerPattern = env->NewString(tmpPattern, decSepOffset);
+ free(tmpPattern);
+ counter++;
+
+ // currency pattern
+ pattern = ures_getStringByIndex(rootElems, 1, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ ures_close(rootElems);
+ goto zones;
+ }
+ currencyPattern = env->NewString(pattern, patternLength);
+ counter++;
+
+ // percent pattern
+ pattern = ures_getStringByIndex(rootElems, 2, &patternLength, &status);
+ if(U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ ures_close(rootElems);
+ goto zones;
+ }
+ percentPattern = env->NewString(pattern, patternLength);
+ counter++;
+
+ ures_close(rootElems);
+
+zones:
+
+ ures_close(root);
+
+
+ if(needsTZ == JNI_TRUE) {
+ counter++; //add empty timezone
+ }
+
+
+
+ // collect all content and put it into an array
+ result = env->NewObjectArray(counter, obj_class, NULL);
+
+ int index = 0;
+
+ if(needsTZ == JNI_TRUE) {
+ addObject(env, result, "timezones", NULL, index++);
+ }
+ if(firstDayOfWeek != NULL && index < counter) {
+ addObject(env, result, "First_Day", firstDayOfWeek, index++);
+ }
+ if(minimalDaysInFirstWeek != NULL && index < counter) {
+ addObject(env, result, "Minimal_Days", minimalDaysInFirstWeek, index++);
+ }
+ if(amPmMarkers != NULL && index < counter) {
+ addObject(env, result, "ampm", amPmMarkers, index++);
+ }
+ if(eras != NULL && index < counter) {
+ addObject(env, result, "eras", eras, index++);
+ }
+ if(localPatternChars != NULL && index < counter) {
+ addObject(env, result, "LocalPatternChars", localPatternChars, index++);
+ }
+ if(weekdays != NULL && index < counter) {
+ addObject(env, result, "weekdays", weekdays, index++);
+ }
+ if(shortWeekdays != NULL && index < counter) {
+ addObject(env, result, "shortWeekdays", shortWeekdays, index++);
+ }
+ if(months != NULL && index < counter) {
+ addObject(env, result, "months", months, index++);
+ }
+ if(shortMonths != NULL && index < counter) {
+ addObject(env, result, "shortMonths", shortMonths, index++);
+ }
+ if(time_SHORT != NULL && index < counter) {
+ addObject(env, result, "Time_SHORT", time_SHORT, index++);
+ }
+ if(time_MEDIUM != NULL && index < counter) {
+ addObject(env, result, "Time_MEDIUM", time_MEDIUM, index++);
+ }
+ if(time_LONG != NULL && index < counter) {
+ addObject(env, result, "Time_LONG", time_LONG, index++);
+ }
+ if(time_FULL != NULL && index < counter) {
+ addObject(env, result, "Time_FULL", time_FULL, index++);
+ }
+ if(date_SHORT != NULL && index < counter) {
+ addObject(env, result, "Date_SHORT", date_SHORT, index++);
+ }
+ if(date_MEDIUM != NULL && index < counter) {
+ addObject(env, result, "Date_MEDIUM", date_MEDIUM, index++);
+ }
+ if(date_LONG != NULL && index < counter) {
+ addObject(env, result, "Date_LONG", date_LONG, index++);
+ }
+ if(date_FULL != NULL && index < counter) {
+ addObject(env, result, "Date_FULL", date_FULL, index++);
+ }
+ if(decimalPatternChars != NULL && index < counter) {
+ addObject(env, result, "DecimalPatternChars", decimalPatternChars, index++);
+ }
+ if(naN != NULL && index < counter) {
+ addObject(env, result, "NaN", naN, index++);
+ }
+ if(infinity != NULL && index < counter) {
+ addObject(env, result, "Infinity", infinity, index++);
+ }
+ if(currencySymbol != NULL && index < counter) {
+ addObject(env, result, "CurrencySymbol", currencySymbol, index++);
+ }
+ if(intCurrencySymbol != NULL && index < counter) {
+ addObject(env, result, "IntCurrencySymbol", intCurrencySymbol, index++);
+ }
+ if(numberPattern != NULL && index < counter) {
+ addObject(env, result, "Number", numberPattern, index++);
+ }
+ if(integerPattern != NULL && index < counter) {
+ addObject(env, result, "Integer", integerPattern, index++);
+ }
+ if(currencyPattern != NULL && index < counter) {
+ addObject(env, result, "Currency", currencyPattern, index++);
+ }
+ if(percentPattern != NULL && index < counter) {
+ addObject(env, result, "Percent", percentPattern, index++);
+ }
+
+ return result;
+
+}
+
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"getFractionDigitsNative", "(Ljava/lang/String;)I",
+ (void*) getFractionDigitsNative},
+ {"getCurrencyCodeNative", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getCurrencyCodeNative},
+ {"getCurrencySymbolNative", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getCurrencySymbolNative},
+ {"getDisplayCountryNative",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getDisplayCountryNative},
+ {"getDisplayLanguageNative",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getDisplayLanguageNative},
+ {"getDisplayVariantNative",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getDisplayVariantNative},
+ {"getISO3CountryNative",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getISO3CountryNative},
+ {"getISO3LanguageNative",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) getISO3LanguageNative},
+ {"getISOCountriesNative", "()[Ljava/lang/String;",
+ (void*) getISOCountriesNative},
+ {"getISOLanguagesNative", "()[Ljava/lang/String;",
+ (void*) getISOLanguagesNative},
+ {"getAvailableLocalesNative", "()[Ljava/lang/String;",
+ (void*) getAvailableLocalesNative},
+ {"getTimeZonesNative",
+ "([[Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) getTimeZonesNative},
+ {"getDisplayTimeZoneNative",
+ "(Ljava/lang/String;ZILjava/lang/String;)Ljava/lang/String;",
+ (void*) getDisplayTimeZoneNative},
+ {"getContentImpl",
+ "(Ljava/lang/String;Z)[[Ljava/lang/Object;",
+ (void*) getContentImpl},
+};
+
+int register_com_ibm_icu4jni_util_Resources(JNIEnv* env) {
+
+ // initializing String
+
+ jclass stringclass = env->FindClass("java/lang/String");
+
+ if(stringclass == NULL) {
+ LOGE("Can't find java/lang/String");
+ jniThrowException(env, "java/lang/ClassNotFoundException", "java.lang.String");
+ return -1;
+ }
+
+ string_class = (jclass) env->NewGlobalRef(stringclass);
+
+ return jniRegisterNativeMethods(env,
+ "com/ibm/icu4jni/util/Resources", gMethods,
+ NELEM(gMethods));
+}
diff --git a/icu/src/main/native/sub.mk b/icu/src/main/native/sub.mk
new file mode 100644
index 0000000..2f160f5
--- /dev/null
+++ b/icu/src/main/native/sub.mk
@@ -0,0 +1,30 @@
+# This file is included by the top-level libcore Android.mk.
+# It's not a normal makefile, so we don't include CLEAR_VARS
+# or BUILD_*_LIBRARY.
+
+LOCAL_SRC_FILES := \
+ BidiWrapperInterface.c \
+ BreakIteratorInterface.c \
+ DecimalFormatInterface.cpp \
+ CharacterInterface.c \
+ ConverterInterface.c \
+ CollationInterface.c \
+ RegExInterface.cpp \
+ ResourceInterface.cpp \
+ RBNFInterface.cpp \
+ ErrorCode.c
+
+LOCAL_C_INCLUDES += \
+ external/icu4c/common \
+ external/icu4c/i18n
+
+# Any shared/static libs that are listed here must also
+# be listed in libs/nativehelper/Android.mk.
+# TODO: fix this requirement
+
+LOCAL_SHARED_LIBRARIES += \
+ libicudata \
+ libicuuc \
+ libicui18n
+
+LOCAL_STATIC_LIBRARIES +=