summaryrefslogtreecommitdiffstats
path: root/icu/src
diff options
context:
space:
mode:
Diffstat (limited to 'icu/src')
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java342
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java408
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java129
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java118
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/NativeConverter.java422
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java205
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java295
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java34
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java130
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java133
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java214
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java230
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java186
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/Collator.java431
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java568
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java295
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java68
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java263
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java109
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java133
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java719
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java258
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/util/Resources.java533
-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
38 files changed, 12702 insertions, 0 deletions
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
new file mode 100644
index 0000000..3b9bf86
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
@@ -0,0 +1,342 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+ /**
+ * A JNI interface for ICU converters.
+ *
+ *
+ * @author Ram Viswanadha, IBM
+ */
+package com.ibm.icu4jni.charset;
+
+import com.ibm.icu4jni.common.ErrorCode;
+// BEGIN android-removed
+// import com.ibm.icu4jni.converters.NativeConverter;
+// END android-removed
+
+
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.ByteBuffer;
+
+public final class CharsetDecoderICU extends CharsetDecoder{
+
+
+ private static final int INPUT_OFFSET = 0,
+ OUTPUT_OFFSET = 1,
+ INVALID_BYTES = 2,
+ INPUT_HELD = 3,
+ LIMIT = 4;
+ /* data is 3 element array where
+ * data[INPUT_OFFSET] = on input contains the start of input and on output the number of input chars consumed
+ * data[OUTPUT_OFFSET] = on input contains the start of output and on output the number of output bytes written
+ * data[INVALID_CHARS] = number of invalid chars
+ * data[INPUT_HELD] = number of input chars held in the converter's state
+ */
+ private int[] data = new int[LIMIT];
+
+ /* handle to the ICU converter that is opened */
+ private long converterHandle=0;
+
+
+ private byte[] input = null;
+ private char[] output= null;
+
+ // These instance variables are
+ // always assigned in the methods
+ // before being used. This class
+ // inhrently multithread unsafe
+ // so we dont have to worry about
+ // synchronization
+ private int inEnd;
+ private int outEnd;
+ private int ec;
+ private int onUnmappableInput = NativeConverter.STOP_CALLBACK;;
+ private int onMalformedInput = NativeConverter.STOP_CALLBACK;;
+ private int savedInputHeldLen;
+
+ /**
+ * Constructs a new decoder for the given charset
+ * @param cs for which the decoder is created
+ * @param cHandle the address of ICU converter
+ * @exception RuntimeException
+ * @stable ICU 2.4
+ */
+ public CharsetDecoderICU(Charset cs,long cHandle){
+ super(cs,
+ NativeConverter.getAveCharsPerByte(cHandle),
+ NativeConverter.getMaxCharsPerByte(cHandle)
+ );
+
+ char[] sub = replacement().toCharArray();
+ ec = NativeConverter.setCallbackDecode(cHandle,
+ onMalformedInput,
+ onUnmappableInput,
+ sub, sub.length);
+ if(ErrorCode.isFailure(ec)){
+ throw ErrorCode.getException(ec);
+ }
+ // store the converter handle
+ converterHandle=cHandle;
+
+ }
+
+ /**
+ * Sets this decoders replacement string. Substitutes the string in input if an
+ * umappable or illegal sequence is encountered
+ * @param newReplacement to replace the error bytes with
+ * @stable ICU 2.4
+ */
+ protected void implReplaceWith(String newReplacement) {
+ if(converterHandle > 0){
+ if( newReplacement.length() > NativeConverter.getMaxBytesPerChar(converterHandle)) {
+ throw new IllegalArgumentException();
+ }
+ ec =NativeConverter.setSubstitutionChars(converterHandle,
+ newReplacement.toCharArray(),
+ newReplacement.length()
+ );
+ if(ErrorCode.isFailure(ec)){
+ throw ErrorCode.getException(ec);
+ }
+ }
+ }
+
+ /**
+ * Sets the action to be taken if an illegal sequence is encountered
+ * @param newAction action to be taken
+ * @exception IllegalArgumentException
+ * @stable ICU 2.4
+ */
+ protected final void implOnMalformedInput(CodingErrorAction newAction) {
+ if(newAction.equals(CodingErrorAction.IGNORE)){
+ onMalformedInput = NativeConverter.SKIP_CALLBACK;
+ }else if(newAction.equals(CodingErrorAction.REPLACE)){
+ onMalformedInput = NativeConverter.SUBSTITUTE_CALLBACK;
+ }else if(newAction.equals(CodingErrorAction.REPORT)){
+ onMalformedInput = NativeConverter.STOP_CALLBACK;
+ }
+ char[] sub = replacement().toCharArray();
+ //System.out.println(" setting callbacks mfi " + onMalformedInput +" umi " + onUnmappableInput);
+ ec = NativeConverter.setCallbackDecode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+ if(ErrorCode.isFailure(ec)){
+ throw ErrorCode.getException(ec);
+ }
+ }
+
+ /**
+ * Sets the action to be taken if an illegal sequence is encountered
+ * @param newAction action to be taken
+ * @exception IllegalArgumentException
+ * @stable ICU 2.4
+ */
+ protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
+ if(newAction.equals(CodingErrorAction.IGNORE)){
+ onUnmappableInput = NativeConverter.SKIP_CALLBACK;
+ }else if(newAction.equals(CodingErrorAction.REPLACE)){
+ onUnmappableInput = NativeConverter.SUBSTITUTE_CALLBACK;
+ }else if(newAction.equals(CodingErrorAction.REPORT)){
+ onUnmappableInput = NativeConverter.STOP_CALLBACK;
+ }
+ char[] sub = replacement().toCharArray();
+ ec = NativeConverter.setCallbackDecode(converterHandle,onMalformedInput, onUnmappableInput, sub, sub.length);
+ if(ErrorCode.isFailure(ec)){
+ throw ErrorCode.getException(ec);
+ }
+ }
+
+ /**
+ * Flushes any characters saved in the converter's internal buffer and
+ * resets the converter.
+ * @param out action to be taken
+ * @return result of flushing action and completes the decoding all input.
+ * Returns CoderResult.UNDERFLOW if the action succeeds.
+ * @stable ICU 2.4
+ */
+ protected final CoderResult implFlush(CharBuffer out) {
+ try{
+
+ data[OUTPUT_OFFSET] = getArray(out);
+
+ ec=NativeConverter.flushByteToChar(
+ converterHandle, /* Handle to ICU Converter */
+ output, /* input array of chars */
+ outEnd, /* input index+1 to be written */
+ data /* contains data, inOff,outOff */
+ );
+
+
+ /* If we don't have room for the output, throw an exception*/
+ if (ErrorCode.isFailure(ec)) {
+ if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+ return CoderResult.OVERFLOW;
+ }else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND ) {//CSDL: add this truncated character error handling
+ if(data[INPUT_OFFSET]>0){
+ return CoderResult.malformedForLength(data[INPUT_OFFSET]);
+ }
+ }else {
+ ErrorCode.getException(ec);
+ }
+ }
+ return CoderResult.UNDERFLOW;
+ }finally{
+ /* save the flushed data */
+ setPosition(out);
+ implReset();
+ }
+ }
+
+ /**
+ * Resets the to Unicode mode of converter
+ * @stable ICU 2.4
+ */
+ protected void implReset() {
+ NativeConverter.resetByteToChar(converterHandle);
+ data[INPUT_OFFSET] = 0;
+ data[OUTPUT_OFFSET] = 0;
+ data[INVALID_BYTES] = 0;
+ data[INPUT_HELD] = 0;
+ savedInputHeldLen = 0;
+ output = null;
+ input = null;
+ }
+
+ /**
+ * Decodes one or more bytes. The default behaviour of the converter
+ * is stop and report if an error in input stream is encountered.
+ * To set different behaviour use @see CharsetDecoder.onMalformedInput()
+ * This method allows a buffer by buffer conversion of a data stream.
+ * The state of the conversion is saved between calls to convert.
+ * Among other things, this means multibyte input sequences can be
+ * split between calls. If a call to convert results in an Error, the
+ * conversion may be continued by calling convert again with suitably
+ * modified parameters.All conversions should be finished with a call to
+ * the flush method.
+ * @param in buffer to decode
+ * @param out buffer to populate with decoded result
+ * @return result of decoding action. Returns CoderResult.UNDERFLOW if the decoding
+ * action succeeds or more input is needed for completing the decoding action.
+ * @stable ICU 2.4
+ */
+ protected CoderResult decodeLoop(ByteBuffer in,CharBuffer out){
+
+ if(!in.hasRemaining()){
+ return CoderResult.UNDERFLOW;
+ }
+
+ data[INPUT_OFFSET] = getArray(in);
+ data[OUTPUT_OFFSET]= getArray(out);
+ data[INPUT_HELD] = 0;
+
+ try{
+ /* do the conversion */
+ ec=NativeConverter.decode(
+ converterHandle, /* Handle to ICU Converter */
+ input, /* input array of bytes */
+ inEnd, /* last index+1 to be converted */
+ output, /* input array of chars */
+ outEnd, /* input index+1 to be written */
+ data, /* contains data, inOff,outOff */
+ false /* donot flush the data */
+ );
+
+
+ /* return an error*/
+ if(ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR){
+ return CoderResult.OVERFLOW;
+ }else if(ec==ErrorCode.U_INVALID_CHAR_FOUND){
+ return CoderResult.malformedForLength(data[INVALID_BYTES]);
+ }else if(ec==ErrorCode.U_ILLEGAL_CHAR_FOUND){
+ return CoderResult.malformedForLength(data[INVALID_BYTES]);
+ }
+ /* decoding action succeded */
+ return CoderResult.UNDERFLOW;
+ }finally{
+ setPosition(in);
+ setPosition(out);
+ }
+ }
+
+ /**
+ * Releases the system resources by cleanly closing ICU converter opened
+ * @stable ICU 2.4
+ */
+ protected void finalize()throws Throwable{
+ NativeConverter.closeConverter(converterHandle);
+ super.finalize();
+ converterHandle = 0;
+ }
+
+ //------------------------------------------
+ // private utility methods
+ //------------------------------------------
+
+ private final int getArray(CharBuffer out){
+ if(out.hasArray()){
+ output = out.array();
+ outEnd = out.limit();
+ return out.position();
+ }else{
+ outEnd = out.remaining();
+ if(output==null || (outEnd > output.length)){
+ output = new char[outEnd];
+ }
+ //since the new
+ // buffer start position
+ // is 0
+ return 0;
+ }
+
+ }
+ private final int getArray(ByteBuffer in){
+ if(in.hasArray()){
+ input = in.array();
+ inEnd = in.limit();
+ return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ }else{
+ inEnd = in.remaining();
+ if(input==null|| (inEnd > input.length)){
+ input = new byte[inEnd];
+ }
+ // save the current position
+ int pos = in.position();
+ in.get(input,0,inEnd);
+ // reset the position
+ in.position(pos);
+ // the start position
+ // of the new buffer
+ // is whatever is savedInputLen
+ return savedInputHeldLen;
+ }
+
+ }
+ private final void setPosition(CharBuffer out){
+ if(out.hasArray()){
+ out.position(out.position() + data[OUTPUT_OFFSET]);
+ }else{
+ out.put(output,0,data[OUTPUT_OFFSET]);
+ }
+ }
+ private final void setPosition(ByteBuffer in){
+
+ // ok was there input held in the previous invocation of decodeLoop
+ // that resulted in output in this invocation?
+ if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen >0){
+ int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+ in.position(len);
+ savedInputHeldLen = data[INPUT_HELD];
+ }else{
+ in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen);
+ savedInputHeldLen = data[INPUT_HELD];
+ in.position(in.position() - savedInputHeldLen);
+ }
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
new file mode 100644
index 0000000..0fdb2c5
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
@@ -0,0 +1,408 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+/**
+ * A JNI interface for ICU converters.
+ *
+ *
+ * @author Ram Viswanadha, IBM
+ */
+package com.ibm.icu4jni.charset;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+import com.ibm.icu4jni.common.ErrorCode;
+// BEGIN android-removed
+// import com.ibm.icu4jni.converters.NativeConverter;
+// END android-removed
+
+public final class CharsetEncoderICU extends CharsetEncoder {
+
+ private static final int INPUT_OFFSET = 0,
+ OUTPUT_OFFSET = 1,
+ INVALID_CHARS = 2,
+ INPUT_HELD = 3,
+ LIMIT = 4;
+ /* data is 3 element array where
+ * data[INPUT_OFFSET] = on input contains the start of input and on output the number of input chars consumed
+ * data[OUTPUT_OFFSET] = on input contains the start of output and on output the number of output bytes written
+ * data[INVALID_CHARS] = number of invalid chars
+ * data[INPUT_HELD] = number of input chars held in the converter's state
+ */
+ private int[] data = new int[LIMIT];
+ /* handle to the ICU converter that is opened */
+ private long converterHandle=0;
+
+ private char[] input = null;
+ private byte[] output = null;
+
+ // These instance variables are
+ // always assigned in the methods
+ // before being used. This class
+ // inhrently multithread unsafe
+ // so we dont have to worry about
+ // synchronization
+ private int inEnd;
+ private int outEnd;
+ private int ec;
+ private int savedInputHeldLen;
+ private int onUnmappableInput = NativeConverter.STOP_CALLBACK;;
+ private int onMalformedInput = NativeConverter.STOP_CALLBACK;;
+
+ /**
+ * Construcs a new encoder for the given charset
+ * @param cs for which the decoder is created
+ * @param cHandle the address of ICU converter
+ * @param replacement the substitution bytes
+ * @stable ICU 2.4
+ */
+ public CharsetEncoderICU(Charset cs, long cHandle, byte[] replacement) {
+ super(
+ cs,
+ (float) NativeConverter.getAveBytesPerChar(cHandle),
+ (float) NativeConverter.getMaxBytesPerChar(cHandle),
+ replacement);
+ byte[] sub = replacement();
+ // The default callback action on unmappable input
+ // or malformed input is to ignore so we set ICU converter
+ // callback to stop and report the error
+ ec = NativeConverter.setCallbackEncode( cHandle,
+ onMalformedInput,
+ onUnmappableInput,
+ sub, sub.length);
+ converterHandle = cHandle;
+ if (ErrorCode.isFailure(ec)) {
+ throw ErrorCode.getException(ec);
+ }
+ }
+
+ /**
+ * Sets this encoders replacement string. Substitutes the string in output if an
+ * umappable or illegal sequence is encountered
+ * @param newReplacement to replace the error chars with
+ * @stable ICU 2.4
+ */
+ protected void implReplaceWith(byte[] newReplacement) {
+ if (converterHandle != 0) {
+ if (newReplacement.length
+ > NativeConverter.getMaxBytesPerChar(converterHandle)) {
+ throw new IllegalArgumentException("Number of replacement Bytes are greater than max bytes per char");
+ }
+ ec = NativeConverter.setSubstitutionBytes(converterHandle,
+ newReplacement,
+ newReplacement.length);
+ if (ErrorCode.isFailure(ec)) {
+ throw ErrorCode.getException(ec);
+ }
+ }
+ }
+
+ /**
+ * Sets the action to be taken if an illegal sequence is encountered
+ * @param newAction action to be taken
+ * @exception IllegalArgumentException
+ * @stable ICU 2.4
+ */
+ protected void implOnMalformedInput(CodingErrorAction newAction) {
+ onMalformedInput = NativeConverter.STOP_CALLBACK;
+
+ if (newAction.equals(CodingErrorAction.IGNORE)) {
+ onMalformedInput = NativeConverter.SKIP_CALLBACK;
+ } else if (newAction.equals(CodingErrorAction.REPLACE)) {
+ onMalformedInput = NativeConverter.SUBSTITUTE_CALLBACK;
+ }
+ byte[] sub = replacement();
+ ec = NativeConverter.setCallbackEncode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+ if (ErrorCode.isFailure(ec)) {
+ throw ErrorCode.getException(ec);
+ }
+
+ }
+
+ /**
+ * Sets the action to be taken if an illegal sequence is encountered
+ * @param newAction action to be taken
+ * @exception IllegalArgumentException
+ * @stable ICU 2.4
+ */
+ protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
+ onUnmappableInput = NativeConverter.STOP_CALLBACK;
+
+ if (newAction.equals(CodingErrorAction.IGNORE)) {
+ onUnmappableInput = NativeConverter.SKIP_CALLBACK;
+ } else if (newAction.equals(CodingErrorAction.REPLACE)) {
+ onUnmappableInput = NativeConverter.SUBSTITUTE_CALLBACK;
+ }
+ byte[] sub = replacement();
+ ec = NativeConverter.setCallbackEncode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+ if (ErrorCode.isFailure(ec)) {
+ throw ErrorCode.getException(ec);
+ }
+ }
+
+ /**
+ * Flushes any characters saved in the converter's internal buffer and
+ * resets the converter.
+ * @param out action to be taken
+ * @return result of flushing action and completes the decoding all input.
+ * Returns CoderResult.UNDERFLOW if the action succeeds.
+ * @stable ICU 2.4
+ */
+ protected CoderResult implFlush(ByteBuffer out) {
+ try {
+ data[OUTPUT_OFFSET] = getArray(out);
+ ec = NativeConverter.flushCharToByte(converterHandle,/* Handle to ICU Converter */
+ output, /* output array of chars */
+ outEnd, /* output index+1 to be written */
+ data /* contains data, inOff,outOff */
+ );
+
+ /* If we don't have room for the output, throw an exception*/
+ if (ErrorCode.isFailure(ec)) {
+ if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+ return CoderResult.OVERFLOW;
+ }else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND) {//CSDL: add this truncated character error handling
+ if(data[INPUT_OFFSET]>0){
+ return CoderResult.malformedForLength(data[INPUT_OFFSET]);
+ }
+ }else {
+ ErrorCode.getException(ec);
+ }
+ }
+ return CoderResult.UNDERFLOW;
+ } finally {
+ setPosition(out);
+ implReset();
+ }
+ }
+
+ /**
+ * Resets the from Unicode mode of converter
+ * @stable ICU 2.4
+ */
+ protected void implReset() {
+ NativeConverter.resetCharToByte(converterHandle);
+ data[INPUT_OFFSET] = 0;
+ data[OUTPUT_OFFSET] = 0;
+ data[INVALID_CHARS] = 0;
+ data[INPUT_HELD] = 0;
+ savedInputHeldLen = 0;
+ }
+
+ /**
+ * Encodes one or more chars. The default behaviour of the
+ * converter is stop and report if an error in input stream is encountered.
+ * To set different behaviour use @see CharsetEncoder.onMalformedInput()
+ * @param in buffer to decode
+ * @param out buffer to populate with decoded result
+ * @return result of decoding action. Returns CoderResult.UNDERFLOW if the decoding
+ * action succeeds or more input is needed for completing the decoding action.
+ * @stable ICU 2.4
+ */
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+
+ if (!in.hasRemaining()) {
+ return CoderResult.UNDERFLOW;
+ }
+
+ data[INPUT_OFFSET] = getArray(in);
+ data[OUTPUT_OFFSET]= getArray(out);
+ data[INPUT_HELD] = 0;
+ // BEGIN android-added
+ data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors.
+ // END android added
+
+ try {
+ /* do the conversion */
+ ec = NativeConverter.encode(converterHandle,/* Handle to ICU Converter */
+ input, /* input array of bytes */
+ inEnd, /* last index+1 to be converted */
+ output, /* output array of chars */
+ outEnd, /* output index+1 to be written */
+ data, /* contains data, inOff,outOff */
+ false /* donot flush the data */
+ );
+ if (ErrorCode.isFailure(ec)) {
+ /* If we don't have room for the output return error */
+ if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+ return CoderResult.OVERFLOW;
+ } else if (ec == ErrorCode.U_INVALID_CHAR_FOUND) {
+ return CoderResult.unmappableForLength(data[INVALID_CHARS]);
+ } else if (ec == ErrorCode.U_ILLEGAL_CHAR_FOUND) {
+ // in.position(in.position() - 1);
+ return CoderResult.malformedForLength(data[INVALID_CHARS]);
+ }
+ }
+ return CoderResult.UNDERFLOW;
+ } finally {
+ /* save state */
+ setPosition(in);
+ setPosition(out);
+ }
+ }
+
+ /**
+ * Ascertains if a given Unicode character can
+ * be converted to the target encoding
+ *
+ * @param c the character to be converted
+ * @return true if a character can be converted
+ * @stable ICU 2.4
+ *
+ */
+ public boolean canEncode(char c) {
+ return canEncode((int) c);
+ }
+
+ /**
+ * Ascertains if a given Unicode code point (32bit value for handling surrogates)
+ * can be converted to the target encoding. If the caller wants to test if a
+ * surrogate pair can be converted to target encoding then the
+ * responsibility of assembling the int value lies with the caller.
+ * For assembling a code point the caller can use UTF16 class of ICU4J and do something like:
+ * <pre>
+ * while(i<mySource.length){
+ * if(UTF16.isLeadSurrogate(mySource[i])&& i+1< mySource.length){
+ * if(UTF16.isTrailSurrogate(mySource[i+1])){
+ * int temp = UTF16.charAt(mySource,i,i+1,0);
+ * if(!((CharsetEncoderICU) myConv).canEncode(temp)){
+ * passed=false;
+ * }
+ * i++;
+ * i++;
+ * }
+ * }
+ * }
+ * </pre>
+ * or
+ * <pre>
+ * String src = new String(mySource);
+ * int i,codepoint;
+ * boolean passed = false;
+ * while(i<src.length()){
+ * codepoint = UTF16.charAt(src,i);
+ * i+= (codepoint>0xfff)? 2:1;
+ * if(!(CharsetEncoderICU) myConv).canEncode(codepoint)){
+ * passed = false;
+ * }
+ * }
+ * </pre>
+ *
+ * @param codepoint Unicode code point as int value
+ * @return true if a character can be converted
+ * @obsolete ICU 2.4
+ * @deprecated ICU 3.4
+ */
+ public boolean canEncode(int codepoint) {
+ return NativeConverter.canEncode(converterHandle, codepoint);
+ }
+
+ /**
+ * Releases the system resources by cleanly closing ICU converter opened
+ * @exception Throwable exception thrown by super class' finalize method
+ * @stable ICU 2.4
+ */
+ protected void finalize() throws Throwable {
+ NativeConverter.closeConverter(converterHandle);
+ super.finalize();
+ converterHandle=0;
+ }
+
+ //------------------------------------------
+ // private utility methods
+ //------------------------------------------
+ private final int getArray(ByteBuffer out) {
+ if(out.hasArray()){
+ output = out.array();
+ outEnd = out.limit();
+ return out.position();
+ }else{
+ outEnd = out.remaining();
+ if(output==null || (outEnd > output.length)){
+ output = new byte[outEnd];
+ }
+ //since the new
+ // buffer start position
+ // is 0
+ return 0;
+ }
+ }
+
+ private final int getArray(CharBuffer in) {
+ if(in.hasArray()){
+ input = in.array();
+ inEnd = in.limit();
+ return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ }else{
+ inEnd = in.remaining();
+ if(input==null|| (inEnd > input.length)){
+ input = new char[inEnd];
+ }
+ // save the current position
+ int pos = in.position();
+ in.get(input,0,inEnd);
+ // reset the position
+ in.position(pos);
+ // the start position
+ // of the new buffer
+ // is whatever is savedInputLen
+ return savedInputHeldLen;
+ }
+
+ }
+ private final void setPosition(ByteBuffer out) {
+
+ if (out.hasArray()) {
+ // in getArray method we accessed the
+ // array backing the buffer directly and wrote to
+ // it, so just just set the position and return.
+ // This is done to avoid the creation of temp array.
+ out.position(out.position() + data[OUTPUT_OFFSET] );
+ } else {
+ out.put(output, 0, data[OUTPUT_OFFSET]);
+ }
+ }
+ private final void setPosition(CharBuffer in){
+
+// BEGIN android-removed
+// // was there input held in the previous invocation of encodeLoop
+// // that resulted in output in this invocation?
+// if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen>0){
+// int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+// in.position(len);
+// savedInputHeldLen = data[INPUT_HELD];
+// }else{
+// in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen);
+// savedInputHeldLen = data[INPUT_HELD];
+// in.position(in.position() - savedInputHeldLen);
+// }
+// END android-removed
+
+// BEGIN android-added
+ // Slightly rewired original code to make it cleaner. Also
+ // added a fix for the problem where input charatcers got
+ // lost when invalid characters were encountered. Not sure
+ // what happens when data[INVALID_CHARS] is > 1, though,
+ // since we never saw that happening.
+ int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+ len -= data[INVALID_CHARS]; // Otherwise position becomes wrong.
+ in.position(len);
+ savedInputHeldLen = data[INPUT_HELD];
+ // was there input held in the previous invocation of encodeLoop
+ // that resulted in output in this invocation?
+ if(!(data[OUTPUT_OFFSET]>0 && savedInputHeldLen>0)){
+ in.position(in.position() - savedInputHeldLen);
+ }
+// END android-added
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java
new file mode 100644
index 0000000..df6f7dc
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java
@@ -0,0 +1,129 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.HashMap;
+import java.util.Map;
+
+// BEGIN android-removed
+// import com.ibm.icu4jni.common.ErrorCode;
+// import com.ibm.icu4jni.converters.NativeConverter;
+// END android-removed
+
+
+public final class CharsetICU extends Charset{
+ private String icuCanonicalName;
+ /**
+ * Constructor to create a the CharsetICU object
+ * @param canonicalName the canonical name as a string
+ * @param aliases the alias set as an array of strings
+ * @stable ICU 2.4
+ */
+ protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
+ super(canonicalName,aliases);
+ icuCanonicalName = icuCanonName;
+
+ }
+ /**
+ * Returns a new decoder instance of this charset object
+ * @return a new decoder object
+ * @stable ICU 2.4
+ */
+ public CharsetDecoder newDecoder(){
+ // the arrays are locals and not
+ // instance variables since the
+ // methods on this class need to
+ // be thread safe
+ long converterHandle = NativeConverter.openConverter(icuCanonicalName);
+ return new CharsetDecoderICU(this,converterHandle);
+ };
+
+ // hardCoded list of replacement bytes
+ private static final Map subByteMap = new HashMap();
+ static{
+ subByteMap.put("UTF-32",new byte[]{0x00, 0x00, (byte)0xfe, (byte)0xff});
+ subByteMap.put("ibm-16684_P110-2003",new byte[]{0x40, 0x40}); // make \u3000 the sub char
+ subByteMap.put("ibm-971_P100-1995",new byte[]{(byte)0xa1, (byte)0xa1}); // make \u3000 the sub char
+ }
+ /**
+ * Returns a new encoder object of the charset
+ * @return a new encoder
+ * @stable ICU 2.4
+ */
+ public CharsetEncoder newEncoder(){
+ // the arrays are locals and not
+ // instance variables since the
+ // methods on this class need to
+ // be thread safe
+ long converterHandle = NativeConverter.openConverter(icuCanonicalName);
+
+ //According to the contract all converters should have non-empty replacement
+ byte[] replacement = NativeConverter.getSubstitutionBytes(converterHandle);
+
+ try{
+ return new CharsetEncoderICU(this,converterHandle, replacement);
+ }catch(IllegalArgumentException ex){
+ // work around for the non-sensical check in the nio API that
+ // a substitution character must be mappable while decoding!!
+ replacement = (byte[])subByteMap.get(icuCanonicalName);
+ if(replacement==null){
+ replacement = new byte[NativeConverter.getMinBytesPerChar(converterHandle)];
+ for(int i=0; i<replacement.length; i++){
+ replacement[i]= 0x3f;
+ }
+ }
+ NativeConverter.setSubstitutionBytes(converterHandle, replacement, replacement.length);
+ return new CharsetEncoderICU(this,converterHandle, replacement);
+ }
+ }
+
+ /**
+ * Ascertains if a charset is a sub set of this charset
+ * @param cs charset to test
+ * @return true if the given charset is a subset of this charset
+ * @stable ICU 2.4
+ *
+ * //CSDL: major changes by Jack
+ */
+ public boolean contains(Charset cs){
+ if (null == cs) {
+ return false;
+ } else if (this.equals(cs)) {
+ return true;
+ }
+
+ long converterHandle1 = 0;
+ long converterHandle2 = 0;
+
+ try {
+ converterHandle1 = NativeConverter.openConverter(this.name());
+ if (converterHandle1 > 0) {
+ converterHandle2 = NativeConverter.openConverter(cs.name());
+ if (converterHandle2 > 0) {
+ return NativeConverter.contains(converterHandle1,
+ converterHandle2);
+ }
+ }
+ return false;
+ } finally {
+ if (0 != converterHandle1) {
+ NativeConverter.closeConverter(converterHandle1);
+ if (0 != converterHandle2) {
+ NativeConverter.closeConverter(converterHandle2);
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java
new file mode 100644
index 0000000..6f63479
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java
@@ -0,0 +1,118 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.*;
+import java.util.Iterator;
+// BEGIN android-removed
+// import com.ibm.icu4jni.converters.NativeConverter;
+// END android-removed
+
+public final class CharsetProviderICU extends CharsetProvider{
+
+ /**
+ * Constructs a CharsetProviderICU object
+ * @stable ICU 2.4
+ */
+ public CharsetProviderICU(){
+ }
+
+ /**
+ * Constructs a charset for the given charset name
+ * @param charsetName charset name
+ * @return charset objet for the given charset name
+ * @stable ICU 2.4
+ */
+ public final Charset charsetForName(String charsetName) {
+ // get the canonical name
+ String icuCanonicalName = NativeConverter.getICUCanonicalName(charsetName);
+
+ // create the converter object and return it
+ if(icuCanonicalName==null || icuCanonicalName.length()==0){
+ // this would make the Charset API to throw
+ // unsupported encoding exception
+ return null;
+ }
+
+ // BEGIN android-added
+ try{
+ long cn = NativeConverter.openConverter(icuCanonicalName);
+ NativeConverter.closeConverter(cn);
+ }catch (RuntimeException re) {
+ // unsupported encoding. let the charset api throw an
+ // UnsupportedEncodingException
+ return null;
+ }
+ // END android-added
+
+ return getCharset(icuCanonicalName);
+ }
+ private final Charset getCharset(String icuCanonicalName){
+ String[] aliases = (String[])NativeConverter.getAliases(icuCanonicalName);
+ String canonicalName = NativeConverter.getJavaCanonicalName(icuCanonicalName);
+ return (new CharsetICU(canonicalName,icuCanonicalName, aliases));
+ }
+ /**
+ * Adds an entry to the given map whose key is the charset's
+ * canonical name and whose value is the charset itself.
+ * @param map a map to receive charset objects and names
+ * @stable ICU 2.4
+ */
+ public final void putCharsets(Map map) {
+ // Get the available converter canonical names and aliases
+ String[] charsets = NativeConverter.getAvailable();
+ for(int i=0; i<charsets.length;i++){
+ // store the charsets and aliases in a Map
+ if (!map.containsKey(charsets[i])){
+ map.put(charsets[i], charsetForName(charsets[i]));
+ }
+ }
+ }
+ /**
+ * Class that implements the iterator for charsets
+ * @stable ICU 2.4
+ */
+ protected final class CharsetIterator implements Iterator{
+ private String[] names;
+ private int currentIndex;
+ protected CharsetIterator(String[] strs){
+ names = strs;
+ currentIndex=0;
+ }
+ public boolean hasNext(){
+ return (currentIndex< names.length);
+ }
+ public Object next(){
+ if(currentIndex<names.length){
+ return charsetForName(names[currentIndex++]);
+ }else{
+ throw new NoSuchElementException();
+ }
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+ /**
+ * Returns an iterator for the available charsets
+ * @return Iterator the charset name iterator
+ * @stable ICU 2.4
+ */
+ public final Iterator charsets(){
+ String[] charsets = NativeConverter.getAvailable();
+ Iterator iter = new CharsetIterator(charsets);
+ return iter;
+ }
+
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/NativeConverter.java b/icu/src/main/java/com/ibm/icu4jni/charset/NativeConverter.java
new file mode 100644
index 0000000..2bfb050
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/NativeConverter.java
@@ -0,0 +1,422 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.charset;
+
+/**
+ * Class for accessing the underlying JNI methods
+ * @internal ICU 2.4
+ */
+final class NativeConverter{
+
+ //Native methods
+
+ /**
+ * Converts an array of bytes containing characters in an external
+ * encoding into an array of Unicode characters. This method allows
+ * a buffer by buffer conversion of a data stream. The state of the
+ * conversion is saved between calls to convert. Among other things,
+ * this means multibyte input sequences can be split between calls.
+ * If a call to convert results in an Error, the conversion may be
+ * continued by calling convert again with suitably modified parameters.
+ * All conversions should be finished with a call to the flush method.
+ *
+ * @param converterHandle Address of converter object created by C code
+ * @param input byte array containing text to be converted.
+ * @param inEnd stop conversion at this offset in input array (exclusive).
+ * @param output character array to receive conversion result.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+
+ public static final native int convertByteToChar( long converterHandle,
+ byte[] input, int inEnd,
+ char[] output, int outEnd,
+ int[] data,
+ boolean flush);
+ /**
+ * Converts an array of bytes containing characters in an external
+ * encoding into an array of Unicode characters. This method allows
+ * a buffer by buffer conversion of a data stream. The state of the
+ * conversion is saved between calls to convert. Among other things,
+ * this means multibyte input sequences can be split between calls.
+ * If a call to convert results in an Error, the conversion may be
+ * continued by calling convert again with suitably modified parameters.
+ * All conversions should be finished with a call to the flush method.
+ *
+ * @param converterHandle Address of converter object created by C code
+ * @param input byte array containing text to be converted.
+ * @param inEnd stop conversion at this offset in input array (exclusive).
+ * @param output character array to receive conversion result.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int decode( long converterHandle,
+ byte[] input, int inEnd,
+ char[] output, int outEnd,
+ int[] data,
+ boolean flush);
+ /**
+ * Converts an array of Unicode chars containing characters in an
+ * external encoding into an array of bytes. This method allows
+ * a buffer by buffer conversion of a data stream. The state of the
+ * conversion is saved between calls to convert. Among other things,
+ * this means multibyte input sequences can be split between calls.
+ * If a call to convert results in an Error, the conversion may be
+ * continued by calling convert again with suitably modified parameters.
+ * All conversions should be finished with a call to the flush method.
+ *
+ * @param converterHandle Address of converter object created by C code
+ * @param input char array containing text to be converted.
+ * @param inEnd stop conversion at this offset in input array (exclusive).
+ * @param output byte array to receive conversion result.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int convertCharToByte(long converterHandle,
+ char[] input, int inEnd,
+ byte[] output, int outEnd,
+ int[] data,
+ boolean flush);
+ /**
+ * Converts an array of Unicode chars containing characters in an
+ * external encoding into an array of bytes. This method allows
+ * a buffer by buffer conversion of a data stream. The state of the
+ * conversion is saved between calls to convert. Among other things,
+ * this means multibyte input sequences can be split between calls.
+ * If a call to convert results in an Error, the conversion may be
+ * continued by calling convert again with suitably modified parameters.
+ * All conversions should be finished with a call to the flush method.
+ *
+ * @param converterHandle Address of converter object created by C code
+ * @param input char array containing text to be converted.
+ * @param inEnd stop conversion at this offset in input array (exclusive).
+ * @param output byte array to receive conversion result.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int encode(long converterHandle,
+ char[] input, int inEnd,
+ byte[] output, int outEnd,
+ int[] data,
+ boolean flush);
+ /**
+ * Writes any remaining output to the output buffer and resets the
+ * converter to its initial state.
+ *
+ * @param converterHandle Address of converter object created by C code
+ * @param output byte array to receive flushed output.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @return int error code returned by ICU
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @internal ICU 2.4
+ */
+ public static final native int flushCharToByte(long converterHandle,
+ byte[] output,
+ int outEnd,
+ int[] data);
+ /**
+ * Writes any remaining output to the output buffer and resets the
+ * converter to its initial state.
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param output char array to receive flushed output.
+ * @param outEnd stop writing to output array at this offset (exclusive).
+ * @return int error code returned by ICU
+ * @param data integer array containing the following data
+ * data[0] = inputOffset
+ * data[1] = outputOffset
+ * @internal ICU 2.4
+ */
+ public static final native int flushByteToChar(long converterHandle,
+ char[] output,
+ int outEnd,
+ int[] data);
+
+ /**
+ * Open the converter with the specified encoding
+ *
+ * @param converterHandle long array for recieving the adress of converter object
+ * created by the native code
+ * @param encoding string representing encoding
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native long openConverter(String encoding);
+ /**
+ * Resets the ByteToChar (toUnicode) state of specified converter
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @internal ICU 2.4
+ */
+ public static final native void resetByteToChar(long converterHandle);
+
+ /**
+ * Resets the CharToByte (fromUnicode) state of specified converter
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @internal ICU 2.4
+ */
+ public static final native void resetCharToByte(long converterHandle);
+
+ /**
+ * Closes the specified converter and releases the resources
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @internal ICU 2.4
+ */
+ public static final native void closeConverter(long converterHandle);
+
+ /**
+ * Sets the substitution Unicode chars of the specified converter used
+ * by encoder
+ * @param converterHandle Address of converter object created by the native code
+ * @param subChars array of chars to used for substitution
+ * @param length length of the array
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int setSubstitutionChars( long converterHandle,
+ char[] subChars,int length);
+ /**
+ * Sets the substitution bytes of the specified converter used by decoder
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param subChars array of bytes to used for substitution
+ * @param length length of the array
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int setSubstitutionBytes( long converterHandle,
+ byte[] subChars,int length);
+ /**
+ * Sets the substitution mode of CharToByte(fromUnicode) for the specified converter
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param mode to set the true/false
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int setSubstitutionModeCharToByte(long converterHandle,
+ boolean mode);
+ /**
+ * Sets the substitution mode of CharToByte(fromUnicode) for the specified converter
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param mode to set the true/false
+ * @return int error code returned by ICU
+ * @internal ICU 3.6
+ */
+ public static final native int setSubstitutionModeByteToChar(long converterHandle,
+ boolean mode);
+ /**
+ * Gets the numnber of invalid bytes in the specified converter object
+ * for the last error that has occured
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param length array of int to recieve length of the array
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int countInvalidBytes(long converterHandle, int[] length);
+
+ /**
+ * Gets the numnber of invalid chars in the specified converter object
+ * for the last error that has occured
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @param length array of int to recieve length of the array
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int countInvalidChars(long converterHandle, int[] length);
+
+ /**
+ * Gets the number of bytes needed for converting a char
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @return number of bytes needed
+ * @internal ICU 2.4
+ */
+ public static final native int getMaxBytesPerChar(long converterHandle);
+
+ /**
+ * Gets the number of bytes needed for converting a char
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @return number of bytes needed
+ * @internal ICU 3.2
+ */
+ public static final native int getMinBytesPerChar(long converterHandle);
+
+ /**
+ * Gets the average numnber of bytes needed for converting a char
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @return number of bytes needed
+ * @internal ICU 2.4
+ */
+ public static final native float getAveBytesPerChar(long converterHandle);
+
+ /**
+ * Gets the number of chars needed for converting a byte
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @return number of bytes needed
+ * @internal ICU 2.4
+ */
+ public static final native int getMaxCharsPerByte(long converterHandle);
+
+ /**
+ * Gets the average numnber of chars needed for converting a byte
+ *
+ * @param converterHandle Address of converter object created by the native code
+ * @return number of bytes needed
+ * @internal ICU 2.4
+ */
+ public static final native float getAveCharsPerByte(long converterHandle);
+
+ //CSDL: added by Jack
+ /**
+ * Determines whether charset1 contains charset2.
+ */
+ public static final native boolean contains(long converterHandle1, long converterHandle2);
+
+ public static final native byte[] getSubstitutionBytes(long converterHandle);
+
+ /**
+ * Ascertains if a given Unicode code unit can
+ * be converted to the target encoding
+ * @param converterHandle Address of converter object created by the native code
+ * @param codeUnit the character to be converted
+ * @return true if a character can be converted
+ * @internal ICU 2.4
+ *
+ */
+ public static final native boolean canEncode(long converterHandle,int codeUnit);
+
+ /**
+ * Ascertains if a given a byte sequence can be converted to Unicode
+ * @param converterHandle Address of converter object created by the native code
+ * @param bytes the bytes to be converted
+ * @return true if a character can be converted
+ * @internal ICU 2.4
+ *
+ */
+ public static final native boolean canDecode(long converterHandle,byte[] bytes);
+
+ /**
+ * Gets the number of converters installed in the current installation of ICU
+ * @return int number of converters installed
+ * @internal ICU 2.4
+ */
+ public static final native int countAvailable();
+
+ /**
+ * Gets the canonical names of available converters
+ * @return Object[] names as an object array
+ * @internal ICU 2.4
+ */
+ public static final native String[] getAvailable();
+
+ /**
+ * Gets the number of aliases for a converter name
+ * @param enc encoding name
+ * @return number of aliases for the converter
+ * @internal ICU 2.4
+ */
+ public static final native int countAliases(String enc);
+
+ /**
+ * Gets the aliases associated with the converter name
+ * @param enc converter name
+ * @return converter names as elements in an object array
+ * @internal ICU 2.4
+ */
+ public static final native String[] getAliases(String enc);
+
+ /**
+ * Gets the canonical name of the converter
+ * @param enc converter name
+ * @return canonical name of the converter
+ * @internal ICU 2.4
+ */
+ public static final native String getCanonicalName(String enc);
+
+ /**
+ * Gets the canonical name of the converter as defined by Java
+ * @param enc converter name
+ * @return canonical name of the converter
+ * @internal ICU 3.4
+ */
+ public static final native String getICUCanonicalName(String enc);
+
+ /**
+ * Gets the canonical name of the converter as defined by Java
+ * @param icuCanonicalName converter name
+ * @return canonical name of the converter
+ * @internal ICU 3.4
+ */
+ public static final native String getJavaCanonicalName(String icuCanonicalName);
+
+ /**
+ * Sets the callback to Unicode for ICU conveter. The default behaviour of ICU callback
+ * is to call the specified callback function for both illegal and unmapped sequences.
+ * @param converterHandle Adress of the converter object created by native code
+ * @param mode call back mode to set. This is either STOP_CALLBACK, SKIP_CALLBACK or SUBSTITUE_CALLBACK
+ * The converter performs the specified callback when an error occurs
+ * @param stopOnIllegal If true sets the alerts the converter callback to stop on an illegal sequence
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, char[] subChars, int length);
+
+ /**
+ * Sets the callback from Unicode for ICU conveter. The default behaviour of ICU callback
+ * is to call the specified callback function for both illegal and unmapped sequences.
+ * @param converterHandle Adress of the converter object created by native code
+ * @param mode call back mode to set. This is either STOP_CALLBACK, SKIP_CALLBACK or SUBSTITUE_CALLBACK
+ * The converter performs the specified callback when an error occurs
+ * @param stopOnIllegal If true sets the alerts the converter callback to stop on an illegal sequence
+ * @return int error code returned by ICU
+ * @internal ICU 2.4
+ */
+ public static final native int setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes, int length);
+
+ /**
+ * Returns a thread safe clone of the converter
+ * @internal ICU 2.4
+ */
+ public static final native long safeClone(long converterHandle);
+
+ /** @internal ICU 2.4 */
+ public static final int STOP_CALLBACK = 0;//CodingErrorAction.REPORT
+ /** @internal ICU 2.4 */
+ public static final int SKIP_CALLBACK = 1;//CodingErrorAction.IGNORE
+ /** @internal ICU 2.4 */
+ public static final int SUBSTITUTE_CALLBACK = 2;//CodingErrorAction.REPLACE
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java b/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java
new file mode 100644
index 0000000..023f165
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java
@@ -0,0 +1,205 @@
+/**
+******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+******************************************************************************
+*
+******************************************************************************
+*/
+
+package com.ibm.icu4jni.common;
+
+/**
+* Error exception class mapping ICU error codes of the enum UErrorCode
+* @author syn wee quek
+* @internal
+*/
+public final class ErrorCode extends Exception
+{
+
+ // public methods --------------------------------------------------------
+
+ /**
+ * Generic mapping from the error codes to java default exceptions.
+ * @param error error code
+ * @return java default exception that maps to the argument error code,
+ * otherwise if error is not a valid error code, null is returned.
+ * @stable ICU 2.4
+ */
+ public static final RuntimeException getException(int error)
+ {
+ if (error <= U_ZERO_ERROR && error >= U_ERROR_LIMIT) {
+ return null;
+ }
+ String errorname = ERROR_NAMES_[U_ILLEGAL_ARGUMENT_ERROR];
+ switch (error) {
+ case U_ILLEGAL_ARGUMENT_ERROR :
+ return new IllegalArgumentException(errorname);
+ case U_INDEX_OUTOFBOUNDS_ERROR :
+ return new ArrayIndexOutOfBoundsException(errorname);
+ case U_BUFFER_OVERFLOW_ERROR :
+ return new ArrayIndexOutOfBoundsException(errorname);
+ case U_UNSUPPORTED_ERROR :
+ return new UnsupportedOperationException(errorname);
+ default :
+ return new RuntimeException(errorname);
+ }
+ }
+
+ // public static data member ---------------------------------------------
+
+ /**
+ * Start of information results (semantically successful)
+ */
+ public static final int U_ERROR_INFO_START = -128;
+ /**
+ * A resource bundle lookup returned a fallback result (not an error)
+ */
+ public static final int U_USING_FALLBACK_ERROR = -128;
+ /**
+ * A resource bundle lookup returned a result from the root locale (not an
+ * error)
+ */
+ public static final int U_USING_DEFAULT_ERROR = -127;
+ /**
+ * A SafeClone operation required allocating memory (informational
+ * only
+ */
+ public static final int U_SAFECLONE_ALLOCATED_ERROR = -126;
+ /**
+ * This must always be the last warning value to indicate the limit for
+ * UErrorCode warnings (last warning code +1)
+ */
+ public static final int U_ERROR_INFO_LIMIT = -125;
+
+ /**
+ * No error, no warning
+ */
+ public static final int U_ZERO_ERROR = 0;
+ /**
+ * Start of codes indicating failure
+ */
+ public static final int U_ILLEGAL_ARGUMENT_ERROR = 1;
+ public static final int U_MISSING_RESOURCE_ERROR = 2;
+ public static final int U_INVALID_FORMAT_ERROR = 3;
+ public static final int U_FILE_ACCESS_ERROR = 4;
+ /**
+ * Indicates a bug in the library code
+ */
+ public static final int U_INTERNAL_PROGRAM_ERROR = 5;
+ public static final int U_MESSAGE_PARSE_ERROR = 6;
+ /**
+ * Memory allocation error
+ */
+ public static final int U_MEMORY_ALLOCATION_ERROR = 7;
+ public static final int U_INDEX_OUTOFBOUNDS_ERROR = 8;
+ /**
+ * Equivalent to Java ParseException
+ */
+ public static final int U_PARSE_ERROR = 9;
+ /**
+ * In the Character conversion routines: Invalid character or sequence was
+ * encountered
+ */
+ public static final int U_INVALID_CHAR_FOUND = 10;
+ /**
+ * In the Character conversion routines: More bytes are required to complete
+ * the conversion successfully
+ */
+ public static final int U_TRUNCATED_CHAR_FOUND = 11;
+ /**
+ * In codeset conversion: a sequence that does NOT belong in the codepage has
+ * been encountered
+ */
+ public static final int U_ILLEGAL_CHAR_FOUND = 12;
+ /**
+ * Conversion table file found, but corrupted
+ */
+ public static final int U_INVALID_TABLE_FORMAT = 13;
+ /**
+ * Conversion table file not found
+ */
+ public static final int U_INVALID_TABLE_FILE = 14;
+ /**
+ * A result would not fit in the supplied buffer
+ */
+ public static final int U_BUFFER_OVERFLOW_ERROR = 15;
+ /**
+ * Requested operation not supported in current context
+ */
+ public static final int U_UNSUPPORTED_ERROR = 16;
+ /**
+ * an operation is requested over a resource that does not support it
+ */
+ public static final int U_RESOURCE_TYPE_MISMATCH = 17;
+ /**
+ * ISO-2022 illlegal escape sequence
+ */
+ public static final int U_ILLEGAL_ESCAPE_SEQUENCE = 18;
+ /**
+ * ISO-2022 unsupported escape sequence
+ */
+ public static final int U_UNSUPPORTED_ESCAPE_SEQUENCE = 19;
+ /**
+ * No space available for in-buffer expansion for Arabic shaping
+ */
+ public static final int U_NO_SPACE_AVAILABLE = 20;
+ /**
+ * This must always be the last value to indicate the limit for UErrorCode
+ * (last error code +1)
+ */
+ public static final int U_ERROR_LIMIT = 21;
+ /**
+ * Load library flag
+ */
+ public static boolean LIBRARY_LOADED = false;
+
+ // private data member ----------------------------------------------------
+
+ /**
+ * Array of error code names corresponding to the errorcodes.
+ * ie ERROR_NAMES_[0] = name of U_ZERO_ERROR
+ */
+ private static final String ERROR_NAMES_[] = {
+ "U_ZERO_ERROR", "U_ILLEGAL_ARGUMENT_ERROR",
+ "U_MISSING_RESOURCE_ERROR", "U_INVALID_FORMAT_ERROR",
+ "U_FILE_ACCESS_ERROR", "U_INTERNAL_PROGRAM_ERROR",
+ "U_MESSAGE_PARSE_ERROR", "U_MEMORY_ALLOCATION_ERROR",
+ "U_INDEX_OUTOFBOUNDS_ERROR", "U_PARSE_ERROR",
+ "U_INVALID_CHAR_FOUND", "U_TRUNCATED_CHAR_FOUND",
+ "U_ILLEGAL_CHAR_FOUND", "U_INVALID_TABLE_FORMAT",
+ "U_INVALID_TABLE_FILE", "U_BUFFER_OVERFLOW_ERROR",
+ "U_UNSUPPORTED_ERROR", "U_RESOURCE_TYPE_MISMATCH",
+ "U_ILLEGAL_ESCAPE_SEQUENCE", "U_UNSUPPORTED_ESCAPE_SEQUENCE"
+ };
+ /**
+ * Returns the error name of the input error code
+ * @param ec int value of the error code
+ * @return String name of the error code
+ * @stable ICU 2.4
+ */
+ public static String getErrorName(int ec){
+ return ERROR_NAMES_[ec];
+ }
+
+ /**
+ * Returns true if the input error code denotes success
+ * @param ec int value of the error code
+ * @return boolean
+ * @stable ICU 2.4
+ */
+ public static boolean isSuccess(int ec){
+ return (ec<=U_ZERO_ERROR);
+ }
+
+ /**
+ * Returns true if the input error code denotes failure
+ * @param ec int value of the error code
+ * @return boolean
+ * @stable ICU 2.4
+ */
+ public static boolean isFailure(int ec){
+ return (ec>U_ZERO_ERROR);
+ }
+}
+
diff --git a/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java b/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java
new file mode 100644
index 0000000..7ab1843
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.lang;
+
+import java.lang.Character.UnicodeBlock;
+
+public class UCharacter {
+
+ public static int digit(int codePoint, int radix) {
+ return digitImpl(codePoint, radix);
+ }
+
+ private static native int digitImpl(int codePoint, int radix);
+
+ public static int getType(int codePoint) {
+ return getTypeImpl(codePoint);
+ }
+
+ private static native int getTypeImpl(int codePoint);
+
+ public static byte getDirectionality(int codePoint) {
+ return getDirectionalityImpl(codePoint);
+ }
+
+ private static native byte getDirectionalityImpl(int codePoint);
+
+ public static boolean isMirrored(int codePoint) {
+ return isMirroredImpl(codePoint);
+ }
+
+ private static native boolean isMirroredImpl(int codePoint);
+
+ public static int getNumericValue(int codePoint) {
+ return getNumericValueImpl(codePoint);
+ }
+
+ private static native int getNumericValueImpl(int codePoint);
+
+ public static boolean isDefined(int codePoint) {
+ return isDefinedValueImpl(codePoint);
+ }
+
+ private static native boolean isDefinedValueImpl(int codePoint);
+
+ public static boolean isDigit(int codePoint) {
+ return isDigitImpl(codePoint);
+ }
+
+ private static native boolean isDigitImpl(int codePoint);
+
+ public static boolean isIdentifierIgnorable(int codePoint) {
+ return isIdentifierIgnorableImpl(codePoint);
+ }
+
+ private static native boolean isIdentifierIgnorableImpl(int codePoint);
+
+ public static boolean isLetter(int codePoint) {
+ return isLetterImpl(codePoint);
+ }
+
+ private static native boolean isLetterImpl(int codePoint);
+
+ public static boolean isLetterOrDigit(int codePoint) {
+ return isLetterOrDigitImpl(codePoint);
+ }
+
+ private static native boolean isLetterOrDigitImpl(int codePoint);
+
+ public static boolean isSpaceChar(int codePoint) {
+ return isSpaceCharImpl(codePoint);
+ }
+
+ private static native boolean isSpaceCharImpl(int codePoint);
+
+ public static boolean isTitleCase(int codePoint) {
+ return isTitleCaseImpl(codePoint);
+ }
+
+ private static native boolean isTitleCaseImpl(int codePoint);
+
+ public static boolean isUnicodeIdentifierPart(int codePoint) {
+ return isUnicodeIdentifierPartImpl(codePoint);
+ }
+
+ private static native boolean isUnicodeIdentifierPartImpl(int codePoint);
+
+ public static boolean isUnicodeIdentifierStart(int codePoint) {
+ return isUnicodeIdentifierStartImpl(codePoint);
+ }
+
+ private static native boolean isUnicodeIdentifierStartImpl(int codePoint);
+
+ public static boolean isWhitespace(int codePoint) {
+ return isWhitespaceImpl(codePoint);
+ }
+
+ private static native boolean isWhitespaceImpl(int codePoint);
+
+ public static int toLowerCase(int codePoint) {
+ return toLowerCaseImpl(codePoint);
+ }
+
+ private static native int toLowerCaseImpl(int codePoint);
+
+ public static int toTitleCase(int codePoint) {
+ return toTitleCaseImpl(codePoint);
+ }
+
+ private static native int toTitleCaseImpl(int codePoint);
+
+ public static int toUpperCase(int codePoint) {
+ return toUpperCaseImpl(codePoint);
+ }
+
+ private static native int toUpperCaseImpl(int codePoint);
+
+ public static boolean isUpperCase(int codePoint) {
+ return isUpperCaseImpl(codePoint);
+ }
+
+ private static native boolean isUpperCaseImpl(int codePoint);
+
+ public static boolean isLowerCase(int codePoint) {
+ return isLowerCaseImpl(codePoint);
+ }
+
+ private static native boolean isLowerCaseImpl(int codePoint);
+
+ public static int forName(String blockName) {
+ if (blockName == null) {
+ throw new NullPointerException();
+ }
+ return forname(blockName);
+ }
+
+ private static native int forname(String blockName);
+
+ public static int of(int codePoint) {
+ return codeblock(codePoint);
+ }
+
+ private static native int codeblock(int codePoint);
+
+ public static UnicodeBlock[] getBlockTable() {
+ /**
+ * The indices of the entries of this table correspond with the value
+ * of the ICU enum UBlockCode. When updating ICU it's necessary
+ * to check if there where any changes for the properties
+ * used by java.lang.Character.
+ * The enum is defined in common/unicode/uchar.h
+ */
+ UnicodeBlock[] result = new UnicodeBlock[] { null,
+ UnicodeBlock.BASIC_LATIN,
+ UnicodeBlock.LATIN_1_SUPPLEMENT,
+ UnicodeBlock.LATIN_EXTENDED_A,
+ UnicodeBlock.LATIN_EXTENDED_B,
+ UnicodeBlock.IPA_EXTENSIONS,
+ UnicodeBlock.SPACING_MODIFIER_LETTERS,
+ UnicodeBlock.COMBINING_DIACRITICAL_MARKS,
+ UnicodeBlock.GREEK,
+ UnicodeBlock.CYRILLIC,
+ UnicodeBlock.ARMENIAN,
+ UnicodeBlock.HEBREW,
+ UnicodeBlock.ARABIC,
+ UnicodeBlock.SYRIAC,
+ UnicodeBlock.THAANA,
+ UnicodeBlock.DEVANAGARI,
+ UnicodeBlock.BENGALI,
+ UnicodeBlock.GURMUKHI,
+ UnicodeBlock.GUJARATI,
+ UnicodeBlock.ORIYA,
+ UnicodeBlock.TAMIL,
+ UnicodeBlock.TELUGU,
+ UnicodeBlock.KANNADA,
+ UnicodeBlock.MALAYALAM,
+ UnicodeBlock.SINHALA,
+ UnicodeBlock.THAI,
+ UnicodeBlock.LAO,
+ UnicodeBlock.TIBETAN,
+ UnicodeBlock.MYANMAR,
+ UnicodeBlock.GEORGIAN,
+ UnicodeBlock.HANGUL_JAMO,
+ UnicodeBlock.ETHIOPIC,
+ UnicodeBlock.CHEROKEE,
+ UnicodeBlock.UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS,
+ UnicodeBlock.OGHAM,
+ UnicodeBlock.RUNIC,
+ UnicodeBlock.KHMER,
+ UnicodeBlock.MONGOLIAN,
+ UnicodeBlock.LATIN_EXTENDED_ADDITIONAL,
+ UnicodeBlock.GREEK_EXTENDED,
+ UnicodeBlock.GENERAL_PUNCTUATION,
+ UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS,
+ UnicodeBlock.CURRENCY_SYMBOLS,
+ UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS,
+ UnicodeBlock.LETTERLIKE_SYMBOLS,
+ UnicodeBlock.NUMBER_FORMS,
+ UnicodeBlock.ARROWS,
+ UnicodeBlock.MATHEMATICAL_OPERATORS,
+ UnicodeBlock.MISCELLANEOUS_TECHNICAL,
+ UnicodeBlock.CONTROL_PICTURES,
+ UnicodeBlock.OPTICAL_CHARACTER_RECOGNITION,
+ UnicodeBlock.ENCLOSED_ALPHANUMERICS,
+ UnicodeBlock.BOX_DRAWING,
+ UnicodeBlock.BLOCK_ELEMENTS,
+ UnicodeBlock.GEOMETRIC_SHAPES,
+ UnicodeBlock.MISCELLANEOUS_SYMBOLS,
+ UnicodeBlock.DINGBATS,
+ UnicodeBlock.BRAILLE_PATTERNS,
+ UnicodeBlock.CJK_RADICALS_SUPPLEMENT,
+ UnicodeBlock.KANGXI_RADICALS,
+ UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS,
+ UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION,
+ UnicodeBlock.HIRAGANA,
+ UnicodeBlock.KATAKANA,
+ UnicodeBlock.BOPOMOFO,
+ UnicodeBlock.HANGUL_COMPATIBILITY_JAMO,
+ UnicodeBlock.KANBUN,
+ UnicodeBlock.BOPOMOFO_EXTENDED,
+ UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS,
+ UnicodeBlock.CJK_COMPATIBILITY,
+ UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
+ UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS,
+ UnicodeBlock.YI_SYLLABLES,
+ UnicodeBlock.YI_RADICALS,
+ UnicodeBlock.HANGUL_SYLLABLES,
+ UnicodeBlock.HIGH_SURROGATES,
+ UnicodeBlock.HIGH_PRIVATE_USE_SURROGATES,
+ UnicodeBlock.LOW_SURROGATES,
+ UnicodeBlock.PRIVATE_USE_AREA,
+ UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS,
+ UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS,
+ UnicodeBlock.ARABIC_PRESENTATION_FORMS_A,
+ UnicodeBlock.COMBINING_HALF_MARKS,
+ UnicodeBlock.CJK_COMPATIBILITY_FORMS,
+ UnicodeBlock.SMALL_FORM_VARIANTS,
+ UnicodeBlock.ARABIC_PRESENTATION_FORMS_B,
+ UnicodeBlock.SPECIALS,
+ UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS,
+ UnicodeBlock.OLD_ITALIC,
+ UnicodeBlock.GOTHIC,
+ UnicodeBlock.DESERET,
+ UnicodeBlock.BYZANTINE_MUSICAL_SYMBOLS,
+ UnicodeBlock.MUSICAL_SYMBOLS,
+ UnicodeBlock.MATHEMATICAL_ALPHANUMERIC_SYMBOLS,
+ UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B,
+ UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT,
+ UnicodeBlock.TAGS,
+ UnicodeBlock.CYRILLIC_SUPPLEMENTARY,
+ UnicodeBlock.TAGALOG,
+ UnicodeBlock.HANUNOO,
+ UnicodeBlock.BUHID,
+ UnicodeBlock.TAGBANWA,
+ UnicodeBlock.MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A,
+ UnicodeBlock.SUPPLEMENTAL_ARROWS_A,
+ UnicodeBlock.SUPPLEMENTAL_ARROWS_B,
+ UnicodeBlock.MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B,
+ UnicodeBlock.SUPPLEMENTAL_MATHEMATICAL_OPERATORS,
+ UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS,
+ UnicodeBlock.VARIATION_SELECTORS,
+ UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_A,
+ UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B,
+ UnicodeBlock.LIMBU,
+ UnicodeBlock.TAI_LE,
+ UnicodeBlock.KHMER_SYMBOLS,
+ UnicodeBlock.PHONETIC_EXTENSIONS,
+ UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_ARROWS,
+ UnicodeBlock.YIJING_HEXAGRAM_SYMBOLS,
+ UnicodeBlock.LINEAR_B_SYLLABARY,
+ UnicodeBlock.LINEAR_B_IDEOGRAMS,
+ UnicodeBlock.AEGEAN_NUMBERS,
+ UnicodeBlock.UGARITIC,
+ UnicodeBlock.SHAVIAN,
+ UnicodeBlock.OSMANYA,
+ UnicodeBlock.CYPRIOT_SYLLABARY,
+ UnicodeBlock.TAI_XUAN_JING_SYMBOLS,
+ UnicodeBlock.VARIATION_SELECTORS_SUPPLEMENT
+ };
+ return result;
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java b/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java
new file mode 100644
index 0000000..4460b19
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java
@@ -0,0 +1,34 @@
+package com.ibm.icu4jni.math;
+
+public class BigDecimal extends Number {
+
+ @Override
+ public double doubleValue() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float floatValue() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int intValue() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long longValue() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java b/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java
new file mode 100644
index 0000000..bdfff5b
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.regex;
+
+public class NativeRegEx {
+
+ /**
+ * Opens (compiles) an ICU regular expression.
+ */
+ public static native int open(String pattern, int flags);
+
+ /**
+ * Makes a copy of a compiled regular expression.
+ */
+ public static native int clone(int regex);
+
+ /**
+ * Closes the regular expression, recovering all resources (memory) it was
+ * holding.
+ */
+ public static native void close(int regex);
+
+ /**
+ * Sets the subject text string upon which the regular expression will look
+ * for matches.
+ */
+ public static native void setText(int regex, String text);
+
+ /**
+ * Attempts to match the input string, beginning at startIndex, against the
+ * pattern.
+ */
+ public static native boolean matches(int regex, int startIndex);
+
+ /**
+ * Attempts to match the input string, starting from the specified index,
+ * against the pattern.
+ */
+ public static native boolean lookingAt(int regex, int startIndex);
+
+ /**
+ * Finds the first matching substring of the input string that matches the
+ * pattern.
+ */
+ public static native boolean find(int regex, int startIndex);
+
+ /**
+ * Finds the first matching substring of the input string that matches the
+ * pattern.
+ */
+ public static native boolean findNext(int regex);
+
+ /**
+ * Gets the number of capturing groups in this regular expression's pattern.
+ */
+ public static native int groupCount(int regex);
+
+ /**
+ * Gets all the group information for the current match of the pattern.
+ */
+ public static native void startEnd(int regex, int[] startEnd);
+
+ /**
+ * Sets the region of the input to be considered during matching.
+ */
+ public static native void setRegion(int regex, int start, int end);
+
+ /**
+ * Queries the start of the region of the input to be considered during
+ * matching.
+ */
+ public static native int regionStart(int regex);
+
+ /**
+ * Queries the end of the region of the input to be considered during
+ * matching.
+ */
+ public static native int regionEnd(int regex);
+
+ /**
+ * Controls the transparency of the region bounds.
+ */
+ public static native void useTransparentBounds(int regex, boolean value);
+
+ /**
+ * Queries the transparency of the region bounds.
+ */
+ public static native boolean hasTransparentBounds(int regex);
+
+ /**
+ * Controls the anchoring property of the region bounds.
+ */
+ public static native void useAnchoringBounds(int regex, boolean value);
+
+ /**
+ * Queries the anchoring property of the region bounds.
+ */
+ public static native boolean hasAnchoringBounds(int regex);
+
+ /**
+ * Queries whether we hit the end of the input during the last match.
+ */
+ public static native boolean hitEnd(int regex);
+
+ /**
+ * Queries whether more input might change a current match, but wouldn't
+ * destroy it.
+ */
+ public static native boolean requireEnd(int regex);
+
+ /**
+ * Resets the matcher, cause a current match to be lost, and sets the
+ * position at which a subsequent findNext() would start.
+ */
+ public static native void reset(int regex, int position);
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java b/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java
new file mode 100644
index 0000000..c8f5372
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+public abstract class BreakIterator implements Cloneable
+{
+ protected static int BI_CHAR_INSTANCE = 1;
+ protected static int BI_WORD_INSTANCE = 2;
+ protected static int BI_LINE_INSTANCE = 3;
+ protected static int BI_SENT_INSTANCE = 4;
+
+ protected int type = 0;
+
+ public static Locale[] getAvailableLocales() {
+
+ String[] locales = NativeBreakIterator.getAvailableLocalesImpl();
+
+ Locale[] result = new Locale[locales.length];
+
+ String locale;
+
+ int index, index2;
+
+ for(int i = 0; i < locales.length; i++) {
+ locale = locales[i];
+
+ index = locale.indexOf('_');
+ index2 = locale.lastIndexOf('_');
+
+ if(index == -1) {
+ result[i] = new Locale(locales[i]);
+ } else if(index > 0 && index == index2) {
+ result[i] = new Locale(
+ locale.substring(0,index),
+ locale.substring(index+1));
+ } else if(index > 0 && index2 > index) {
+ result[i] = new Locale(
+ locale.substring(0,index),
+ locale.substring(index+1,index2),
+ locale.substring(index2+1));
+ }
+ }
+
+ return result;
+ }
+
+ public static BreakIterator getCharacterInstance() {
+ int iter = NativeBreakIterator.getCharacterInstanceImpl("");
+ return new RuleBasedBreakIterator(iter, BI_CHAR_INSTANCE);
+ }
+
+ public static BreakIterator getCharacterInstance(Locale where) {
+ int iter = NativeBreakIterator.getCharacterInstanceImpl(where.toString());
+ return new RuleBasedBreakIterator(iter, BI_CHAR_INSTANCE);
+ }
+
+ public static BreakIterator getLineInstance() {
+ int iter = NativeBreakIterator.getLineInstanceImpl("");
+ return new RuleBasedBreakIterator(iter, BI_LINE_INSTANCE);
+ }
+
+ public static BreakIterator getLineInstance(Locale where) {
+ int iter = NativeBreakIterator.getLineInstanceImpl(where.toString());
+ return new RuleBasedBreakIterator(iter, BI_LINE_INSTANCE);
+ }
+
+ public static BreakIterator getSentenceInstance() {
+ int iter = NativeBreakIterator.getSentenceInstanceImpl("");
+ return new RuleBasedBreakIterator(iter, BI_SENT_INSTANCE);
+ }
+
+ public static BreakIterator getSentenceInstance(Locale where) {
+ int iter = NativeBreakIterator.getSentenceInstanceImpl(where.toString());
+ return new RuleBasedBreakIterator(iter, BI_SENT_INSTANCE);
+ }
+
+ public static BreakIterator getWordInstance() {
+ int iter = NativeBreakIterator.getWordInstanceImpl("");
+ return new RuleBasedBreakIterator(iter, BI_WORD_INSTANCE);
+ }
+
+ public static BreakIterator getWordInstance(Locale where) {
+ int iter = NativeBreakIterator.getWordInstanceImpl(where.toString());
+ return new RuleBasedBreakIterator(iter, BI_WORD_INSTANCE);
+ }
+
+ public void setText(String newText) {
+ setText(new StringCharacterIterator(newText));
+ }
+
+ public abstract boolean isBoundary(int offset);
+
+ public abstract int preceding(int offset);
+
+ public abstract Object clone();
+
+ public abstract int current();
+
+ public abstract int first();
+
+ public abstract int following(int offset);
+
+ public abstract CharacterIterator getText();
+
+ public abstract int last();
+
+ public abstract int next(int n);
+
+ public abstract int next();
+
+ public abstract int previous();
+
+ public abstract void setText(CharacterIterator newText);
+
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java b/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java
new file mode 100644
index 0000000..b1c6107
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java
@@ -0,0 +1,214 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Interface for storing ICU collation equivalent enum values.
+* Constants with the prefix VALUE corresponds to ICU's UColAttributeValues,
+* the rest corresponds to UColAttribute.
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class CollationAttribute
+{
+ // Collation strength constants ----------------------------------
+ /**
+ * Default value, accepted by most attributes
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_DEFAULT = -1;
+ /**
+ * Primary collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_PRIMARY = 0;
+ /**
+ * Secondary collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_SECONDARY = 1;
+ /**
+ * Tertiary collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_TERTIARY = 2;
+ /**
+ * Default collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_DEFAULT_STRENGTH = VALUE_TERTIARY;
+ /**
+ * Quaternary collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_QUATERNARY = 3;
+ /**
+ * Identical collation strength
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_IDENTICAL = 15;
+
+ /**
+ * Turn the feature off - works for FRENCH_COLLATION, CASE_LEVEL,
+ * HIRAGANA_QUATERNARY_MODE and DECOMPOSITION_MODE
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_OFF = 16;
+ /** @stable ICU 2.4 */
+ public static final int VALUE_ON = 17;
+
+ /**
+ * ALTERNATE_HANDLING mode constants
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_SHIFTED = 20;
+ /** @stable ICU 2.4 */
+ public static final int VALUE_NON_IGNORABLE = 21;
+
+ /**
+ * CASE_FIRST mode constants
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_LOWER_FIRST = 24;
+ /** @stable ICU 2.4 */
+ public static final int VALUE_UPPER_FIRST = 25;
+
+ /**
+ * NORMALIZATION_MODE mode constants
+ * @deprecated ICU 2.4. Users advised to use VALUE_ON instead.
+ */
+ public static final int VALUE_ON_WITHOUT_HANGUL = 28;
+
+ /**
+ * Number of attribute value constants
+ * @stable ICU 2.4
+ */
+ public static final int VALUE_ATTRIBUTE_VALUE_COUNT = 29;
+
+ // Collation attribute constants -----------------------------------
+
+ /**
+ * Attribute for direction of secondary weights
+ * @stable ICU 2.4
+ */
+ public static final int FRENCH_COLLATION = 0;
+ /**
+ * Attribute for handling variable elements
+ * @stable ICU 2.4
+ */
+ public static final int ALTERNATE_HANDLING = 1;
+ /**
+ * Who goes first, lower case or uppercase.
+ * @stable ICU 2.4
+ */
+ public static final int CASE_FIRST = 2;
+ /**
+ * Do we have an extra case level
+ * @stable ICU 2.4
+ */
+ public static final int CASE_LEVEL = 3;
+ /**
+ * Attribute for normalization
+ * @stable ICU 2.4
+ */
+ public static final int NORMALIZATION_MODE = 4;
+ /**
+ * Attribute for strength
+ * @stable ICU 2.4
+ */
+ public static final int STRENGTH = 5;
+ /**
+ * Attribute count
+ * @stable ICU 2.4
+ */
+ public static final int ATTRIBUTE_COUNT = 6;
+
+ // package methods --------------------------------------------------
+
+ /**
+ * Checks if argument is a valid collation strength
+ * @param strength potential collation strength
+ * @return true if strength is a valid collation strength, false otherwise
+ */
+ static boolean checkStrength(int strength)
+ {
+ if (strength < VALUE_PRIMARY ||
+ (strength > VALUE_QUATERNARY && strength != VALUE_IDENTICAL))
+ return false;
+ return true;
+ }
+
+ /**
+ * Checks if argument is a valid collation type
+ * @param type collation type to be checked
+ * @return true if type is a valid collation type, false otherwise
+ */
+ static boolean checkType(int type)
+ {
+ if (type < FRENCH_COLLATION || type > STRENGTH)
+ return false;
+ return true;
+ }
+
+ /**
+ * Checks if argument is a valid normalization type
+ * @param type normalization type to be checked
+ * @return true if type is a valid normalization type, false otherwise
+ */
+ static boolean checkNormalization(int type)
+ {
+ if (type != VALUE_ON && type != VALUE_OFF
+ && type != VALUE_ON_WITHOUT_HANGUL) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if attribute type and corresponding attribute value is valid
+ * @param type attribute type
+ * @param value attribute value
+ * @return true if the pair is valid, false otherwise
+ */
+ static boolean checkAttribute(int type, int value)
+ {
+ if (value == VALUE_DEFAULT) {
+ return true;
+ }
+
+ switch (type)
+ {
+ case FRENCH_COLLATION :
+ if (value >= VALUE_OFF && value <= VALUE_ON)
+ return true;
+ break;
+ case ALTERNATE_HANDLING :
+ if (value >= VALUE_SHIFTED &&
+ value <= VALUE_NON_IGNORABLE)
+ return true;
+ break;
+ case CASE_FIRST :
+ if (value >= VALUE_LOWER_FIRST &&
+ value <= VALUE_UPPER_FIRST)
+ return true;
+ break;
+ case CASE_LEVEL :
+ return (value == VALUE_ON ||
+ value <= VALUE_OFF);
+ case NORMALIZATION_MODE :
+ return (value == VALUE_OFF || value == VALUE_ON ||
+ value == VALUE_ON_WITHOUT_HANGUL);
+ case STRENGTH :
+ checkStrength(value);
+ }
+ return false;
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java b/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java
new file mode 100644
index 0000000..0f5bae4
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java
@@ -0,0 +1,230 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+
+
+/**
+* Collation element iterator JNI wrapper.
+* Iterates over the collation elements of a data string.
+* The iterator supports both forward and backwards full iteration, ie if
+* backwards iteration is performed in the midst of a forward iteration, the
+* result is undefined.
+* To perform a backwards iteration in the midst of a forward iteration,
+* reset() has to be called.
+* This will shift the position to either the start or the last character in the
+* data string depending on whether next() is called or previous().
+* <pre>
+* RuleBasedCollator coll = Collator.getInstance();
+* CollationElementIterator iterator = coll.getCollationElementIterator("abc");
+* int ce = 0;
+* while (ce != CollationElementIterator.NULLORDER) {
+* ce = iterator.next();
+* }
+* iterator.reset();
+* while (ce != CollationElementIterator.NULLORDER) {
+* ce = iterator.previous();
+* }
+* </pre>
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class CollationElementIterator
+{
+ // public data member -------------------------------------------
+
+ /**
+ * @stable ICU 2.4
+ */
+ public static final int NULLORDER = 0xFFFFFFFF;
+
+ // public methods -----------------------------------------------
+
+ /**
+ * Reset the collation elements to their initial state.
+ * This will move the 'cursor' to the beginning of the text.
+ * @stable ICU 2.4
+ */
+ public void reset()
+ {
+ NativeCollation.reset(m_collelemiterator_);
+ }
+
+ /**
+ * Get the ordering priority of the next collation element in the text.
+ * A single character may contain more than one collation element.
+ * @return next collation elements ordering, or NULLORDER if the end of the
+ * text is reached.
+ * @stable ICU 2.4
+ */
+ public int next()
+ {
+ return NativeCollation.next(m_collelemiterator_);
+ }
+
+ /**
+ * Get the ordering priority of the previous collation element in the text.
+ * A single character may contain more than one collation element.
+ * @return previous collation element ordering, or NULLORDER if the end of
+ * the text is reached.
+ * @stable ICU 2.4
+ */
+ public int previous()
+ {
+ return NativeCollation.previous(m_collelemiterator_);
+ }
+
+ /**
+ * Get the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @param order collation order returned by previous or next.
+ * @return maximum size of the expansion sequences ending with the collation
+ * element or 1 if collation element does not occur at the end of
+ * any expansion sequence
+ * @stable ICU 2.4
+ */
+ public int getMaxExpansion(int order)
+ {
+ return NativeCollation.getMaxExpansion(m_collelemiterator_, order);
+ }
+
+ /**
+ * Set the text containing the collation elements.
+ * @param source text containing the collation elements.
+ * @stable ICU 2.4
+ */
+ public void setText(String source)
+ {
+ NativeCollation.setText(m_collelemiterator_, source);
+ }
+
+ // BEGIN android-added
+ public void setText(CharacterIterator source)
+ {
+ NativeCollation.setText(m_collelemiterator_, source.toString());
+ }
+ // END android-added
+
+ /**
+ * Get the offset of the current source character.
+ * This is an offset into the text of the character containing the current
+ * collation elements.
+ * @return offset of the current source character.
+ * @stable ICU 2.4
+ */
+ public int getOffset()
+ {
+ return NativeCollation.getOffset(m_collelemiterator_);
+ }
+
+ /**
+ * Set the offset of the current source character.
+ * This is an offset into the text of the character to be processed.
+ * @param offset The desired character offset.
+ * @stable ICU 2.4
+ */
+ public void setOffset(int offset)
+ {
+ NativeCollation.setOffset(m_collelemiterator_, offset);
+ }
+
+ /**
+ * Gets the primary order of a collation order.
+ * @param order the collation order
+ * @return the primary order of a collation order.
+ * @stable ICU 2.4
+ */
+ public static int primaryOrder(int order)
+ {
+ return ((order & PRIMARY_ORDER_MASK_) >> PRIMARY_ORDER_SHIFT_) &
+ UNSIGNED_16_BIT_MASK_;
+ }
+
+ /**
+ * Gets the secondary order of a collation order.
+ * @param order the collation order
+ * @return the secondary order of a collation order.
+ * @stable ICU 2.4
+ */
+ public static int secondaryOrder(int order)
+ {
+ return (order & SECONDARY_ORDER_MASK_) >> SECONDARY_ORDER_SHIFT_;
+ }
+
+ /**
+ * Gets the tertiary order of a collation order.
+ * @param order the collation order
+ * @return the tertiary order of a collation order.
+ * @stable ICU 2.4
+ */
+ public static int tertiaryOrder(int order)
+ {
+ return order & TERTIARY_ORDER_MASK_;
+ }
+
+ // protected constructor ----------------------------------------
+
+ /**
+ * CollationElementIteratorJNI constructor.
+ * The only caller of this class should be
+ * RuleBasedCollator.getCollationElementIterator().
+ * @param collelemiteratoraddress address of C collationelementiterator
+ */
+ CollationElementIterator(int collelemiteratoraddress)
+ {
+ m_collelemiterator_ = collelemiteratoraddress;
+ }
+
+ // protected methods --------------------------------------------
+
+ /**
+ * Garbage collection.
+ * Close C collator and reclaim memory.
+ * @stable ICU 2.4
+ */
+ protected void finalize()
+ {
+ NativeCollation.closeElements(m_collelemiterator_);
+ }
+
+ // private data members -----------------------------------------
+
+ /**
+ * C collator
+ */
+ private int m_collelemiterator_;
+
+ /**
+ * ICU constant primary order mask for collation elements
+ */
+ private static final int PRIMARY_ORDER_MASK_ = 0xffff0000;
+ /**
+ * ICU constant secondary order mask for collation elements
+ */
+ private static final int SECONDARY_ORDER_MASK_ = 0x0000ff00;
+ /**
+ * ICU constant tertiary order mask for collation elements
+ */
+ private static final int TERTIARY_ORDER_MASK_ = 0x000000ff;
+ /**
+ * ICU constant primary order shift for collation elements
+ */
+ private static final int PRIMARY_ORDER_SHIFT_ = 16;
+ /**
+ * ICU constant secondary order shift for collation elements
+ */
+ private static final int SECONDARY_ORDER_SHIFT_ = 8;
+ /**
+ * Unsigned 16 bit mask
+ */
+ private static final int UNSIGNED_16_BIT_MASK_ = 0x0000FFFF;
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java b/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java
new file mode 100644
index 0000000..7e8a000
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java
@@ -0,0 +1,186 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Collation key wrapper, containing the byte array sort key.
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class CollationKey implements Comparable
+{
+ // public methods -----------------------------------------------
+
+ /**
+ * Bitwise comparison for the collation keys
+ * @param target CollationKey to be compared
+ * @return comparison result from Collator, RESULT_LESS, RESULT_EQUAL,
+ * RESULT_GREATER
+ * @stable ICU 2.4
+ */
+ public int compareTo(CollationKey target)
+ {
+ byte tgtbytes[] = target.m_bytes_;
+
+ if (m_bytes_ == null || m_bytes_.length == 0) {
+ if (tgtbytes == null || tgtbytes.length == 0) {
+ return Collator.RESULT_EQUAL;
+ }
+ return Collator.RESULT_LESS;
+ }
+ else {
+ if (tgtbytes == null || tgtbytes.length == 0) {
+ return Collator.RESULT_GREATER;
+ }
+ }
+
+ int count = m_bytes_.length;
+ if (tgtbytes.length < count) {
+ count = tgtbytes.length;
+ }
+
+ int s,
+ t;
+ for (int i = 0; i < count; i ++)
+ {
+ // unable to use Arrays.equals
+ s = m_bytes_[i] & UNSIGNED_BYTE_MASK_;
+ t = tgtbytes[i] & UNSIGNED_BYTE_MASK_;
+ if (s < t) {
+ return Collator.RESULT_LESS;
+ }
+ if (s > t) {
+ return Collator.RESULT_GREATER;
+ }
+ }
+
+ if (m_bytes_.length < target.m_bytes_.length) {
+ return Collator.RESULT_LESS;
+ }
+
+ if (m_bytes_.length > target.m_bytes_.length) {
+ return Collator.RESULT_GREATER;
+ }
+
+ return Collator.RESULT_EQUAL;
+ }
+
+ /**
+ * Bitwise comparison for the collation keys.
+ * Argument is casted to CollationKey
+ * @param target CollationKey to be compared
+ * @return comparison result from Collator, RESULT_LESS, RESULT_EQUAL,
+ * RESULT_GREATER
+ * @stable ICU 2.4
+ */
+ public int compareTo(Object target)
+ {
+ return compareTo((CollationKey)target);
+ }
+
+ /**
+ * Checks if target object is equal to this object.
+ * Target is first casted to CollationKey and bitwise compared.
+ * @param target comparison object
+ * @return true if both objects are equal, false otherwise
+ * @stable ICU 2.4
+ */
+ public boolean equals(Object target)
+ {
+ if (this == target) {
+ return true;
+ }
+
+ // checks getClass here since CollationKey is final not subclassable
+ if (target == null || target.getClass() != getClass()) {
+ return false;
+ }
+
+ return compareTo((CollationKey)target) == Collator.RESULT_EQUAL;
+ }
+
+ /**
+ * Creates a hash code for this CollationKey.
+ * Compute the hash by iterating sparsely over about 32 (up to 63) bytes
+ * spaced evenly through the string. For each byte, multiply the previous
+ * hash value by a prime number and add the new byte in, like a linear
+ * congruential random number generator, producing a pseudorandom
+ * deterministic value well distributed over the output range.
+ * @return hash value of collation key. Hash value is never 0.
+ * @stable ICU 2.4
+ */
+ public int hashCode()
+ {
+ if (m_hash_ == 0)
+ {
+ if (m_bytes_ != null || m_bytes_.length != 0)
+ {
+ int len = m_bytes_.length;
+ int inc = ((len - 32) / 32) + 1;
+ for (int i = 0; i < len;)
+ {
+ m_hash_ = (m_hash_ * 37) + m_bytes_[i];
+ i += inc;
+ }
+ }
+ if (m_hash_ == 0)
+ m_hash_ = 1;
+ }
+ return m_hash_;
+ }
+
+ /**
+ * Create the value of the Collation key in term of bytes
+ * @return value of Collation key in bytes
+ * @stable ICU 2.4
+ */
+ public byte[] toByteArray()
+ {
+ if (m_bytes_ == null || m_bytes_.length == 0)
+ return null;
+
+ return (byte[])m_bytes_.clone();
+ }
+
+ // package constructors ----------------------------------------------
+
+ /**
+ * Default constructor, for use by the Collator and its subclasses.
+ */
+ CollationKey()
+ {
+ m_hash_ = 0;
+ }
+
+ /**
+ * Constructor, for use only by the Collator and its subclasses.
+ */
+ CollationKey(byte[] bytes)
+ {
+ m_bytes_ = bytes;
+ m_hash_ = 0;
+ }
+
+ // private data members -----------------------------------------------
+
+ private byte m_bytes_[];
+
+ /**
+ * Mask value to retrieve a single unsigned byte
+ */
+ private static final int UNSIGNED_BYTE_MASK_ = 0x00FF;
+
+ /**
+ * Cached hash value
+ */
+ private int m_hash_;
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/Collator.java b/icu/src/main/java/com/ibm/icu4jni/text/Collator.java
new file mode 100644
index 0000000..4a7e1bf
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/Collator.java
@@ -0,0 +1,431 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.util.Locale;
+import com.ibm.icu4jni.text.RuleBasedCollator;
+
+/**
+* Abstract class handling locale specific collation via JNI and ICU.
+* Subclasses implement specific collation strategies. One subclass,
+* com.ibm.icu4jni.text.RuleBasedCollator, is currently provided and is
+* applicable to a wide set of languages. Other subclasses may be created to
+* handle more specialized needs.
+* You can use the static factory method, getInstance(), to obtain the
+* appropriate Collator object for a given locale.
+*
+* <pre>
+* // Compare two strings in the default locale
+* Collator myCollator = Collator.getInstance();
+* if (myCollator.compare("abc", "ABC") < 0) {
+* System.out.println("abc is less than ABC");
+* }
+* else {
+* System.out.println("abc is greater than or equal to ABC");
+* }
+* </pre>
+*
+* You can set a Collator's strength property to determine the level of
+* difference considered significant in comparisons.
+* Five strengths in CollationAttribute are provided: VALUE_PRIMARY,
+* VALUE_SECONDARY, VALUE_TERTIARY, VALUE_QUARTENARY and VALUE_IDENTICAL.
+* The exact assignment of strengths to language features is locale dependant.
+* For example, in Czech, "e" and "f" are considered primary differences, while
+* "e" and "?" latin small letter e with circumflex are secondary differences,
+* "e" and "E" are tertiary differences and "e" and "e" are identical.
+*
+* <p>
+* The following shows how both case and accents could be ignored for US
+* English.
+* <pre>
+* //Get the Collator for US English and set its strength to PRIMARY
+* Collator usCollator = Collator.getInstance(Locale.US);
+* usCollator.setStrength(Collator.PRIMARY);
+* if (usCollator.compare("abc", "ABC") == 0) {
+* System.out.println("Strings are equivalent");
+* }
+* </pre>
+* For comparing Strings exactly once, the compare method provides the best
+* performance.
+* When sorting a list of Strings however, it is generally necessary to compare
+* each String multiple times.
+* In this case, com.ibm.icu4jni.text.CollationKey provide better performance.
+* The CollationKey class converts a String to a series of bits that can be
+* compared bitwise against other CollationKeys.
+* A CollationKey is created by a Collator object for a given String.
+* Note: CollationKeys from different Collators can not be compared.
+* </p>
+*
+* Considerations :
+* 1) ErrorCode not returned to user throw exceptions instead
+* 2) Similar API to java.text.Collator
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public abstract class Collator implements Cloneable
+{
+ // public data members ---------------------------------------------------
+
+ /**
+ * Strongest collator strength value. Typically used to denote differences
+ * between base characters. See class documentation for more explanation.
+ * @see #setStrength
+ * @see #getStrength
+ * @stable ICU 2.4
+ */
+ public final static int PRIMARY = CollationAttribute.VALUE_PRIMARY;
+
+ /**
+ * Second level collator strength value.
+ * Accents in the characters are considered secondary differences.
+ * Other differences between letters can also be considered secondary
+ * differences, depending on the language.
+ * See class documentation for more explanation.
+ * @see #setStrength
+ * @see #getStrength
+ * @stable ICU 2.4
+ */
+ public final static int SECONDARY = CollationAttribute.VALUE_SECONDARY;
+
+ /**
+ * Third level collator strength value.
+ * Upper and lower case differences in characters are distinguished at this
+ * strength level. In addition, a variant of a letter differs from the base
+ * form on the tertiary level.
+ * See class documentation for more explanation.
+ * @see #setStrength
+ * @see #getStrength
+ * @stable ICU 2.4
+ */
+ public final static int TERTIARY = CollationAttribute.VALUE_TERTIARY;
+
+ /**
+ * Fourth level collator strength value.
+ * When punctuation is ignored
+ * <a href="http://www-124.ibm.com/icu/userguide/Collate_Concepts.html#Ignoring_Punctuation">
+ * (see Ignoring Punctuations in the user guide)</a> at PRIMARY to TERTIARY
+ * strength, an additional strength level can
+ * be used to distinguish words with and without punctuation.
+ * See class documentation for more explanation.
+ * @see #setStrength
+ * @see #getStrength
+ * @stable ICU 2.4
+ */
+ public final static int QUATERNARY = CollationAttribute.VALUE_QUATERNARY;
+
+ /**
+ * <p>
+ * Smallest Collator strength value. When all other strengths are equal,
+ * the IDENTICAL strength is used as a tiebreaker. The Unicode code point
+ * values of the NFD form of each string are compared, just in case there
+ * is no difference.
+ * See class documentation for more explanation.
+ * </p>
+ * <p>
+ * Note this value is different from JDK's
+ * </p>
+ * @stable ICU 2.4
+ */
+ public final static int IDENTICAL = CollationAttribute.VALUE_IDENTICAL;
+
+ /**
+ * <p>Decomposition mode value. With NO_DECOMPOSITION set, Strings
+ * will not be decomposed for collation. This is the default
+ * decomposition setting unless otherwise specified by the locale
+ * used to create the Collator.</p>
+ *
+ * <p><strong>Note</strong> this value is different from the JDK's.</p>
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #getDecomposition
+ * @see #setDecomposition
+ * @stable ICU 2.4
+ */
+ public final static int NO_DECOMPOSITION = CollationAttribute.VALUE_OFF;
+
+ /**
+ * <p>Decomposition mode value. With CANONICAL_DECOMPOSITION set,
+ * characters that are canonical variants according to the Unicode standard
+ * will be decomposed for collation.</p>
+ *
+ * <p>CANONICAL_DECOMPOSITION corresponds to Normalization Form D as
+ * described in <a href="http://www.unicode.org/unicode/reports/tr15/">
+ * Unicode Technical Report #15</a>.
+ * </p>
+ * @see #NO_DECOMPOSITION
+ * @see #getDecomposition
+ * @see #setDecomposition
+ * @stable ICU 2.4
+ */
+ public final static int CANONICAL_DECOMPOSITION
+ = CollationAttribute.VALUE_ON;
+
+ // Collation result constants -----------------------------------
+ // corresponds to ICU's UCollationResult enum balues
+ /**
+ * string a == string b
+ * @stable ICU 2.4
+ */
+ public static final int RESULT_EQUAL = 0;
+ /**
+ * string a > string b
+ * @stable ICU 2.4
+ */
+ public static final int RESULT_GREATER = 1;
+ /**
+ * string a < string b
+ * @stable ICU 2.4
+ */
+ public static final int RESULT_LESS = -1;
+ /**
+ * accepted by most attributes
+ * @stable ICU 2.4
+ */
+ public static final int RESULT_DEFAULT = -1;
+
+ // public methods -----------------------------------------------
+
+ /**
+ * Factory method to create an appropriate Collator which uses the default
+ * locale collation rules.
+ * Current implementation createInstance() returns a RuleBasedCollator(Locale)
+ * instance. The RuleBasedCollator will be created in the following order,
+ * <ul>
+ * <li> Data from argument locale resource bundle if found, otherwise
+ * <li> Data from parent locale resource bundle of arguemtn locale if found,
+ * otherwise
+ * <li> Data from built-in default collation rules if found, other
+ * <li> null is returned
+ * </ul>
+ * @return an instance of Collator
+ * @stable ICU 2.4
+ */
+ public static Collator getInstance()
+ {
+ return getInstance(null);
+ }
+
+ /**
+ * Factory method to create an appropriate Collator which uses the argument
+ * locale collation rules.<br>
+ * Current implementation createInstance() returns a RuleBasedCollator(Locale)
+ * instance. The RuleBasedCollator will be created in the following order,
+ * <ul>
+ * <li> Data from argument locale resource bundle if found, otherwise
+ * <li> Data from parent locale resource bundle of arguemtn locale if found,
+ * otherwise
+ * <li> Data from built-in default collation rules if found, other
+ * <li> null is returned
+ * </ul>
+ * @param locale to be used for collation
+ * @return an instance of Collator
+ * @stable ICU 2.4
+ */
+ public static Collator getInstance(Locale locale)
+ {
+ RuleBasedCollator result = new RuleBasedCollator(locale);
+ return result;
+ }
+
+ /**
+ * Locale dependent equality check for the argument strings.
+ * @param source string
+ * @param target string
+ * @return true if source is equivalent to target, false otherwise
+ * @stable ICU 2.4
+ */
+ public boolean equals(String source, String target)
+ {
+ return (compare(source, target) == RESULT_EQUAL);
+ }
+
+ /**
+ * Checks if argument object is equals to this object.
+ * @param target object
+ * @return true if source is equivalent to target, false otherwise
+ * @stable ICU 2.4
+ */
+ public abstract boolean equals(Object target);
+
+ /**
+ * Makes a copy of the current object.
+ * @return a copy of this object
+ * @stable ICU 2.4
+ */
+ public abstract Object clone() throws CloneNotSupportedException;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different strings. Returns information about whether a string is less
+ * than, greater than or equal to another string.
+ * <p>Example of use:
+ * <pre>
+ * . Collator myCollation = Collator.getInstance(Locale::US);
+ * . myCollation.setStrength(CollationAttribute.VALUE_PRIMARY);
+ * . // result would be CollationAttribute.VALUE_EQUAL
+ * . // ("abc" == "ABC")
+ * . // (no primary difference between "abc" and "ABC")
+ * . int result = myCollation.compare("abc", "ABC",3);
+ * . myCollation.setStrength(CollationAttribute.VALUE_TERTIARY);
+ * . // result would be Collation.LESS (abc" &lt;&lt;&lt; "ABC")
+ * . // (with tertiary difference between "abc" and "ABC")
+ * . int result = myCollation.compare("abc", "ABC",3);
+ * </pre>
+ * @param source source string.
+ * @param target target string.
+ * @return result of the comparison, Collator.RESULT_EQUAL,
+ * Collator.RESULT_GREATER or Collator.RESULT_LESS
+ * @stable ICU 2.4
+ */
+ public abstract int compare(String source, String target);
+
+ /**
+ * Get the decomposition mode of this Collator.
+ * @return the decomposition mode
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #NO_DECOMPOSITION
+ * @stable ICU 2.4
+ */
+ public abstract int getDecomposition();
+
+ /**
+ * Set the normalization mode used int this object
+ * The normalization mode influences how strings are compared.
+ * @param mode desired normalization mode
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #NO_DECOMPOSITION
+ * @stable ICU 2.4
+ */
+ public abstract void setDecomposition(int mode);
+
+ /**
+ * Determines the minimum strength that will be use in comparison or
+ * transformation.
+ * <p>
+ * E.g. with strength == SECONDARY, the tertiary difference is ignored
+ * </p>
+ * <p>
+ * E.g. with strength == PRIMARY, the secondary and tertiary difference
+ * are ignored.
+ * </p>
+ * @return the current comparison level.
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @stable ICU 2.4
+ */
+ public abstract int getStrength();
+
+ /**
+ * Gets the attribute to be used in comparison or transformation.
+ * @param type the attribute to be set from CollationAttribute
+ * @return value attribute value from CollationAttribute
+ * @stable ICU 2.4
+ */
+ public abstract int getAttribute(int type);
+
+ /**
+ * Sets the minimum strength to be used in comparison or transformation.
+ * <p>Example of use:
+ * <pre>
+ * . Collator myCollation = Collator.createInstance(Locale::US);
+ * . myCollation.setStrength(PRIMARY);
+ * . // result will be "abc" == "ABC"
+ * . // tertiary differences will be ignored
+ * . int result = myCollation->compare("abc", "ABC");
+ * </pre>
+ * @param strength the new comparison level.
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @stable ICU 2.4
+ */
+ public abstract void setStrength(int strength);
+
+ /**
+ * Sets the attribute to be used in comparison or transformation.
+ * <p>Example of use:
+ * <pre>
+ * . Collator myCollation = Collator.createInstance(Locale::US);
+ * . myCollation.setAttribute(CollationAttribute.CASE_LEVEL,
+ * . CollationAttribute.VALUE_ON);
+ * . int result = myCollation->compare("\\u30C3\\u30CF",
+ * . "\\u30C4\\u30CF");
+ * . // result will be Collator.RESULT_LESS.
+ * </pre>
+ * @param type the attribute to be set from CollationAttribute
+ * @param value attribute value from CollationAttribute
+ * @stable ICU 2.4
+ */
+ public abstract void setAttribute(int type, int value);
+
+ /**
+ * Get the sort key as an CollationKey object from the argument string.
+ * To retrieve sort key in terms of byte arrays, use the method as below<br>
+ * <code>
+ * Collator collator = Collator.getInstance();
+ * CollationKey collationkey = collator.getCollationKey("string");
+ * byte[] array = collationkey.toByteArray();
+ * </code><br>
+ * Byte array result are zero-terminated and can be compared using
+ * java.util.Arrays.equals();
+ * @param source string to be processed.
+ * @return the sort key
+ * @stable ICU 2.4
+ */
+ public abstract CollationKey getCollationKey(String source);
+
+ /**
+ * Returns a hash of this collation object
+ * @return hash of this collation object
+ * @stable ICU 2.4
+ */
+ public abstract int hashCode();
+
+ // BEGIN android-added
+ public static Locale[] getAvailableLocales() {
+
+ String[] locales = NativeCollation.getAvailableLocalesImpl();
+
+ Locale[] result = new Locale[locales.length];
+
+ String locale;
+
+ int index, index2;
+
+ for(int i = 0; i < locales.length; i++) {
+ locale = locales[i];
+
+ index = locale.indexOf('_');
+ index2 = locale.lastIndexOf('_');
+
+ if(index == -1) {
+ result[i] = new Locale(locales[i]);
+ } else if(index == 2 && index == index2) {
+ result[i] = new Locale(
+ locale.substring(0,2),
+ locale.substring(3,5));
+ } else if(index == 2 && index2 > index) {
+ result[i] = new Locale(
+ locale.substring(0,index),
+ locale.substring(index + 1,index2),
+ locale.substring(index2 + 1));
+ }
+ }
+
+ return result;
+ }
+ // END android-added
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
new file mode 100644
index 0000000..5bee1fd
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
@@ -0,0 +1,568 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatAttribute;
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatTextAttribute;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Currency;
+import java.util.Locale;
+
+public class DecimalFormat extends NumberFormat {
+
+ private int addr;
+
+ private DecimalFormatSymbols symbols;
+
+ // fix to be icu4j conform (harmony wants this field to exist)
+ // for serialization of java.text.DecimalFormat
+ @SuppressWarnings("unused")
+ private boolean useExponentialNotation = false;
+ @SuppressWarnings("unused")
+ private byte minExponentDigits = 0;
+
+ private boolean negPrefNull;
+ private boolean negSuffNull;
+ private boolean posPrefNull;
+ private boolean posSuffNull;
+
+ public DecimalFormat(String pattern, DecimalFormatSymbols icuSymbols) {
+ this.addr = icuSymbols.getAddr();
+ this.symbols = icuSymbols;
+ applyPattern(pattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() * 37 + this.getPositivePrefix().hashCode();
+ }
+
+ @Override
+ public Object clone() {
+ String pat = this.toPattern();
+ Locale loc = this.symbols.getLocale();
+ DecimalFormatSymbols sym = (DecimalFormatSymbols) this.symbols.clone();
+ DecimalFormat newdf = new DecimalFormat(pat, sym);
+ newdf.setMaximumIntegerDigits(this.getMaximumIntegerDigits());
+ newdf.setMaximumFractionDigits(this.getMaximumFractionDigits());
+ newdf.setMinimumIntegerDigits(this.getMinimumIntegerDigits());
+ newdf.setMinimumFractionDigits(this.getMinimumFractionDigits());
+ newdf.setGroupingUsed(this.isGroupingUsed());
+ newdf.setGroupingSize(this.getGroupingSize());
+ return newdf;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof DecimalFormat)) {
+ return false;
+ }
+ DecimalFormat obj = (DecimalFormat) object;
+
+ if(obj.addr == this.addr) {
+ return true;
+ }
+
+ boolean result = super.equals(object);
+
+
+ result &= obj.toPattern().equals(this.toPattern());
+ result &= obj.isDecimalSeparatorAlwaysShown() == this.isDecimalSeparatorAlwaysShown();
+ result &= obj.getGroupingSize() == this.getGroupingSize();
+ result &= obj.getMultiplier() == this.getMultiplier();
+ result &= obj.getNegativePrefix().equals(this.getNegativePrefix());
+ result &= obj.getNegativeSuffix().equals(this.getNegativeSuffix());
+ result &= obj.getPositivePrefix().equals(this.getPositivePrefix());
+ result &= obj.getPositiveSuffix().equals(this.getPositiveSuffix());
+ result &= obj.getMaximumIntegerDigits() == this.getMaximumIntegerDigits();
+ result &= obj.getMaximumFractionDigits() == this.getMaximumFractionDigits();
+ result &= obj.getMinimumIntegerDigits() == this.getMinimumIntegerDigits();
+ result &= obj.getMinimumFractionDigits() == this.getMinimumFractionDigits();
+ result &= obj.isGroupingUsed() == this.isGroupingUsed();
+ Currency objCurr = obj.getCurrency();
+ Currency thisCurr = this.getCurrency();
+ if(objCurr != null) {
+ result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
+ result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
+ result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
+ } else {
+ result &= thisCurr == null;
+ }
+ result &= obj.getDecimalFormatSymbols().equals(this.getDecimalFormatSymbols());
+
+ return result;
+ }
+
+ @Override
+ public StringBuffer format(Object value, StringBuffer buffer, FieldPosition field) {
+
+ if(!(value instanceof Number)) {
+ throw new IllegalArgumentException();
+ }
+ if(buffer == null || field == null) {
+ throw new NullPointerException();
+ }
+
+ String fieldType = getFieldType(field.getFieldAttribute());
+
+ Number number = (Number) value;
+
+ if(number instanceof BigInteger) {
+ BigInteger valBigInteger = (BigInteger) number;
+ String result = NativeDecimalFormat.format(this.addr,
+ valBigInteger.toString(10), field, fieldType, null, 0);
+ return buffer.append(result);
+ } else if(number instanceof BigDecimal) {
+ BigDecimal valBigDecimal = (BigDecimal) number;
+ StringBuilder val = new StringBuilder();
+ val.append(valBigDecimal.unscaledValue().toString(10));
+ int scale = valBigDecimal.scale();
+ scale = makeScalePositive(scale, val);
+ String result = NativeDecimalFormat.format(this.addr,
+ val.toString(), field, fieldType, null, scale);
+ return buffer.append(result);
+ } else {
+ double dv = number.doubleValue();
+ long lv = number.longValue();
+ if (dv == lv) {
+ String result = NativeDecimalFormat.format(this.addr, lv, field,
+ fieldType, null);
+ return buffer.append(result);
+ }
+ String result = NativeDecimalFormat.format(this.addr, dv, field,
+ fieldType, null);
+ return buffer.append(result);
+ }
+ }
+
+ @Override
+ public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
+
+ if(buffer == null || field == null) {
+ throw new NullPointerException();
+ }
+
+ String fieldType = getFieldType(field.getFieldAttribute());
+
+ String result = NativeDecimalFormat.format(this.addr, value, field,
+ fieldType, null);
+
+ buffer.append(result.toCharArray(), 0, result.length());
+
+ return buffer;
+ }
+
+ @Override
+ public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
+
+ if(buffer == null || field == null) {
+ throw new NullPointerException();
+ }
+
+ String fieldType = getFieldType(field.getFieldAttribute());
+
+ String result = NativeDecimalFormat.format(this.addr, value, field,
+ fieldType, null);
+
+ buffer.append(result.toCharArray(), 0, result.length());
+
+ return buffer;
+ }
+
+ public void applyLocalizedPattern(String pattern) {
+ if (pattern == null) {
+ throw new NullPointerException("pattern was null");
+ }
+ try {
+ NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
+ } catch(RuntimeException re) {
+ throw new IllegalArgumentException(
+ "applying localized pattern failed for pattern: " + pattern, re);
+ }
+ }
+
+ public void applyPattern(String pattern) {
+ if (pattern == null) {
+ throw new NullPointerException("pattern was null");
+ }
+ try {
+ NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
+ } catch(RuntimeException re) {
+ throw new IllegalArgumentException(
+ "applying pattern failed for pattern: " + pattern, re);
+ }
+ }
+
+ @Override
+ public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+ if (!(object instanceof Number)) {
+ throw new IllegalArgumentException();
+ }
+ Number number = (Number) object;
+ String text = null;
+ StringBuffer attributes = new StringBuffer();
+
+ if(number instanceof BigInteger) {
+ BigInteger valBigInteger = (BigInteger) number;
+ text = NativeDecimalFormat.format(this.addr,
+ valBigInteger.toString(10), null, null, attributes, 0);
+ } else if(number instanceof BigDecimal) {
+ BigDecimal valBigDecimal = (BigDecimal) number;
+ StringBuilder val = new StringBuilder();
+ val.append(valBigDecimal.unscaledValue().toString(10));
+ int scale = valBigDecimal.scale();
+ scale = makeScalePositive(scale, val);
+ text = NativeDecimalFormat.format(this.addr, val.toString(), null,
+ null, attributes, scale);
+ } else {
+ double dv = number.doubleValue();
+ long lv = number.longValue();
+ if (dv == lv) {
+ text = NativeDecimalFormat.format(this.addr, lv, null,
+ null, attributes);
+ } else {
+ text = NativeDecimalFormat.format(this.addr, dv, null,
+ null, attributes);
+ }
+ }
+
+ AttributedString as = new AttributedString(text.toString());
+
+ String[] attrs = attributes.toString().split(";");
+ // add NumberFormat field attributes to the AttributedString
+ int size = attrs.length / 3;
+ if(size * 3 != attrs.length) {
+ return as.getIterator();
+ }
+ for (int i = 0; i < size; i++) {
+ Format.Field attribute = getField(attrs[3*i]);
+ as.addAttribute(attribute, attribute, Integer.parseInt(attrs[3*i+1]),
+ Integer.parseInt(attrs[3*i+2]));
+ }
+
+ // return the CharacterIterator from AttributedString
+ return as.getIterator();
+ }
+
+ private int makeScalePositive(int scale, StringBuilder val) {
+ if (scale < 0) {
+ scale = -scale;
+ for (int i = scale; i > 0; i--) {
+ val.append('0');
+ }
+ scale = 0;
+ }
+ return scale;
+ }
+
+ public String toLocalizedPattern() {
+ return NativeDecimalFormat.toPatternImpl(this.addr, true);
+ }
+
+ public String toPattern() {
+ return NativeDecimalFormat.toPatternImpl(this.addr, false);
+ }
+
+ @Override
+ public Number parse(String string, ParsePosition position) {
+ return NativeDecimalFormat.parse(addr, string, position);
+ }
+
+ // start getter and setter
+
+ @Override
+ public int getMaximumFractionDigits() {
+ return NativeDecimalFormat.getAttribute(this .addr,
+ UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal());
+ }
+
+ @Override
+ public int getMaximumIntegerDigits() {
+ return NativeDecimalFormat.getAttribute(this .addr,
+ UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal());
+ }
+
+ @Override
+ public int getMinimumFractionDigits() {
+ return NativeDecimalFormat.getAttribute(this .addr,
+ UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal());
+ }
+
+ @Override
+ public int getMinimumIntegerDigits() {
+ return NativeDecimalFormat.getAttribute(this .addr,
+ UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal());
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return this.symbols.getCurrency();
+ }
+
+ public int getGroupingSize() {
+ return NativeDecimalFormat.getAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_GROUPING_SIZE.ordinal());
+ }
+
+ public int getMultiplier() {
+ return NativeDecimalFormat.getAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MULTIPLIER.ordinal());
+ }
+
+ public String getNegativePrefix() {
+ if (negPrefNull) {
+ return null;
+ }
+ return NativeDecimalFormat.getTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_NEGATIVE_PREFIX.ordinal());
+ }
+
+ public String getNegativeSuffix() {
+ if (negSuffNull) {
+ return null;
+ }
+ return NativeDecimalFormat.getTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_NEGATIVE_SUFFIX.ordinal());
+ }
+
+ public String getPositivePrefix() {
+ if (posPrefNull) {
+ return null;
+ }
+ return NativeDecimalFormat.getTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_POSITIVE_PREFIX.ordinal());
+ }
+
+ public String getPositiveSuffix() {
+ if (posSuffNull) {
+ return null;
+ }
+ return NativeDecimalFormat.getTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_POSITIVE_SUFFIX.ordinal());
+ }
+
+ public boolean isDecimalSeparatorAlwaysShown() {
+ return NativeDecimalFormat.getAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal()) != 0;
+ }
+
+ @Override
+ public boolean isParseIntegerOnly() {
+ return NativeDecimalFormat.getAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_PARSE_INT_ONLY.ordinal()) != 0;
+ }
+
+ @Override
+ public boolean isGroupingUsed() {
+ return NativeDecimalFormat.getAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal()) != 0;
+ }
+
+ public DecimalFormatSymbols getDecimalFormatSymbols() {
+ return this.symbols;
+ }
+
+ public void setDecimalFormatSymbols(DecimalFormatSymbols icuSymbols) {
+ this.symbols = icuSymbols;
+ }
+
+ public void setDecimalSeparatorAlwaysShown(boolean value) {
+ int i = value ? -1 : 0;
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal(), i);
+ }
+
+ @Override
+ public void setCurrency(Currency currency) {
+ this.symbols.setCurrency(currency);
+ }
+
+ public void setGroupingSize(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_GROUPING_SIZE.ordinal(), value);
+ }
+
+ @Override
+ public void setGroupingUsed(boolean value) {
+ int i = value ? -1 : 0;
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal(), i);
+ }
+
+ @Override
+ public void setMaximumFractionDigits(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal(), value);
+ }
+
+ @Override
+ public void setMaximumIntegerDigits(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal(), value);
+ }
+
+ @Override
+ public void setMinimumFractionDigits(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal(), value);
+ }
+
+ @Override
+ public void setMinimumIntegerDigits(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal(), value);
+ }
+
+ public void setMultiplier(int value) {
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_MULTIPLIER.ordinal(), value);
+ }
+
+ public void setNegativePrefix(String value) {
+ negPrefNull = value == null;
+ if (!negPrefNull) {
+ NativeDecimalFormat.setTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_NEGATIVE_PREFIX.ordinal(),
+ value);
+ }
+ }
+
+ public void setNegativeSuffix(String value) {
+ negSuffNull = value == null;
+ if (!negSuffNull) {
+ NativeDecimalFormat.setTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_NEGATIVE_SUFFIX.ordinal(),
+ value);
+ }
+ }
+
+ public void setPositivePrefix(String value) {
+ posPrefNull = value == null;
+ if (!posPrefNull) {
+ NativeDecimalFormat.setTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_POSITIVE_PREFIX.ordinal(),
+ value);
+ }
+ }
+
+ public void setPositiveSuffix(String value) {
+ posSuffNull = value == null;
+ if (!posSuffNull) {
+ NativeDecimalFormat.setTextAttribute(this.addr,
+ UNumberFormatTextAttribute.UNUM_POSITIVE_SUFFIX.ordinal(),
+ value);
+ }
+ }
+
+ @Override
+ public void setParseIntegerOnly(boolean value) {
+ int i = value ? -1 : 0;
+ NativeDecimalFormat.setAttribute(this.addr,
+ UNumberFormatAttribute.UNUM_PARSE_INT_ONLY.ordinal(), i);
+ }
+
+ static protected String getFieldType(Format.Field field) {
+ if(field == null) {
+ return null;
+ }
+ if(field.equals(NumberFormat.Field.SIGN)) {
+ return "sign";
+ }
+ if(field.equals(NumberFormat.Field.INTEGER)) {
+ return "integer";
+ }
+ if(field.equals(NumberFormat.Field.FRACTION)) {
+ return "fraction";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT)) {
+ return "exponent";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT_SIGN)) {
+ return "exponent_sign";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT_SYMBOL)) {
+ return "exponent_symbol";
+ }
+ if(field.equals(NumberFormat.Field.CURRENCY)) {
+ return "currency";
+ }
+ if(field.equals(NumberFormat.Field.GROUPING_SEPARATOR)) {
+ return "grouping_separator";
+ }
+ if(field.equals(NumberFormat.Field.DECIMAL_SEPARATOR)) {
+ return "decimal_separator";
+ }
+ if(field.equals(NumberFormat.Field.PERCENT)) {
+ return "percent";
+ }
+ if(field.equals(NumberFormat.Field.PERMILLE)) {
+ return "permille";
+ }
+ return null;
+ }
+
+ protected Format.Field getField(String type) {
+ if(type.equals("")) {
+ return null;
+ }
+ if(type.equals("sign")) {
+ return NumberFormat.Field.SIGN;
+ }
+ if(type.equals("integer")) {
+ return NumberFormat.Field.INTEGER;
+ }
+ if(type.equals("fraction")) {
+ return NumberFormat.Field.FRACTION;
+ }
+ if(type.equals("exponent")) {
+ return NumberFormat.Field.EXPONENT;
+ }
+ if(type.equals("exponent_sign")) {
+ return NumberFormat.Field.EXPONENT_SIGN;
+ }
+ if(type.equals("exponent_symbol")) {
+ return NumberFormat.Field.EXPONENT_SYMBOL;
+ }
+ if(type.equals("currency")) {
+ return NumberFormat.Field.CURRENCY;
+ }
+ if(type.equals("grouping_separator")) {
+ return NumberFormat.Field.GROUPING_SEPARATOR;
+ }
+ if(type.equals("decimal_separator")) {
+ return NumberFormat.Field.DECIMAL_SEPARATOR;
+ }
+ if(type.equals("percent")) {
+ return NumberFormat.Field.PERCENT;
+ }
+ if(type.equals("permille")) {
+ return NumberFormat.Field.PERMILLE;
+ }
+ return null;
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
new file mode 100644
index 0000000..98463e4
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatSymbol;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class DecimalFormatSymbols {
+
+ private int addr;
+
+ private Locale loc;
+
+ private DecimalFormatSymbols(int addr, Locale loc) {
+ this.addr = addr;
+ this.loc = loc;
+ }
+
+ public DecimalFormatSymbols(Locale locale) {
+ this.loc = locale;
+ ResourceBundle bundle = AccessController.
+ doPrivileged(new PrivilegedAction<ResourceBundle>() {
+ public ResourceBundle run() {
+ return ResourceBundle.getBundle(
+ "org.apache.harmony.luni.internal.locale.Locale", loc); //$NON-NLS-1$
+ }
+ });
+ String pattern = bundle.getString("Number");
+ this.addr = NativeDecimalFormat.openDecimalFormatImpl(
+ locale.toString(), pattern);
+ String currSymbol = bundle.getString("CurrencySymbol");
+ String intCurrSymbol = bundle.getString("IntCurrencySymbol");
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), currSymbol);
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(),
+ intCurrSymbol);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if(object == null) {
+ return false;
+ }
+ if(!(object instanceof DecimalFormatSymbols)) {
+ return false;
+ }
+
+ DecimalFormatSymbols sym = (DecimalFormatSymbols) object;
+
+ if(sym.addr == this.addr) {
+ return true;
+ }
+
+ boolean result = true;
+
+ Currency objCurr = sym.getCurrency();
+ Currency thisCurr = this.getCurrency();
+ if(objCurr != null) {
+ result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
+ result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
+ result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
+ } else {
+ result &= thisCurr == null;
+ }
+ result &= sym.getCurrencySymbol().equals(this.getCurrencySymbol());
+ result &= sym.getDecimalSeparator() == this.getDecimalSeparator();
+ result &= sym.getDigit() == this.getDigit();
+ result &= sym.getGroupingSeparator() == this.getGroupingSeparator();
+ result &= sym.getInfinity().equals(this.getInfinity());
+ result &= sym.getInternationalCurrencySymbol().equals(
+ this.getInternationalCurrencySymbol());
+ result &= sym.getMinusSign() == this.getMinusSign();
+ result &= sym.getMonetaryDecimalSeparator() ==
+ this.getMonetaryDecimalSeparator();
+ result &= sym.getNaN().equals(this.getNaN());
+ result &= sym.getPatternSeparator() == this.getPatternSeparator();
+ result &= sym.getPercent() == this.getPercent();
+ result &= sym.getPerMill() == this.getPerMill();
+ result &= sym.getZeroDigit() == this.getZeroDigit();
+
+ return result;
+ }
+
+ @Override
+ public Object clone() {
+ int addr = NativeDecimalFormat.cloneImpl(this.addr);
+ Locale loc = (Locale) this.loc.clone();
+ return new DecimalFormatSymbols(addr, loc);
+ }
+
+ public void setCurrency(Currency currency) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(),
+ currency.getSymbol());
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(),
+ currency.getCurrencyCode());
+ }
+
+ public void setCurrencySymbol(String symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(),
+ symbol);
+ }
+
+ public void setDecimalSeparator(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_DECIMAL_SEPARATOR_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setDigit(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_DIGIT_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setGroupingSeparator(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_GROUPING_SEPARATOR_SYMBOL.ordinal(),
+ "" + symbol);
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setInfinity(String symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INFINITY_SYMBOL.ordinal(),
+ symbol);
+ }
+
+ public void setInternationalCurrencySymbol(String symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(),
+ symbol);
+ }
+
+ public void setMinusSign(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_MINUS_SIGN_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setMonetaryDecimalSeparator(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_MONETARY_SEPARATOR_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setNaN(String symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_NAN_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setPatternSeparator(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PATTERN_SEPARATOR_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setPercent(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PERCENT_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setPerMill(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PERMILL_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public void setZeroDigit(char symbol) {
+ NativeDecimalFormat.setSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_ZERO_DIGIT_SYMBOL.ordinal(),
+ "" + symbol);
+ }
+
+ public Currency getCurrency() {
+ String curr = NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal());
+ if(curr.equals("") || curr.equals("\u00a4\u00a4")) {
+ return null;
+ }
+ return Currency.getInstance(curr);
+ }
+
+ public String getCurrencySymbol() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal());
+ }
+
+ public char getDecimalSeparator() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_DECIMAL_SEPARATOR_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getDigit() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_DIGIT_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getGroupingSeparator() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_GROUPING_SEPARATOR_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public String getInfinity() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INFINITY_SYMBOL.ordinal());
+ }
+
+ public String getInternationalCurrencySymbol() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal());
+ }
+
+ public char getMinusSign() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_MINUS_SIGN_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getMonetaryDecimalSeparator() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_MONETARY_SEPARATOR_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public String getNaN() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_NAN_SYMBOL.ordinal());
+ }
+
+ public char getPatternSeparator() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PATTERN_SEPARATOR_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getPercent() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PERCENT_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getPerMill() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_PERMILL_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ public char getZeroDigit() {
+ return NativeDecimalFormat.getSymbol(this.addr,
+ UNumberFormatSymbol.UNUM_ZERO_DIGIT_SYMBOL.ordinal())
+ .charAt(0);
+ }
+
+ int getAddr() {
+ return this.addr;
+ }
+
+ Locale getLocale() {
+ return this.loc;
+ }
+
+ protected void finalize() {
+ NativeDecimalFormat.closeDecimalFormatImpl(this.addr);
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java b/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java
new file mode 100644
index 0000000..25249c7
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+final class NativeBreakIterator
+{
+ public NativeBreakIterator() {
+
+ }
+
+ static String[] getAvailableLocalesImpl() {
+ int count = getAvailableLocalesCountImpl();
+ String[] result = new String[count];
+
+ for(int i = 0; i < count; i++) {
+ result[i] = getAvailableLocalesImpl(i);
+ }
+ return result;
+ }
+
+ private static native String getAvailableLocalesImpl(int i);
+
+ private static native int getAvailableLocalesCountImpl();
+
+ static native int getCharacterInstanceImpl(String locale);
+
+ static native int getWordInstanceImpl(String locale);
+
+ static native int getLineInstanceImpl(String locale);
+
+ static native int getSentenceInstanceImpl(String locale);
+
+ static native void closeBreakIteratorImpl(int biaddress);
+
+ static native void setTextImpl(int biaddress, String text);
+
+ static native int cloneImpl(int biaddress);
+
+ static native int precedingImpl(int biaddress, int offset);
+
+ static native boolean isBoundaryImpl(int biaddress, int offset);
+
+ static native int nextImpl(int biaddress, int n);
+
+ static native int previousImpl(int biaddress);
+
+ static native int currentImpl(int biaddress);
+
+ static native int firstImpl(int biaddress);
+
+ static native int followingImpl(int biaddress, int offset);
+
+ static native int lastImpl(int biaddress);
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java b/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java
new file mode 100644
index 0000000..2242b69
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java
@@ -0,0 +1,263 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Package static class for declaring all native methods for collation use.
+* @author syn wee quek
+* @internal ICU 2.4
+*/
+
+final class NativeCollation
+{
+ // collator methods ---------------------------------------------
+
+ public NativeCollation() {
+
+ }
+
+ /**
+ * Method to create a new C Collator using the default locale rules.
+ * @return new c collator
+ * @internal ICU 2.4
+ */
+ static native int openCollator();
+
+ /**
+ * Method to create a new C Collator using the argument locale rules.
+ * @param locale locale name
+ * @return new c collator
+ * @internal ICU 2.4
+ */
+ static native int openCollator(String locale);
+
+ /**
+ * Method to create a new C Collator using the argument rules.
+ * @param rules , set of collation rules
+ * @param normalizationmode default normalization mode
+ * @param collationstrength default collation strength
+ * @return new c collator
+ * @internal ICU 2.4
+ */
+ static native int openCollatorFromRules(String rules,
+ int normalizationmode,
+ int collationstrength);
+
+ /**
+ * Close a C collator
+ * Once closed, a UCollatorOld should not be used.
+ * @param collatoraddress The UCollatorOld to close
+ * @internal ICU 2.4
+ */
+ static native void closeCollator(int collatoraddress);
+
+ /**
+ * Compare two strings.
+ * The strings will be compared using the normalization mode and options
+ * specified in openCollator or openCollatorFromRules
+ * @param collatoraddress address of the c collator
+ * @param source The source string.
+ * @param target The target string.
+ * @return result of the comparison, Collation.EQUAL,
+ * Collation.GREATER or Collation.LESS
+ * @internal ICU 2.4
+ */
+ static native int compare(int collatoraddress, String source,
+ String target);
+
+ /**
+ * Get the normalization mode for this object.
+ * The normalization mode influences how strings are compared.
+ * @param collatoraddress
+ * @return normalization mode; one of the values from Normalization
+ * @internal ICU 2.4
+ */
+ static native int getNormalization(int collatoraddress);
+
+ /**
+ * Set the normalization mode used int this object
+ * The normalization mode influences how strings are compared.
+ * @param collatoraddress the address of the C collator
+ * @param normalizationmode desired normalization mode; one of the values
+ * from Normalization
+ * @internal ICU 2.4
+ */
+ static native void setNormalization(int collatoraddress,
+ int normalizationmode);
+
+ /**
+ * Get the collation rules from a UCollator.
+ * The rules will follow the rule syntax.
+ * @param collatoraddress the address of the C collator
+ * @return collation rules.
+ * @internal ICU 2.4
+ */
+ static native String getRules(int collatoraddress);
+
+ /**
+ * Get a sort key for the argument string
+ * Sort keys may be compared using java.util.Arrays.equals
+ * @param collatoraddress address of the C collator
+ * @param source string for key to be generated
+ * @return sort key
+ * @internal ICU 2.4
+ */
+ static native byte[] getSortKey(int collatoraddress, String source);
+
+ /**
+ * Gets the version information for collation.
+ * @param collatoraddress address of the C collator
+ * @return version information
+ * @internal ICU 2.4
+ */
+ // private native String getVersion(int collatoraddress);
+
+ /**
+ * Universal attribute setter.
+ * @param collatoraddress address of the C collator
+ * @param type type of attribute to be set
+ * @param value attribute value
+ * @exception RuntimeException when error occurs while setting attribute value
+ * @internal ICU 2.4
+ */
+ static native void setAttribute(int collatoraddress, int type, int value);
+
+ /**
+ * Universal attribute getter
+ * @param collatoraddress address of the C collator
+ * @param type type of attribute to be set
+ * @return attribute value
+ * @exception RuntimeException thrown when error occurs while getting attribute value
+ * @internal ICU 2.4
+ */
+ static native int getAttribute(int collatoraddress, int type);
+
+ /**
+ * Thread safe cloning operation
+ * @param collatoraddress address of C collator to be cloned
+ * @return address of the new clone
+ * @exception RuntimeException thrown when error occurs while cloning
+ * @internal ICU 2.4
+ */
+ static native int safeClone(int collatoraddress);
+
+ /**
+ * Create a CollationElementIterator object that will iterator over the
+ * elements in a string, using the collation rules defined in this
+ * RuleBasedCollator
+ * @param collatoraddress address of C collator
+ * @param source string to iterate over
+ * @return address of C collationelementiterator
+ * @internal ICU 2.4
+ */
+ static native int getCollationElementIterator(int collatoraddress,
+ String source);
+
+ /**
+ * Returns a hash of this collation object
+ * @param collatoraddress address of C collator
+ * @return hash of this collation object
+ * @internal ICU 2.4
+ */
+ static native int hashCode(int collatoraddress);
+
+
+ // collationelementiterator methods -------------------------------------
+
+ /**
+ * Close a C collation element iterator.
+ * @param address of C collation element iterator to close.
+ * @internal ICU 2.4
+ */
+ static native void closeElements(int address);
+
+ /**
+ * Reset the collation elements to their initial state.
+ * This will move the 'cursor' to the beginning of the text.
+ * @param address of C collation element iterator to reset.
+ * @internal ICU 2.4
+ */
+ static native void reset(int address);
+
+ /**
+ * Get the ordering priority of the next collation element in the text.
+ * A single character may contain more than one collation element.
+ * @param address if C collation elements containing the text.
+ * @return next collation elements ordering, or NULLORDER if the end of the
+ * text is reached.
+ * @internal ICU 2.4
+ */
+ static native int next(int address);
+
+ /**
+ * Get the ordering priority of the previous collation element in the text.
+ * A single character may contain more than one collation element.
+ * @param address of the C collation element iterator containing the text.
+ * @return previous collation element ordering, or NULLORDER if the end of
+ * the text is reached.
+ * @internal ICU 2.4
+ */
+ static native int previous(int address);
+
+ /**
+ * Get the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @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.
+ * @internal ICU 2.4
+ */
+ static native int getMaxExpansion(int address, int order);
+
+ /**
+ * Set the text containing the collation elements.
+ * @param address of the C collation element iterator to be set
+ * @param source text containing the collation elements.
+ * @internal ICU 2.4
+ */
+ static native void setText(int address, String source);
+
+ /**
+ * Get the offset of the current source character.
+ * This is an offset into the text of the character containing the current
+ * collation elements.
+ * @param address of the C collation elements iterator to query.
+ * @return offset of the current source character.
+ * @internal ICU 2.4
+ */
+ static native int getOffset(int address);
+
+ /**
+ * Set the offset of the current source character.
+ * This is an offset into the text of the character to be processed.
+ * @param address of the C collation element iterator to set.
+ * @param offset The desired character offset.
+ * @internal ICU 2.4
+ */
+ static native void setOffset(int address, int offset);
+
+ // BEGIN android-added
+ static String[] getAvailableLocalesImpl() {
+ int count = getAvailableLocalesCountImpl();
+ String[] result = new String[count];
+
+ for(int i = 0; i < count; i++) {
+ result[i] = getAvailableLocalesImpl(i);
+ }
+ return result;
+ }
+
+ private static native String getAvailableLocalesImpl(int i);
+
+ private static native int getAvailableLocalesCountImpl();
+ // END android-added
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java b/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
new file mode 100644
index 0000000..39f7307
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+
+final class NativeDecimalFormat {
+
+ enum UNumberFormatSymbol {
+ UNUM_DECIMAL_SEPARATOR_SYMBOL,
+ UNUM_GROUPING_SEPARATOR_SYMBOL,
+ UNUM_PATTERN_SEPARATOR_SYMBOL,
+ UNUM_PERCENT_SYMBOL,
+ UNUM_ZERO_DIGIT_SYMBOL,
+ UNUM_DIGIT_SYMBOL,
+ UNUM_MINUS_SIGN_SYMBOL,
+ UNUM_PLUS_SIGN_SYMBOL,
+ UNUM_CURRENCY_SYMBOL,
+ UNUM_INTL_CURRENCY_SYMBOL,
+ UNUM_MONETARY_SEPARATOR_SYMBOL,
+ UNUM_EXPONENTIAL_SYMBOL,
+ UNUM_PERMILL_SYMBOL,
+ UNUM_PAD_ESCAPE_SYMBOL,
+ UNUM_INFINITY_SYMBOL,
+ UNUM_NAN_SYMBOL,
+ UNUM_SIGNIFICANT_DIGIT_SYMBOL,
+ UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL,
+ UNUM_FORMAT_SYMBOL_COUNT
+ }
+
+ enum UNumberFormatAttribute {
+ UNUM_PARSE_INT_ONLY,
+ UNUM_GROUPING_USED,
+ UNUM_DECIMAL_ALWAYS_SHOWN,
+ UNUM_MAX_INTEGER_DIGITS,
+ UNUM_MIN_INTEGER_DIGITS,
+ UNUM_INTEGER_DIGITS,
+ UNUM_MAX_FRACTION_DIGITS,
+ UNUM_MIN_FRACTION_DIGITS,
+ UNUM_FRACTION_DIGITS,
+ UNUM_MULTIPLIER,
+ UNUM_GROUPING_SIZE,
+ UNUM_ROUNDING_MODE,
+ UNUM_ROUNDING_INCREMENT,
+ UNUM_FORMAT_WIDTH,
+ UNUM_PADDING_POSITION,
+ UNUM_SECONDARY_GROUPING_SIZE,
+ UNUM_SIGNIFICANT_DIGITS_USED,
+ UNUM_MIN_SIGNIFICANT_DIGITS,
+ UNUM_MAX_SIGNIFICANT_DIGITS,
+ UNUM_LENIENT_PARSE
+ }
+
+ enum UNumberFormatTextAttribute {
+ UNUM_POSITIVE_PREFIX,
+ UNUM_POSITIVE_SUFFIX,
+ UNUM_NEGATIVE_PREFIX,
+ UNUM_NEGATIVE_SUFFIX,
+ UNUM_PADDING_CHARACTER,
+ UNUM_CURRENCY_CODE,
+ UNUM_DEFAULT_RULESET,
+ UNUM_PUBLIC_RULESETS
+ }
+
+ static native int openDecimalFormatImpl(String locale, String pattern);
+
+ static native void closeDecimalFormatImpl(int addr);
+
+ static native int cloneImpl(int addr);
+
+ static native void setSymbol(int addr, int symbol, String str);
+
+ static native String getSymbol(int addr, int symbol);
+
+ static native void setAttribute(int addr, int symbol, int i);
+
+ static native int getAttribute(int addr, int symbol);
+
+ static native void setTextAttribute(int addr, int symbol, String str);
+
+ static native String getTextAttribute(int addr, int symbol);
+
+ static native void applyPatternImpl(int addr, boolean localized, String pattern);
+
+ static native String toPatternImpl(int addr, boolean localized);
+
+ static native String format(int addr, long value, FieldPosition position, String fieldType, StringBuffer attributes);
+
+ static native String format(int addr, double value, FieldPosition position, String fieldType, StringBuffer attributes);
+
+ static native String format(int addr, String value, FieldPosition position, String fieldType, StringBuffer attributes, int scale);
+
+ static native Number parse(int addr, String string, ParsePosition position);
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java
new file mode 100644
index 0000000..4d38f2b
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+public class RuleBasedBreakIterator extends BreakIterator {
+
+ private CharacterIterator charIter;
+
+ private int addr;
+
+ RuleBasedBreakIterator(int iterAddr, int type) {
+ this.addr = iterAddr;
+ this.type = type;
+ this.charIter = new StringCharacterIterator("");
+ }
+
+ @Override
+ public Object clone() {
+ int cloneAddr = NativeBreakIterator.cloneImpl(this.addr);
+ RuleBasedBreakIterator rbbi =
+ new RuleBasedBreakIterator(cloneAddr, this.type);
+
+ rbbi.charIter = this.charIter;
+
+ return rbbi;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if(object == null) {
+ return false;
+ }
+
+ if(!(object instanceof RuleBasedBreakIterator)) {
+ return false;
+ }
+
+ CharacterIterator iter = ((RuleBasedBreakIterator) object).charIter;
+
+ boolean result = this.type == ((RuleBasedBreakIterator) object).type;
+
+ return result && iter.equals(this.charIter);
+ }
+
+ @Override
+ public int current() {
+ return NativeBreakIterator.currentImpl(this.addr);
+ }
+
+ @Override
+ public int first() {
+ return NativeBreakIterator.firstImpl(this.addr);
+ }
+
+ @Override
+ public int following(int offset) {
+ return NativeBreakIterator.followingImpl(this.addr, offset);
+ }
+
+ @Override
+ public CharacterIterator getText() {
+ int newLoc = NativeBreakIterator.currentImpl(this.addr);
+ this.charIter.setIndex(newLoc);
+ return this.charIter;
+ }
+
+ @Override
+ public int last() {
+ return NativeBreakIterator.lastImpl(this.addr);
+ }
+
+ @Override
+ public int next(int n) {
+ return NativeBreakIterator.nextImpl(this.addr, n);
+ }
+
+ @Override
+ public int next() {
+ return NativeBreakIterator.nextImpl(this.addr, 1);
+ }
+
+ @Override
+ public int previous() {
+ return NativeBreakIterator.previousImpl(this.addr);
+ }
+
+ @Override
+ public void setText(CharacterIterator newText) {
+ this.charIter = newText;
+
+ StringBuilder sb = new StringBuilder();
+
+ char c = newText.first();
+ while(c != CharacterIterator.DONE) {
+ sb.append(c);
+ c = newText.next();
+ }
+
+ NativeBreakIterator.setTextImpl(this.addr, sb.toString());
+ }
+
+ protected void finalize() {
+ NativeBreakIterator.closeBreakIteratorImpl(this.addr);
+ }
+
+ @Override
+ public boolean isBoundary(int offset) {
+ return NativeBreakIterator.isBoundaryImpl(this.addr, offset);
+ }
+
+ @Override
+ public int preceding(int offset) {
+ return NativeBreakIterator.precedingImpl(this.addr, offset);
+ }
+
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java
new file mode 100644
index 0000000..c0aca3b
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java
@@ -0,0 +1,719 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.util.Locale;
+import java.text.CharacterIterator;
+import java.text.ParseException;
+import com.ibm.icu4jni.common.ErrorCode;
+
+/**
+* Concrete implementation class for Collation.
+* <p>
+* The collation table is composed of a list of collation rules, where each
+* rule is of three forms:
+* <pre>
+* < modifier >
+* < relation > < text-argument >
+* < reset > < text-argument >
+* </pre>
+* <p>
+* <code>RuleBasedCollator</code> has the following restrictions for efficiency
+* (other subclasses may be used for more complex languages) :
+* <ol>
+* <li> If a French secondary ordering is specified it applies to the whole
+* collator object.
+* <li> All non-mentioned Unicode characters are at the end of the collation
+* order.
+* <li> If a character is not located in the RuleBasedCollator, the default
+* Unicode Collation Algorithm (UCA) rulebased table is automatically
+* searched as a backup.
+* </ol>
+*
+* The following demonstrates how to create your own collation rules:
+* <UL Type=disc>
+* <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
+* characters, excluding special characters (that is, common whitespace
+* characters [0009-000D, 0020] and rule syntax characters [0021-002F,
+* 003A-0040, 005B-0060, 007B-007E]). If those characters are desired,
+* you can put them in single quotes (e.g. ampersand => '&'). Note that
+* unquoted white space characters are ignored; e.g. <code>b c</code> is
+* treated as <code>bc</code>.
+* <LI><strong>Modifier</strong>: There is a single modifier which is used
+* to specify that all accents (secondary differences) are backwards.
+* <p>'@' : Indicates that accents are sorted backwards, as in French.
+* <LI><strong>Relation</strong>: The relations are the following:
+* <UL Type=square>
+* <LI>'<' : Greater, as a letter difference (primary)
+* <LI>';' : Greater, as an accent difference (secondary)
+* <LI>',' : Greater, as a case difference (tertiary)
+* <LI>'=' : Equal
+* </UL>
+* <LI><strong>Reset</strong>: There is a single reset which is used
+* primarily for contractions and expansions, but which can also be used
+* to add a modification at the end of a set of rules.
+* <p>'&' : Indicates that the next rule follows the position to where
+* the reset text-argument would be sorted.
+* </UL>
+*
+* <p>
+* This sounds more complicated than it is in practice. For example, the
+* following are equivalent ways of expressing the same thing:
+* <blockquote>
+* <pre>
+* a < b < c
+* a < b & b < c
+* a < c & a < b
+* </pre>
+* </blockquote>
+* Notice that the order is important, as the subsequent item goes immediately
+* after the text-argument. The following are not equivalent:
+* <blockquote>
+* <pre>
+* a < b & a < c
+* a < c & a < b
+* </pre>
+* </blockquote>
+* Either the text-argument must already be present in the sequence, or some
+* initial substring of the text-argument must be present. (e.g. "a < b & ae <
+* e" is valid since "a" is present in the sequence before "ae" is reset). In
+* this latter case, "ae" is not entered and treated as a single character;
+* instead, "e" is sorted as if it were expanded to two characters: "a"
+* followed by an "e". This difference appears in natural languages: in
+* traditional Spanish "ch" is treated as though it contracts to a single
+* character (expressed as "c < ch < d"), while in traditional German a-umlaut
+* is treated as though it expanded to two characters (expressed as "a,A < b,B
+* ... & ae;? & AE;?"). [? and ? are, of course, the escape sequences for
+* a-umlaut.]
+* <p>
+* <strong>Ignorable Characters</strong>
+* <p>
+* For ignorable characters, the first rule must start with a relation (the
+* examples we have used above are really fragments; "a < b" really should be
+* "< a < b"). If, however, the first relation is not "<", then all the all
+* text-arguments up to the first "<" are ignorable. For example, ", - < a < b"
+* makes "-" an ignorable character, as we saw earlier in the word
+* "black-birds". In the samples for different languages, you see that most
+* accents are ignorable.
+*
+* <p><strong>Normalization and Accents</strong>
+* <p>
+* <code>RuleBasedCollator</code> automatically processes its rule table to
+* include both pre-composed and combining-character versions of accented
+* characters. Even if the provided rule string contains only base characters
+* and separate combining accent characters, the pre-composed accented
+* characters matching all canonical combinations of characters from the rule
+* string will be entered in the table.
+* <p>
+* This allows you to use a RuleBasedCollator to compare accented strings even
+* when the collator is set to NO_DECOMPOSITION. However, if the strings to be
+* collated contain combining sequences that may not be in canonical order, you
+* should set the collator to CANONICAL_DECOMPOSITION to enable sorting of
+* combining sequences.
+* For more information, see
+* <A HREF="http://www.aw.com/devpress">The Unicode Standard, Version 3.0</A>.)
+*
+* <p><strong>Errors</strong>
+* <p>
+* The following are errors:
+* <UL Type=disc>
+* <LI>A text-argument contains unquoted punctuation symbols
+* (e.g. "a < b-c < d").
+* <LI>A relation or reset character not followed by a text-argument
+* (e.g. "a < , b").
+* <LI>A reset where the text-argument (or an initial substring of the
+* text-argument) is not already in the sequence or allocated in the
+* default UCA table.
+* (e.g. "a < b & e < f")
+* </UL>
+* If you produce one of these errors, a <code>RuleBasedCollator</code> throws
+* a <code>ParseException</code>.
+*
+* <p><strong>Examples</strong>
+* <p>Simple: "< a < b < c < d"
+* <p>Norwegian: "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J
+* < k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T
+* < u,U< v,V< w,W< x,X< y,Y< z,Z
+* < ?=a?,?=A?
+* ;aa,AA< ?,?< ?,?"
+*
+* <p>
+* Normally, to create a rule-based Collator object, you will use
+* <code>Collator</code>'s factory method <code>getInstance</code>.
+* However, to create a rule-based Collator object with specialized rules
+* tailored to your needs, you construct the <code>RuleBasedCollator</code>
+* with the rules contained in a <code>String</code> object. For example:
+* <blockquote>
+* <pre>
+* String Simple = "< a < b < c < d";
+* RuleBasedCollator mySimple = new RuleBasedCollator(Simple);
+* </pre>
+* </blockquote>
+* Or:
+* <blockquote>
+* <pre>
+* String Norwegian = "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J" +
+* "< k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T" +
+* "< u,U< v,V< w,W< x,X< y,Y< z,Z" +
+* "< ?=a?,?=A?" +
+* ";aa,AA< ?,?< ?,?";
+* RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
+* </pre>
+* </blockquote>
+*
+* <p>
+* Combining <code>Collator</code>s is as simple as concatenating strings.
+* Here's an example that combines two <code>Collator</code>s from two
+* different locales:
+* <blockquote>
+* <pre>
+* // Create an en_US Collator object
+* RuleBasedCollator en_USCollator = (RuleBasedCollator)
+* Collator.getInstance(new Locale("en", "US", ""));
+* // Create a da_DK Collator object
+* RuleBasedCollator da_DKCollator = (RuleBasedCollator)
+* Collator.getInstance(new Locale("da", "DK", ""));
+* // Combine the two
+* // First, get the collation rules from en_USCollator
+* String en_USRules = en_USCollator.getRules();
+* // Second, get the collation rules from da_DKCollator
+* String da_DKRules = da_DKCollator.getRules();
+* RuleBasedCollator newCollator =
+* new RuleBasedCollator(en_USRules + da_DKRules);
+* // newCollator has the combined rules
+* </pre>
+* </blockquote>
+*
+* <p>
+* Another more interesting example would be to make changes on an existing
+* table to create a new <code>Collator</code> object. For example, add
+* "& C < ch, cH, Ch, CH" to the <code>en_USCollator</code> object to create
+* your own:
+* <blockquote>
+* <pre>
+* // Create a new Collator object with additional rules
+* String addRules = "& C < ch, cH, Ch, CH";
+* RuleBasedCollator myCollator =
+* new RuleBasedCollator(en_USCollator + addRules);
+* // myCollator contains the new rules
+* </pre>
+* </blockquote>
+*
+* <p>
+* The following example demonstrates how to change the order of
+* non-spacing accents,
+* <blockquote>
+* <pre>
+* // old rule
+* String oldRules = "=?;?;?" // main accents Diaeresis 00A8, Macron 00AF
+* // Acute 00BF
+* + "< a , A ; ae, AE ; ? , ?"
+* + "< b , B < c, C < e, E & C < d, D";
+* // change the order of accent characters
+* String addOn = "& ?;?;?;"; // Acute 00BF, Macron 00AF, Diaeresis 00A8
+* RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
+* </pre>
+* </blockquote>
+*
+* <p>
+* The last example shows how to put new primary ordering in before the
+* default setting. For example, in Japanese <code>Collator</code>, you
+* can either sort English characters before or after Japanese characters,
+* <blockquote>
+* <pre>
+* // get en_US Collator rules
+* RuleBasedCollator en_USCollator =
+* (RuleBasedCollator)Collator.getInstance(Locale.US);
+* // add a few Japanese character to sort before English characters
+* // suppose the last character before the first base letter 'a' in
+* // the English collation rule is ?
+* String jaString = "& \\u30A2 , \\u30FC < \\u30C8";
+* RuleBasedCollator myJapaneseCollator = new
+* RuleBasedCollator(en_USCollator.getRules() + jaString);
+* </pre>
+* </blockquote>
+* <P>
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class RuleBasedCollator extends Collator
+{
+ // public constructors ------------------------------------------
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @exception ParseException thrown if rules are empty or a Runtime error
+ * if collator can not be created.
+ * @stable ICU 2.4
+ */
+ public RuleBasedCollator(String rules) throws ParseException
+ {
+ // BEGIN android-changed
+ if (rules == null) {
+ throw new NullPointerException();
+ }
+ // if (rules.length() == 0)
+ // throw new ParseException("Build rules empty.", 0);
+ // END android-changed
+ m_collator_ = NativeCollation.openCollatorFromRules(rules,
+ CollationAttribute.VALUE_OFF,
+ CollationAttribute.VALUE_DEFAULT_STRENGTH);
+ }
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @param strength collation strength
+ * @exception ParseException thrown if rules are empty or a Runtime error
+ * if collator can not be created.
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @stable ICU 2.4
+ */
+ public RuleBasedCollator(String rules, int strength) throws ParseException
+ {
+ // BEGIN android-changed
+ if (rules == null) {
+ throw new NullPointerException();
+ }
+ // if (rules.length() == 0)
+ // throw new ParseException("Build rules empty.", 0);
+ // END android-changed
+ if (!CollationAttribute.checkStrength(strength))
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+
+ m_collator_ = NativeCollation.openCollatorFromRules(rules,
+ CollationAttribute.VALUE_OFF,
+ strength);
+ }
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * <p>Note API change starting from release 2.4. Prior to release 2.4, the
+ * normalizationmode argument values are from the class
+ * com.ibm.icu4jni.text.Normalization. In 2.4,
+ * the valid normalizationmode arguments for this API are
+ * CollationAttribute.VALUE_ON and CollationAttribute.VALUE_OFF.
+ * </p>
+ * @param rules the collation rules to build the collation table from.
+ * @param strength collation strength
+ * @param normalizationmode normalization mode
+ * @exception IllegalArgumentException thrown when constructor error occurs
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #NO_DECOMPOSITION
+ * @stable ICU 2.4
+ */
+ public RuleBasedCollator(String rules, int normalizationmode, int strength)
+ {
+ // BEGIN android-added
+ if (rules == null) {
+ throw new NullPointerException();
+ }
+ // END android-added
+ if (!CollationAttribute.checkStrength(strength) ||
+ !CollationAttribute.checkNormalization(normalizationmode)) {
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ m_collator_ = NativeCollation.openCollatorFromRules(rules,
+ normalizationmode, strength);
+ }
+
+ // public methods -----------------------------------------------
+
+ /**
+ * Makes a complete copy of the current object.
+ * @return a copy of this object if data clone is a success, otherwise null
+ * @stable ICU 2.4
+ */
+ public Object clone()
+ {
+ RuleBasedCollator result = null;
+ int collatoraddress = NativeCollation.safeClone(m_collator_);
+ result = new RuleBasedCollator(collatoraddress);
+ return (Collator)result;
+ }
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different strings. Returns information about whether a string is less
+ * than, greater than or equal to another string.
+ * <p>Example of use:
+ * <br>
+ * <code>
+ * Collator myCollation = Collator.createInstance(Locale::US);
+ * myCollation.setStrength(CollationAttribute.VALUE_PRIMARY);
+ * // result would be Collator.RESULT_EQUAL ("abc" == "ABC")
+ * // (no primary difference between "abc" and "ABC")
+ * int result = myCollation.compare("abc", "ABC",3);
+ * myCollation.setStrength(CollationAttribute.VALUE_TERTIARY);
+ * // result would be Collation::LESS (abc" &lt;&lt;&lt; "ABC")
+ * // (with tertiary difference between "abc" and "ABC")
+ * int result = myCollation.compare("abc", "ABC",3);
+ * </code>
+ * @param source The source string.
+ * @param target The target string.
+ * @return result of the comparison, Collator.RESULT_EQUAL,
+ * Collator.RESULT_GREATER or Collator.RESULT_LESS
+ * @stable ICU 2.4
+ */
+ public int compare(String source, String target)
+ {
+ return NativeCollation.compare(m_collator_, source, target);
+ }
+
+ /**
+ * Get the normalization mode for this object.
+ * The normalization mode influences how strings are compared.
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #NO_DECOMPOSITION
+ * @stable ICU 2.4
+ */
+ public int getDecomposition()
+ {
+ return NativeCollation.getNormalization(m_collator_);
+ }
+
+ /**
+ * <p>Sets the decomposition mode of the Collator object on or off.
+ * If the decomposition mode is set to on, string would be decomposed into
+ * NFD format where necessary before sorting.</p>
+ * </p>
+ * @param decompositionmode the new decomposition mode
+ * @see #CANONICAL_DECOMPOSITION
+ * @see #NO_DECOMPOSITION
+ * @stable ICU 2.4
+ */
+ public void setDecomposition(int decompositionmode)
+ {
+ if (!CollationAttribute.checkNormalization(decompositionmode))
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+ NativeCollation.setAttribute(m_collator_,
+ CollationAttribute.NORMALIZATION_MODE,
+ decompositionmode);
+ }
+
+ /**
+ * Determines the minimum strength that will be use in comparison or
+ * transformation.
+ * <p>
+ * E.g. with strength == CollationAttribute.VALUE_SECONDARY, the tertiary difference
+ * is ignored
+ * </p>
+ * <p>
+ * E.g. with strength == PRIMARY, the secondary and tertiary difference are
+ * ignored.
+ * </p>
+ * @return the current comparison level.
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @stable ICU 2.4
+ */
+ public int getStrength()
+ {
+ return NativeCollation.getAttribute(m_collator_,
+ CollationAttribute.STRENGTH);
+ }
+
+ /**
+ * Sets the minimum strength to be used in comparison or transformation.
+ * <p>Example of use:
+ * <br>
+ * <code>
+ * Collator myCollation = Collator.createInstance(Locale::US);
+ * myCollation.setStrength(PRIMARY);
+ * // result will be "abc" == "ABC"
+ * // tertiary differences will be ignored
+ * int result = myCollation->compare("abc", "ABC");
+ * </code>
+ * @param strength the new comparison level.
+ * @exception IllegalArgumentException when argument does not belong to any collation strength
+ * mode or error occurs while setting data.
+ * @see #PRIMARY
+ * @see #SECONDARY
+ * @see #TERTIARY
+ * @see #QUATERNARY
+ * @see #IDENTICAL
+ * @stable ICU 2.4
+ */
+ public void setStrength(int strength)
+ {
+ if (!CollationAttribute.checkStrength(strength))
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+ NativeCollation.setAttribute(m_collator_, CollationAttribute.STRENGTH,
+ strength);
+ }
+
+ /**
+ * Sets the attribute to be used in comparison or transformation.
+ * <p>Example of use:
+ * <br>
+ * <code>
+ * Collator myCollation = Collator.createInstance(Locale::US);
+ * myCollation.setAttribute(CollationAttribute.CASE_LEVEL,
+ * CollationAttribute.VALUE_ON);
+ * int result = myCollation->compare("\\u30C3\\u30CF",
+ * "\\u30C4\\u30CF");
+ * // result will be Collator.RESULT_LESS.
+ * </code>
+ * @param type the attribute to be set from CollationAttribute
+ * @param value attribute value from CollationAttribute
+ * @stable ICU 2.4
+ */
+ public void setAttribute(int type, int value)
+ {
+ if (!CollationAttribute.checkAttribute(type, value))
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+ NativeCollation.setAttribute(m_collator_, type, value);
+ }
+
+ /**
+ * Gets the attribute to be used in comparison or transformation.
+ * @param type the attribute to be set from CollationAttribute
+ * @return value attribute value from CollationAttribute
+ * @stable ICU 2.4
+ */
+ public int getAttribute(int type)
+ {
+ if (!CollationAttribute.checkType(type))
+ throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+ return NativeCollation.getAttribute(m_collator_, type);
+ }
+
+ /**
+ * Get the sort key as an CollationKey object from the argument string.
+ * To retrieve sort key in terms of byte arrays, use the method as below<br>
+ * <br>
+ * <code>
+ * Collator collator = Collator.getInstance();
+ * byte[] array = collator.getSortKey(source);
+ * </code><br>
+ * Byte array result are zero-terminated and can be compared using
+ * java.util.Arrays.equals();
+ * @param source string to be processed.
+ * @return the sort key
+ * @stable ICU 2.4
+ */
+ public CollationKey getCollationKey(String source)
+ {
+ // BEGIN android-removed
+ // return new CollationKey(NativeCollation.getSortKey(m_collator_, source));
+ // END android-removed
+ // BEGIN android-added
+ if(source == null) {
+ return null;
+ }
+ byte[] key = NativeCollation.getSortKey(m_collator_, source);
+ if(key == null) {
+ return null;
+ }
+ return new CollationKey(key);
+ // END android-added
+ }
+
+ /**
+ * Get a sort key for the argument string
+ * Sort keys may be compared using java.util.Arrays.equals
+ * @param source string for key to be generated
+ * @return sort key
+ * @stable ICU 2.4
+ */
+ public byte[] getSortKey(String source)
+ {
+ return NativeCollation.getSortKey(m_collator_, source);
+ }
+
+ /**
+ * Get the collation rules of this Collation object
+ * The rules will follow the rule syntax.
+ * @return collation rules.
+ * @stable ICU 2.4
+ */
+ public String getRules()
+ {
+ return NativeCollation.getRules(m_collator_);
+ }
+
+ /**
+ * Create a CollationElementIterator object that will iterator over the
+ * elements in a string, using the collation rules defined in this
+ * RuleBasedCollator
+ * @param source string to iterate over
+ * @return address of C collationelement
+ * @exception IllegalArgumentException thrown when error occurs
+ * @stable ICU 2.4
+ */
+ public CollationElementIterator getCollationElementIterator(String source)
+ {
+ CollationElementIterator result = new CollationElementIterator(
+ NativeCollation.getCollationElementIterator(m_collator_, source));
+ // result.setOwnCollationElementIterator(true);
+ return result;
+ }
+
+ // BEGIN android-added
+ /**
+ * Create a CollationElementIterator object that will iterator over the
+ * elements in a string, using the collation rules defined in this
+ * RuleBasedCollator
+ * @param source string to iterate over
+ * @return address of C collationelement
+ * @exception IllegalArgumentException thrown when error occurs
+ * @stable ICU 2.4
+ */
+ public CollationElementIterator getCollationElementIterator(
+ CharacterIterator source)
+ {
+ CollationElementIterator result = new CollationElementIterator(
+ NativeCollation.getCollationElementIterator(m_collator_,
+ source.toString()));
+ // result.setOwnCollationElementIterator(true);
+ return result;
+ }
+ // END android-added
+
+ /**
+ * Returns a hash of this collation object
+ * Note this method is not complete, it only returns 0 at the moment.
+ * @return hash of this collation object
+ * @stable ICU 2.4
+ */
+ public int hashCode()
+ {
+ // since rules do not change once it is created, we can cache the hash
+ if (m_hashcode_ == 0) {
+ m_hashcode_ = NativeCollation.hashCode(m_collator_);
+ if (m_hashcode_ == 0)
+ m_hashcode_ = 1;
+ }
+ return m_hashcode_;
+ }
+
+ /**
+ * Checks if argument object is equals to this object.
+ * @param target object
+ * @return true if source is equivalent to target, false otherwise
+ * @stable ICU 2.4
+ */
+ public boolean equals(Object target)
+ {
+ if (this == target)
+ return true;
+ if (target == null)
+ return false;
+ if (getClass() != target.getClass())
+ return false;
+
+ RuleBasedCollator tgtcoll = (RuleBasedCollator)target;
+ return getRules().equals(tgtcoll.getRules()) &&
+ getStrength() == tgtcoll.getStrength() &&
+ getDecomposition() == tgtcoll.getDecomposition();
+ }
+
+ // package constructor ----------------------------------------
+
+ /**
+ * RuleBasedCollator default constructor. This constructor takes the default
+ * locale. The only caller of this class should be Collator.getInstance().
+ * Current implementation createInstance() returns a RuleBasedCollator(Locale)
+ * instance. The RuleBasedCollator will be created in the following order,
+ * <ul>
+ * <li> Data from argument locale resource bundle if found, otherwise
+ * <li> Data from parent locale resource bundle of arguemtn locale if found,
+ * otherwise
+ * <li> Data from built-in default collation rules if found, other
+ * <li> null is returned
+ * </ul>
+ */
+ RuleBasedCollator()
+ {
+ m_collator_ = NativeCollation.openCollator();
+ }
+
+ /**
+ * RuleBasedCollator constructor. This constructor takes a locale. The
+ * only caller of this class should be Collator.createInstance().
+ * Current implementation createInstance() returns a RuleBasedCollator(Locale)
+ * instance. The RuleBasedCollator will be created in the following order,
+ * <ul>
+ * <li> Data from argument locale resource bundle if found, otherwise
+ * <li> Data from parent locale resource bundle of arguemtn locale if found,
+ * otherwise
+ * <li> Data from built-in default collation rules if found, other
+ * <li> null is returned
+ * </ul>
+ * @param locale locale used
+ */
+ RuleBasedCollator(Locale locale)
+ {
+ if (locale == null) {
+ m_collator_ = NativeCollation.openCollator();
+ }
+ else {
+ m_collator_ = NativeCollation.openCollator(locale.toString());
+ }
+ }
+
+ // protected methods --------------------------------------------
+
+ /**
+ * Garbage collection.
+ * Close C collator and reclaim memory.
+ */
+ protected void finalize()
+ {
+ NativeCollation.closeCollator(m_collator_);
+ }
+
+ // private data members -----------------------------------------
+
+ /**
+ * C collator
+ */
+ private int m_collator_;
+
+ /**
+ * Hash code for rules
+ */
+ private int m_hashcode_ = 0;
+
+ // private constructor -----------------------------------------
+
+ /**
+ * Private use constructor.
+ * Does not create any instance of the C collator. Accepts argument as the
+ * C collator for new instance.
+ * @param collatoraddress address of C collator
+ */
+ private RuleBasedCollator(int collatoraddress)
+ {
+ m_collator_ = collatoraddress;
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java
new file mode 100644
index 0000000..3c865d8
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.text;
+
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+public class RuleBasedNumberFormat extends NumberFormat {
+
+ /**
+ * Enum of predefined RBNF types.
+ */
+ public enum RBNFType {
+ /**
+ * This creates a spellout instance of RBNF.
+ * It formats numbers into textual representation:
+ * 15 -> 'fifteen' or 15.15 -> 'fifteen point one five'
+ * and it can parse words into numbers: 'twenty' -> 20
+ */
+ SPELLOUT(0),
+ /**
+ * This creates an ordinal instance of RBNF.
+ * It formats numbers into an ordinal text representation:
+ * 15 -> '15th' and by parsing it also works in the other direction.
+ */
+ ORDINAL(1),
+ /**
+ * This creates instance of RBNF that allows to format numbers into time
+ * values: 15 -> '15 sec.' and by parsing it also works in the other
+ * direction.
+ */
+ DURATION(2);
+
+ int type;
+
+ RBNFType(int t) {
+ type = t;
+ }
+
+ int getType() {
+ return type;
+ }
+ }
+
+ @Override
+ protected void finalize(){
+ close();
+ }
+
+ private int addr = 0;
+
+ /**
+ * Open a new rule based number format of selected type for the
+ * default location
+ *
+ * @param type the type of rule based number format
+ */
+ public void open(RBNFType type) {
+ this.addr = openRBNFImpl(type.getType(),
+ Locale.getDefault().toString());
+ }
+
+ /**
+ * Open a new rule based number format of selected type for the
+ * given location
+ *
+ * @param type the type of rule based number format
+ * @param locale the locale to use for this rule based number format
+ */
+ public void open(RBNFType type, Locale locale) {
+ String loc = locale.toString();
+ if (loc == null) {
+ throw new NullPointerException();
+ }
+ this.addr = openRBNFImpl(type.getType(), loc);
+ }
+
+ private static native int openRBNFImpl(int type, String loc);
+
+ /**
+ * Open a new rule based number format for the
+ * default location. The rule passed to the method has to be of the form
+ * described in the ibm icu documentation for RuleBasedNumberFormat.
+ *
+ * @param rule the rule for the rule based number format
+ */
+ public void open(String rule) {
+ if (rule == null) {
+ throw new NullPointerException();
+ }
+ this.addr = openRBNFImpl(rule, Locale.getDefault().toString());
+ }
+
+ /**
+ * Open a new rule based number format for the
+ * given location. The rule passed to the method has to be of the form
+ * described in the ibm icu documentation for RuleBasedNumberFormat.
+ *
+ * @param rule the rule for the rule based number format
+ * @param locale the locale to use for this rule based number format
+ */
+ public void open(String rule, Locale locale) {
+ String loc = locale.toString();
+ if (loc == null || rule == null) {
+ throw new NullPointerException();
+ }
+ this.addr = openRBNFImpl(rule, locale.toString());
+ }
+
+ private static native int openRBNFImpl(String rule, String loc);
+
+ /**
+ * close a RuleBasedNumberFormat
+ */
+ public void close() {
+ if(this.addr != 0) {
+ closeRBNFImpl(this.addr);
+ this.addr = 0;
+ }
+ }
+
+ private static native void closeRBNFImpl(int addr);
+
+ @Override
+ public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
+
+ if(buffer == null) {
+ throw new NullPointerException();
+ }
+
+ String fieldType = null;
+
+ if(field != null) {
+ fieldType = getFieldType(field.getFieldAttribute());
+ }
+
+ String result = formatRBNFImpl(this.addr, value, field,
+ fieldType, null);
+
+ buffer.append(result.toCharArray(), 0, result.length());
+
+ return buffer;
+ }
+
+ private static native String formatRBNFImpl(int addr, long value,
+ FieldPosition field, String fieldType, StringBuffer buffer);
+
+ @Override
+ public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
+
+ if(buffer == null) {
+ throw new NullPointerException();
+ }
+
+ String fieldType = null;
+
+ if(field != null) {
+ fieldType = getFieldType(field.getFieldAttribute());
+ }
+
+ String result = formatRBNFImpl(this.addr, value, field,
+ fieldType, null);
+
+ buffer.append(result.toCharArray(), 0, result.length());
+
+ return buffer;
+ }
+
+ private static native String formatRBNFImpl(int addr, double value,
+ FieldPosition field, String fieldType, StringBuffer buffer);
+
+ @Override
+ public Number parse(String string, ParsePosition position) {
+ if (string == null || position == null) {
+ throw new NullPointerException();
+ }
+ return parseRBNFImpl(this.addr, string, position, false);
+ }
+
+ /**
+ * This method has the same functionality
+ * as {@link #parse(String, ParsePosition)}
+ * But it uses lenient parsing. This means it also accepts strings that
+ * differ from the correct writing (e.g. case or umlaut differences).
+ *
+ * @param string the string to parse
+ * @param position the ParsePosition, updated on return with the index
+ * following the parsed text, or on error the index is unchanged and
+ * the error index is set to the index where the error occurred
+ * @return the Number resulting from the parse, or null if there is an error
+ */
+ public Number parseLenient(String string, ParsePosition position) {
+ if (string == null || position == null) {
+ throw new NullPointerException();
+ }
+ return parseRBNFImpl(this.addr, string, position, true);
+ }
+
+ static native Number parseRBNFImpl(int addr, String string, ParsePosition position, boolean lenient);
+
+
+ static private String getFieldType(Format.Field field) {
+ if(field == null) {
+ return null;
+ }
+ if(field.equals(NumberFormat.Field.SIGN)) {
+ return "sign";
+ }
+ if(field.equals(NumberFormat.Field.INTEGER)) {
+ return "integer";
+ }
+ if(field.equals(NumberFormat.Field.FRACTION)) {
+ return "fraction";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT)) {
+ return "exponent";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT_SIGN)) {
+ return "exponent_sign";
+ }
+ if(field.equals(NumberFormat.Field.EXPONENT_SYMBOL)) {
+ return "exponent_symbol";
+ }
+ if(field.equals(NumberFormat.Field.CURRENCY)) {
+ return "currency";
+ }
+ if(field.equals(NumberFormat.Field.GROUPING_SEPARATOR)) {
+ return "grouping_separator";
+ }
+ if(field.equals(NumberFormat.Field.DECIMAL_SEPARATOR)) {
+ return "decimal_separator";
+ }
+ if(field.equals(NumberFormat.Field.PERCENT)) {
+ return "percent";
+ }
+ if(field.equals(NumberFormat.Field.PERMILLE)) {
+ return "permille";
+ }
+ return null;
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
new file mode 100644
index 0000000..85530ac
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -0,0 +1,533 @@
+/*
+ * 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.
+ */
+
+package com.ibm.icu4jni.util;
+
+import java.util.Enumeration;
+import java.util.ListResourceBundle;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+import java.util.logging.Logger;
+
+/**
+ * Helper class that delivers ResourceBundle instances expected by Harmony, but
+ * with the data taken from ICU's database. This approach has a couple of
+ * advantages:
+ * <ol>
+ * <li> We have less classes in the overall system, since we use different
+ * instances for different ResourceBundles.
+ * <li> We don't have these classes that consists of monstrous static arrays
+ * with anymore.
+ * <li> We have control over which values we load at which time or even cache
+ * for later use.
+ * <li> There is only one central place left in the system where I18N data needs
+ * to be configured, namely ICU.
+ * </ol>
+ * Since we're mimicking the original Harmony ResourceBundle structures, most of
+ * the Harmony code can stay the same. We basically just need to change the
+ * ResourceBundle instantiation. Only the special case of the Locale bundles
+ * needs some more tweaking, since we don't want to keep several hundred
+ * timezone names in memory.
+ */
+public class Resources {
+
+ /**
+ * Cache for ISO language names.
+ */
+ private static String[] isoLanguages = null;
+
+ /**
+ * Cache for ISO country names.
+ */
+ private static String[] isoCountries = null;
+
+ /**
+ * Available locales cache.
+ */
+ private static String[] availableLocales = null;
+
+ /**
+ * Available timezones cache.
+ */
+ private static String[] availableTimezones = null;
+
+ /**
+ * Creates ResourceBundle instance and fills it with ICU data.
+ *
+ * @param bundleName The name of the requested Harmony resource bundle,
+ * excluding the package name.
+ * @param locale The locale to use for the resources. A null value denotes
+ * the default locale as configured in Java.
+ * @return The new ResourceBundle, or null, if no ResourceBundle was
+ * created.
+ */
+ public static ResourceBundle getInstance(String bundleName, String locale) {
+ if (locale == null) {
+ locale = java.util.Locale.getDefault().toString();
+ }
+
+ if (bundleName.startsWith("Locale")) {
+ return new Locale(locale);
+ } else if (bundleName.startsWith("Country")) {
+ return new Country(locale);
+ } else if (bundleName.startsWith("Currency")) {
+ return new Currency(locale);
+ } else if (bundleName.startsWith("Language")) {
+ return new Language(locale);
+ } else if (bundleName.startsWith("Variant")) {
+ return new Variant(locale);
+ } else if (bundleName.equals("ISO3Countries")) {
+ return new ISO3Countries();
+ } else if (bundleName.equals("ISO3Languages")) {
+ return new ISO3Languages();
+ } else if (bundleName.equals("ISO4CurrenciesToDigits")) {
+ return new ISO4CurrenciesToDigits();
+ } else if (bundleName.equals("ISO4Currencies")) {
+ return new ISO4Currencies();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns an array of ISO language names (two-letter codes), fetched either
+ * from ICU's database or from our memory cache.
+ *
+ * @return The array.
+ */
+ public static String[] getISOLanguages() {
+ if (isoLanguages == null) {
+ isoLanguages = getISOLanguagesNative();
+ }
+
+ return isoLanguages;
+ }
+
+ /**
+ * Returns an array of ISO country names (two-letter codes), fetched either
+ * from ICU's database or from our memory cache.
+ *
+ * @return The array.
+ */
+ public static String[] getISOCountries() {
+ if (isoCountries == null) {
+ isoCountries = getISOCountriesNative();
+ }
+
+ return isoCountries;
+ }
+
+ /**
+ * Returns an array of names of locales that are available in the system,
+ * fetched either from ICU's database or from our memory cache.
+ *
+ * @return The array.
+ */
+ public static String[] getAvailableLocales() {
+ if (availableLocales == null) {
+ availableLocales = getAvailableLocalesNative();
+ }
+
+ return availableLocales;
+ }
+
+ /**
+ * Returns an array of names of timezones that are available in the system,
+ * fetched either from the TimeZone class or from our memory cache.
+ *
+ * @return The array.
+ */
+ public static String[] getKnownTimezones() {
+ // TODO Drop the Linux ZoneInfo stuff in favor of ICU.
+ if (availableTimezones == null) {
+ availableTimezones = TimeZone.getAvailableIDs();
+ }
+
+ return availableTimezones;
+ }
+
+ /**
+ * Returns the display name for the given time zone using the given locale.
+ *
+ * @param id The time zone ID, for example "Europe/Berlin"
+ * @param isDST Indicates whether daylight savings is in use
+ * @param style The style, 0 for long, 1 for short
+ * @param locale The locale name, for example "en_US".
+ * @return The desired display name
+ */
+ public static String getDisplayTimeZone(String id, boolean isDST, int style, String locale) {
+ return getDisplayTimeZoneNative(id, isDST, style, locale);
+ }
+
+ /**
+ * Gets the name of the default locale.
+ */
+ private static String getDefaultLocaleName() {
+ return java.util.Locale.getDefault().toString();
+ }
+
+ /**
+ * Name of default locale at the time this class was initialized.
+ */
+ private static final String initialLocale = getDefaultLocaleName();
+
+ /**
+ * Names of time zones for the default locale.
+ */
+ private static String[][] defaultTimezoneNames = null;
+
+ /**
+ * Creates array of time zone names for the given locale. This method takes
+ * about 2s to run on a 400mhz ARM11.
+ */
+ private static String[][] createTimeZoneNamesFor(String locale) {
+ long start = System.currentTimeMillis();
+
+ /*
+ * The following code is optimized for fast native response (the time a
+ * method call can be in native code is limited). It prepares an empty
+ * array to keep native code from having to create new Java objects. It
+ * also fill in the time zone IDs to speed things up a bit. There's one
+ * array for each time zone name type. (standard/long, standard/short,
+ * daylight/long, daylight/short) The native method that fetches these
+ * strings is faster if it can do all entries of one type, before having
+ * to change to the next type. That's why the array passed down to
+ * native has 5 entries, each providing space for all time zone names of
+ * one type. Likely this access to the fields is much faster in the
+ * native code because there's less array access overhead.
+ */
+ String[][] arrayToFill = new String[5][];
+ arrayToFill[0] = getKnownTimezones();
+ arrayToFill[1] = new String[availableTimezones.length];
+ arrayToFill[2] = new String[availableTimezones.length];
+ arrayToFill[3] = new String[availableTimezones.length];
+ arrayToFill[4] = new String[availableTimezones.length];
+
+ /*
+ * Fill in the zone names in native.
+ */
+ getTimeZonesNative(arrayToFill, locale);
+
+ /*
+ * Finally we need to reorder the entries so we get the expected result.
+ */
+ String[][] result = new String[availableTimezones.length][5];
+ for (int i = 0; i < availableTimezones.length; i++) {
+ result[i][0] = arrayToFill[0][i];
+ result[i][1] = arrayToFill[1][i];
+ result[i][2] = arrayToFill[2][i];
+ result[i][3] = arrayToFill[3][i];
+ result[i][4] = arrayToFill[4][i];
+ }
+
+ Logger.getLogger(Resources.class.getSimpleName()).info(
+ "Loaded time zone names for " + locale + " in "
+ + (System.currentTimeMillis() - start) + "ms.");
+
+ return result;
+ }
+
+ /**
+ * Returns the display names for all given timezones using the given locale.
+ *
+ * @return An array of time zone strings. Each row represents one time zone.
+ * The first columns holds the ID of the time zone, for example
+ * "Europe/Berlin". The other columns then hold for each row the
+ * four time zone names with and without daylight savings and in
+ * long and short format. It's exactly the array layout required by
+ * the TomeZone class.
+ */
+ public static String[][] getDisplayTimeZones(String locale) {
+ // Note: Defer loading DefaultTimeZones as long as possible.
+
+ String defaultLocaleName = getDefaultLocaleName();
+ if (locale == null) {
+ locale = defaultLocaleName;
+ }
+
+ // If locale == default and the default locale hasn't changed since
+ // DefaultTimeZones loaded, return the cached names.
+ // TODO: We should force a reboot if the default locale changes.
+ if (defaultLocaleName.equals(locale)
+ && initialLocale.equals(defaultLocaleName)) {
+ if (defaultTimezoneNames == null) {
+ defaultTimezoneNames = createTimeZoneNamesFor(locale);
+ }
+ return defaultTimezoneNames;
+ }
+
+ return createTimeZoneNamesFor(locale);
+ }
+
+ // --- Specialized ResourceBundle subclasses ------------------------------
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "ISO3Countries" bundle.
+ * Keys are the two-letter ISO country codes. Values are the three-letter
+ * ISO country abbreviations. An example entry is "US"->"USA".
+ */
+ private static final class ISO3Countries extends ResourceBundle {
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getISO3CountryNative(key);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "ISO3Languages" bundle.
+ * Keys are the two-letter ISO language codes. Values are the three-letter
+ * ISO language abbreviations. An example entry is "EN"->"ENG".
+ */
+ private static final class ISO3Languages extends ResourceBundle {
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getISO3LanguageNative(key);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "ISO4Currencies" bundle.
+ * Keys are the two-letter ISO language codes. Values are the three-letter
+ * ISO currency abbreviations. An example entry is "US"->"USD".
+ */
+ private static final class ISO4Currencies extends ResourceBundle {
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getCurrencyCodeNative(key);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "ISO4CurrenciesToDigits"
+ * bundle. Keys are the three-letter ISO currency codes. Values are strings
+ * containing the number of fraction digits to use for the currency. An
+ * example entry is "USD"->"2".
+ */
+ private static final class ISO4CurrenciesToDigits extends ResourceBundle {
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ // In some places the triple-x code is used as the fall back
+ // currency. The harmony package returned -1 for this requested
+ // currency.
+ if ("XXX".equals(key)) {
+ return "-1";
+ }
+ int res = getFractionDigitsNative(key);
+ if(res < 0) {
+ throw new MissingResourceException("couldn't find resource.",
+ ISO4CurrenciesToDigits.class.getName(), key);
+ }
+ return "" + res;
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "Country_*" bundles. Keys
+ * are the two-letter ISO country codes. Values are the printable country
+ * names in terms of the specified locale. An example entry is "US"->"United
+ * States".
+ */
+ private static final class Country extends ResourceBundle {
+ private String locale;
+
+ public Country(String locale) {
+ super();
+ this.locale = locale;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getDisplayCountryNative(key, locale);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "Currency_*" bundles. Keys
+ * are the three-letter ISO currency codes. Values are the printable
+ * currency names in terms of the specified locale. An example entry is
+ * "USD"->"$" (for inside the US) and "USD->"US$" (for outside the US).
+ */
+ private static final class Currency extends ResourceBundle {
+
+ private String locale;
+
+ public Currency(String locale) {
+ super();
+ this.locale = locale;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getCurrencySymbolNative(locale, key);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "Language_*" bundles. Keys
+ * are the two-letter ISO language codes. Values are the printable language
+ * names in terms of the specified locale. An example entry is
+ * "en"->"English".
+ */
+ private static final class Language extends ResourceBundle {
+ private String locale;
+
+ public Language(String locale) {
+ super();
+ this.locale = locale;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getDisplayLanguageNative(key, locale);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "Variant_*" bundles. Keys
+ * are a fixed set of variants codes known to Harmony. Values are the
+ * printable variant names in terms of the specified locale. An example
+ * entry is "EURO"->"Euro".
+ */
+ private static final class Variant extends ResourceBundle {
+
+ private String locale;
+
+ public Variant(String locale) {
+ super();
+ this.locale = locale;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // Won't get used
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return getDisplayVariantNative(key, locale);
+ }
+
+ }
+
+ /**
+ * Internal ResourceBundle mimicking the Harmony "Locale_*" bundles. This is
+ * clearly the most complex case, because the content covers a wide range of
+ * data items, with values even being arrays in some cases. Note we are
+ * cheating with the "timezones" entry, since we normally don't want to
+ * waste our precious RAM on several thousand of these Strings.
+ */
+ private static final class Locale extends ListResourceBundle {
+
+ private String locale;
+
+ public Locale(String locale) {
+ super();
+ this.locale = locale;
+ }
+
+ @Override
+ protected Object[][] getContents() {
+ return getContentImpl(locale, false);
+ }
+
+ }
+
+ // --- Native methods accessing ICU's database ----------------------------
+
+ private static native int getFractionDigitsNative(String currencyCode);
+
+ private static native String getCurrencyCodeNative(String locale);
+
+ private static native String getCurrencySymbolNative(String locale, String currencyCode);
+
+ private static native String getDisplayCountryNative(String countryCode, String locale);
+
+ private static native String getDisplayLanguageNative(String languageCode, String locale);
+
+ private static native String getDisplayVariantNative(String variantCode, String locale);
+
+ private static native String getISO3CountryNative(String locale);
+
+ private static native String getISO3LanguageNative(String locale);
+
+ private static native String[] getAvailableLocalesNative();
+
+ private static native String[] getISOLanguagesNative();
+
+ private static native String[] getISOCountriesNative();
+
+ private static native void getTimeZonesNative(String[][] arrayToFill, String locale);
+
+ private static native String getDisplayTimeZoneNative(String id, boolean isDST, int style,
+ String locale);
+
+ private static native Object[][] getContentImpl(String locale, boolean needsTimeZones);
+}
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 +=