• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Internal native functions.  All of the functions defined here make
5  * direct use of VM functions or data structures, so they can't be written
6  * with JNI and shouldn't really be in a shared library.
7  *
8  * All functions here either complete quickly or are used to enter a wait
9  * state, so we don't set the thread status to THREAD_NATIVE when executing
10  * these methods.  This means that the GC will wait for these functions
11  * to finish.  DO NOT perform long operations or blocking I/O in here.
12  *
13  * In some cases we're following the division of labor defined by GNU
14  * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
15  * the VM-specific behavior isolated in VMThread.
16  */
17 
18 #define LOG_TAG "DecimalFormatInterface"
19 #include "JNIHelp.h"
20 #include "AndroidSystemNatives.h"
21 #include "unicode/unum.h"
22 #include "unicode/numfmt.h"
23 #include "unicode/decimfmt.h"
24 #include "unicode/fmtable.h"
25 #include "unicode/ustring.h"
26 #include "digitlst.h"
27 #include "ErrorCode.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include "cutils/log.h"
31 
32 
icuError(JNIEnv * env,UErrorCode errorcode)33 static UBool icuError(JNIEnv *env, UErrorCode errorcode)
34 {
35     const char *emsg = u_errorName(errorcode);
36     jclass  exception;
37 
38     if (U_FAILURE(errorcode)) {// errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
39         switch (errorcode) {
40             case U_ILLEGAL_ARGUMENT_ERROR :
41                 exception = env->FindClass("java/lang/IllegalArgumentException");
42                 break;
43             case U_INDEX_OUTOFBOUNDS_ERROR :
44             case U_BUFFER_OVERFLOW_ERROR :
45                 exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
46                 break;
47             case U_UNSUPPORTED_ERROR :
48                 exception = env->FindClass("java/lang/UnsupportedOperationException");
49                 break;
50             default :
51                 exception = env->FindClass("java/lang/RuntimeException");
52         }
53 
54         return (env->ThrowNew(exception, emsg) != 0);
55     }
56     return 0;
57 }
58 
openDecimalFormatImpl(JNIEnv * env,jclass clazz,jstring locale,jstring pattern)59 static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
60         jstring pattern) {
61 
62     // the errorcode returned by unum_open
63     UErrorCode status = U_ZERO_ERROR;
64 
65     // prepare the pattern string for the call to unum_open
66     const UChar *pattChars = env->GetStringChars(pattern, NULL);
67     int pattLen = env->GetStringLength(pattern);
68 
69     // prepare the locale string for the call to unum_open
70     const char *localeChars = env->GetStringUTFChars(locale, NULL);
71 
72     // open a default type number format
73     UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen,
74             localeChars, NULL, &status);
75 
76     // release the allocated strings
77     env->ReleaseStringChars(pattern, pattChars);
78     env->ReleaseStringUTFChars(locale, localeChars);
79 
80     // check for an error
81     if ( icuError(env, status) != FALSE) {
82         return 0;
83     }
84 
85     // return the handle to the number format
86     return (long) fmt;
87 }
88 
closeDecimalFormatImpl(JNIEnv * env,jclass clazz,jint addr)89 static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) {
90 
91     // get the pointer to the number format
92     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
93 
94     // close this number format
95     unum_close(fmt);
96 }
97 
setSymbol(JNIEnv * env,jclass clazz,jint addr,jint symbol,jstring text)98 static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol,
99         jstring text) {
100 
101     // the errorcode returned by unum_setSymbol
102     UErrorCode status = U_ZERO_ERROR;
103 
104     // get the pointer to the number format
105     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
106 
107     // prepare the symbol string for the call to unum_setSymbol
108     const UChar *textChars = env->GetStringChars(text, NULL);
109     int textLen = env->GetStringLength(text);
110 
111     // set the symbol
112     unum_setSymbol(fmt, (UNumberFormatSymbol) symbol, textChars, textLen,
113             &status);
114 
115     // release previously allocated space
116     env->ReleaseStringChars(text, textChars);
117 
118     // check if an error occured
119     icuError(env, status);
120 }
121 
getSymbol(JNIEnv * env,jclass clazz,jint addr,jint symbol)122 static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
123 
124     uint32_t resultlength, reslenneeded;
125 
126     // the errorcode returned by unum_getSymbol
127     UErrorCode status = U_ZERO_ERROR;
128 
129     // get the pointer to the number format
130     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
131 
132     UChar* result = NULL;
133     resultlength=0;
134 
135     // find out how long the result will be
136     reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result,
137             resultlength, &status);
138 
139     result = NULL;
140     if(status==U_BUFFER_OVERFLOW_ERROR) {
141         status=U_ZERO_ERROR;
142         resultlength=reslenneeded+1;
143         result=(UChar*)malloc(sizeof(UChar) * resultlength);
144         reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result,
145                 resultlength, &status);
146     }
147     if (icuError(env, status) != FALSE) {
148         return NULL;
149     }
150 
151     jstring res = env->NewString(result, reslenneeded);
152 
153     free(result);
154 
155     return res;
156 }
157 
setAttribute(JNIEnv * env,jclass clazz,jint addr,jint symbol,jint value)158 static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol,
159         jint value) {
160 
161     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
162 
163     unum_setAttribute(fmt, (UNumberFormatAttribute) symbol, value);
164 }
165 
getAttribute(JNIEnv * env,jclass clazz,jint addr,jint symbol)166 static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
167 
168     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
169 
170     int res = unum_getAttribute(fmt, (UNumberFormatAttribute) symbol);
171 
172     return res;
173 }
174 
setTextAttribute(JNIEnv * env,jclass clazz,jint addr,jint symbol,jstring text)175 static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol,
176         jstring text) {
177 
178     // the errorcode returned by unum_setTextAttribute
179     UErrorCode status = U_ZERO_ERROR;
180 
181     // get the pointer to the number format
182     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
183 
184     const UChar *textChars = env->GetStringChars(text, NULL);
185     int textLen = env->GetStringLength(text);
186 
187     unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars,
188             textLen, &status);
189 
190     env->ReleaseStringChars(text, textChars);
191 
192     icuError(env, status);
193 }
194 
getTextAttribute(JNIEnv * env,jclass clazz,jint addr,jint symbol)195 static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr,
196         jint symbol) {
197 
198     uint32_t resultlength, reslenneeded;
199 
200     // the errorcode returned by unum_getTextAttribute
201     UErrorCode status = U_ZERO_ERROR;
202 
203     // get the pointer to the number format
204     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
205 
206     UChar* result = NULL;
207     resultlength=0;
208 
209     // find out how long the result will be
210     reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol,
211             result, resultlength, &status);
212 
213     result = NULL;
214     if(status==U_BUFFER_OVERFLOW_ERROR) {
215         status=U_ZERO_ERROR;
216         resultlength=reslenneeded+1;
217         result=(UChar*)malloc(sizeof(UChar) * resultlength);
218         reslenneeded=unum_getTextAttribute(fmt,
219                 (UNumberFormatTextAttribute) symbol, result, resultlength,
220                 &status);
221     }
222     if (icuError(env, status) != FALSE) {
223         return NULL;
224     }
225 
226     jstring res = env->NewString(result, reslenneeded);
227 
228     free(result);
229 
230     return res;
231 }
232 
applyPatternImpl(JNIEnv * env,jclass clazz,jint addr,jboolean localized,jstring pattern)233 static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr,
234         jboolean localized, jstring pattern) {
235 
236     // the errorcode returned by unum_applyPattern
237     UErrorCode status = U_ZERO_ERROR;
238 
239     // get the pointer to the number format
240     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
241 
242     const UChar *pattChars = env->GetStringChars(pattern, NULL);
243     int pattLen = env->GetStringLength(pattern);
244 
245     unum_applyPattern(fmt, localized, pattChars, pattLen, NULL, &status);
246 
247     env->ReleaseStringChars(pattern, pattChars);
248 
249     icuError(env, status);
250 }
251 
toPatternImpl(JNIEnv * env,jclass clazz,jint addr,jboolean localized)252 static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr,
253         jboolean localized) {
254 
255     uint32_t resultlength, reslenneeded;
256 
257     // the errorcode returned by unum_toPattern
258     UErrorCode status = U_ZERO_ERROR;
259 
260     // get the pointer to the number format
261     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
262 
263     UChar* result = NULL;
264     resultlength=0;
265 
266     // find out how long the result will be
267     reslenneeded=unum_toPattern(fmt, localized, result, resultlength, &status);
268 
269     result = NULL;
270     if(status==U_BUFFER_OVERFLOW_ERROR) {
271         status=U_ZERO_ERROR;
272         resultlength=reslenneeded+1;
273         result=(UChar*)malloc(sizeof(UChar) * resultlength);
274         reslenneeded=unum_toPattern(fmt, localized, result, resultlength,
275                 &status);
276     }
277     if (icuError(env, status) != FALSE) {
278         return NULL;
279     }
280 
281     jstring res = env->NewString(result, reslenneeded);
282 
283     free(result);
284 
285     return res;
286 }
287 
formatLong(JNIEnv * env,jclass clazz,jint addr,jlong value,jobject field,jstring fieldType,jobject attributes)288 static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value,
289         jobject field, jstring fieldType, jobject attributes) {
290 
291     const char * fieldPositionClassName = "java/text/FieldPosition";
292     const char * stringBufferClassName = "java/lang/StringBuffer";
293     jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
294     jclass stringBufferClass = env->FindClass(stringBufferClassName);
295     jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
296             "setBeginIndex", "(I)V");
297     jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
298             "setEndIndex", "(I)V");
299     jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
300             "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
301 
302     const char * fieldName = NULL;
303 
304     if(fieldType != NULL) {
305         fieldName = env->GetStringUTFChars(fieldType, NULL);
306     }
307 
308     uint32_t reslenneeded;
309     int64_t val = value;
310     UChar *result = NULL;
311 
312     FieldPosition fp;
313     fp.setField(FieldPosition::DONT_CARE);
314 
315     UErrorCode status = U_ZERO_ERROR;
316 
317     DecimalFormat::AttrBuffer attrBuffer = NULL;
318     attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
319     attrBuffer->bufferSize = 128;
320     attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
321     attrBuffer->buffer[0] = '\0';
322 
323     DecimalFormat *fmt = (DecimalFormat *)(int)addr;
324 
325     UnicodeString *res = new UnicodeString();
326 
327     fmt->format(val, *res, fp, attrBuffer);
328 
329     reslenneeded = res->extract(NULL, 0, status);
330 
331     if(status==U_BUFFER_OVERFLOW_ERROR) {
332         status=U_ZERO_ERROR;
333 
334         result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
335 
336         res->extract(result, reslenneeded + 1, status);
337     }
338     if (icuError(env, status) != FALSE) {
339         free(attrBuffer->buffer);
340         free(attrBuffer);
341         free(result);
342         delete(res);
343         return NULL;
344     }
345 
346     int attrLength = 0;
347 
348     attrLength = (strlen(attrBuffer->buffer) + 1 );
349 
350     if(strlen(attrBuffer->buffer) > 0) {
351 
352         // check if we want to get all attributes
353         if(attributes != NULL) {
354             jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
355             env->CallObjectMethod(attributes, appendMethodID, attrString);
356         }
357 
358         // check if we want one special attribute returned in the given FieldPos
359         if(fieldName != NULL && field != NULL) {
360             const char *delimiter = ";";
361             int begin;
362             int end;
363             char * resattr;
364             resattr = strtok(attrBuffer->buffer, delimiter);
365 
366             while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
367                 resattr = strtok(NULL, delimiter);
368             }
369 
370             if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
371                 resattr = strtok(NULL, delimiter);
372                 begin = (int) strtol(resattr, NULL, 10);
373                 resattr = strtok(NULL, delimiter);
374                 end = (int) strtol(resattr, NULL, 10);
375 
376                 env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
377                 env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
378             }
379         }
380     }
381 
382     if(fieldType != NULL) {
383         env->ReleaseStringUTFChars(fieldType, fieldName);
384     }
385 
386     jstring resulting = env->NewString(result, reslenneeded);
387 
388     free(attrBuffer->buffer);
389     free(attrBuffer);
390     free(result);
391     delete(res);
392 
393     return resulting;
394 }
395 
formatDouble(JNIEnv * env,jclass clazz,jint addr,jdouble value,jobject field,jstring fieldType,jobject attributes)396 static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value,
397         jobject field, jstring fieldType, jobject attributes) {
398 
399     const char * fieldPositionClassName = "java/text/FieldPosition";
400     const char * stringBufferClassName = "java/lang/StringBuffer";
401     jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
402     jclass stringBufferClass = env->FindClass(stringBufferClassName);
403     jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass,
404             "setBeginIndex", "(I)V");
405     jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass,
406             "setEndIndex", "(I)V");
407     jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
408             "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
409 
410     const char * fieldName = NULL;
411 
412     if(fieldType != NULL) {
413         fieldName = env->GetStringUTFChars(fieldType, NULL);
414     }
415 
416     uint32_t reslenneeded;
417     double val = value;
418     UChar *result = NULL;
419 
420     FieldPosition fp;
421     fp.setField(FieldPosition::DONT_CARE);
422 
423     UErrorCode status = U_ZERO_ERROR;
424 
425     DecimalFormat::AttrBuffer attrBuffer = NULL;
426     attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
427     attrBuffer->bufferSize = 128;
428     attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
429     attrBuffer->buffer[0] = '\0';
430 
431     DecimalFormat *fmt = (DecimalFormat *)(int)addr;
432 
433     UnicodeString *res = new UnicodeString();
434 
435     fmt->format(val, *res, fp, attrBuffer);
436 
437     reslenneeded = res->extract(NULL, 0, status);
438 
439     if(status==U_BUFFER_OVERFLOW_ERROR) {
440         status=U_ZERO_ERROR;
441 
442         result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
443 
444         res->extract(result, reslenneeded + 1, status);
445 
446     }
447     if (icuError(env, status) != FALSE) {
448         free(attrBuffer->buffer);
449         free(attrBuffer);
450         free(result);
451         delete(res);
452         return NULL;
453     }
454 
455     int attrLength = 0;
456 
457     attrLength = (strlen(attrBuffer->buffer) + 1 );
458 
459     if(strlen(attrBuffer->buffer) > 0) {
460 
461         // check if we want to get all attributes
462         if(attributes != NULL) {
463             jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
464             env->CallObjectMethod(attributes, appendMethodID, attrString);
465         }
466 
467         // check if we want one special attribute returned in the given FieldPos
468         if(fieldName != NULL && field != NULL) {
469             const char *delimiter = ";";
470             int begin;
471             int end;
472             char * resattr;
473             resattr = strtok(attrBuffer->buffer, delimiter);
474 
475             while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
476                 resattr = strtok(NULL, delimiter);
477             }
478 
479             if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
480                 resattr = strtok(NULL, delimiter);
481                 begin = (int) strtol(resattr, NULL, 10);
482                 resattr = strtok(NULL, delimiter);
483                 end = (int) strtol(resattr, NULL, 10);
484 
485                 env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
486                 env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
487             }
488         }
489     }
490 
491     if(fieldType != NULL) {
492         env->ReleaseStringUTFChars(fieldType, fieldName);
493     }
494 
495     jstring resulting = env->NewString(result, reslenneeded);
496 
497     free(attrBuffer->buffer);
498     free(attrBuffer);
499     free(result);
500     delete(res);
501 
502     return resulting;
503 }
504 
formatDigitList(JNIEnv * env,jclass clazz,jint addr,jstring value,jobject field,jstring fieldType,jobject attributes,jint scale)505 static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value,
506         jobject field, jstring fieldType, jobject attributes, jint scale) {
507 
508     // const char * valueUTF = env->GetStringUTFChars(value, NULL);
509     // LOGI("ENTER formatDigitList: %s, scale: %d", valueUTF, scale);
510     // env->ReleaseStringUTFChars(value, valueUTF);
511 
512     if (scale < 0) {
513         icuError(env, U_ILLEGAL_ARGUMENT_ERROR);
514         return NULL;
515     }
516 
517     const char * fieldName = NULL;
518     if(fieldType != NULL) {
519         fieldName = env->GetStringUTFChars(fieldType, NULL);
520     }
521 
522     uint32_t reslenneeded;
523 
524     // prepare digit list
525 
526     const char *valueChars = env->GetStringUTFChars(value, NULL);
527 
528     bool isInteger = (scale == 0);
529     bool isPositive = (*valueChars != '-');
530 
531     // skip the '-' if the number is negative
532     const char *digits = (isPositive ? valueChars : valueChars + 1);
533     int length = strlen(digits);
534 
535     // The length of our digit list buffer must be the actual string length + 3,
536     // because ICU will append some additional characters at the head and at the
537     // tail of the string, in order to keep strtod() happy:
538     //
539     // - The sign "+" or "-" is appended at the head
540     // - The exponent "e" and the "\0" terminator is appended at the tail
541     //
542     // In retrospect, the changes to ICU's DigitList that were necessary for
543     // big numbers look a bit hacky. It would make sense to rework all this
544     // once ICU 4.x has been integrated into Android. Ideally, big number
545     // support would make it into ICU itself, so we don't need our private
546     // fix anymore.
547     DigitList digitList(length + 3);
548     digitList.fCount = length;
549     strcpy(digitList.fDigits, digits);
550     env->ReleaseStringUTFChars(value, valueChars);
551 
552     digitList.fDecimalAt = digitList.fCount - scale;
553     digitList.fIsPositive = isPositive;
554     digitList.fRoundingMode = DecimalFormat::kRoundHalfUp;
555 
556     UChar *result = NULL;
557 
558     FieldPosition fp;
559     fp.setField(FieldPosition::DONT_CARE);
560     fp.setBeginIndex(0);
561     fp.setEndIndex(0);
562 
563     UErrorCode status = U_ZERO_ERROR;
564 
565     DecimalFormat::AttributeBuffer *attrBuffer = NULL;
566     attrBuffer = (DecimalFormat::AttributeBuffer *) calloc(sizeof(DecimalFormat::AttributeBuffer), 1);
567     attrBuffer->bufferSize = 128;
568     attrBuffer->buffer = (char *) calloc(129 * sizeof(char), 1);
569 
570     DecimalFormat *fmt = (DecimalFormat *)(int)addr;
571 
572     UnicodeString res;
573 
574     fmt->subformat(res, fp, attrBuffer, digitList, isInteger);
575 
576     reslenneeded = res.extract(NULL, 0, status);
577 
578     if(status==U_BUFFER_OVERFLOW_ERROR) {
579         status=U_ZERO_ERROR;
580 
581         result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));
582 
583         res.extract(result, reslenneeded + 1, status);
584 
585         if (icuError(env, status) != FALSE) {
586             if(fieldType != NULL) {
587                 env->ReleaseStringUTFChars(fieldType, fieldName);
588             }
589             free(result);
590             free(attrBuffer->buffer);
591             free(attrBuffer);
592             return NULL;
593         }
594 
595     } else {
596         if(fieldType != NULL) {
597             env->ReleaseStringUTFChars(fieldType, fieldName);
598         }
599         free(attrBuffer->buffer);
600         free(attrBuffer);
601         return NULL;
602     }
603 
604     int attrLength = (strlen(attrBuffer->buffer) + 1 );
605 
606     if(attrLength > 1) {
607 
608         // check if we want to get all attributes
609         if(attributes != NULL) {
610             // prepare the classes and method ids
611             const char * stringBufferClassName = "java/lang/StringBuffer";
612             jclass stringBufferClass = env->FindClass(stringBufferClassName);
613             jmethodID appendMethodID = env->GetMethodID(stringBufferClass,
614                     "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
615 
616             jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
617             env->CallObjectMethod(attributes, appendMethodID, attrString);
618         }
619 
620         // check if we want one special attribute returned in the given FieldPos
621         if(fieldName != NULL && field != NULL) {
622             const char *delimiter = ";";
623             int begin;
624             int end;
625             char * resattr;
626             resattr = strtok(attrBuffer->buffer, delimiter);
627 
628             while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
629                 resattr = strtok(NULL, delimiter);
630             }
631 
632             if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
633 
634                 // prepare the classes and method ids
635                 const char * fieldPositionClassName =
636                         "java/text/FieldPosition";
637                 jclass fieldPositionClass = env->FindClass(
638                         fieldPositionClassName);
639                 jmethodID setBeginIndexMethodID = env->GetMethodID(
640                         fieldPositionClass, "setBeginIndex", "(I)V");
641                 jmethodID setEndIndexMethodID = env->GetMethodID(
642                        fieldPositionClass, "setEndIndex", "(I)V");
643 
644 
645                 resattr = strtok(NULL, delimiter);
646                 begin = (int) strtol(resattr, NULL, 10);
647                 resattr = strtok(NULL, delimiter);
648                 end = (int) strtol(resattr, NULL, 10);
649 
650                 env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
651                 env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
652             }
653         }
654     }
655 
656     if(fieldType != NULL) {
657         env->ReleaseStringUTFChars(fieldType, fieldName);
658     }
659 
660     jstring resulting = env->NewString(result, reslenneeded);
661 
662     free(attrBuffer->buffer);
663     free(attrBuffer);
664     free(result);
665     // const char * resultUTF = env->GetStringUTFChars(resulting, NULL);
666     // LOGI("RETURN formatDigitList: %s", resultUTF);
667     // env->ReleaseStringUTFChars(resulting, resultUTF);
668 
669     return resulting;
670 }
671 
parse(JNIEnv * env,jclass clazz,jint addr,jstring text,jobject position)672 static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
673         jobject position) {
674 
675     const char * textUTF = env->GetStringUTFChars(text, NULL);
676     env->ReleaseStringUTFChars(text, textUTF);
677 
678     const char * parsePositionClassName = "java/text/ParsePosition";
679     const char * longClassName = "java/lang/Long";
680     const char * doubleClassName = "java/lang/Double";
681     const char * bigDecimalClassName = "java/math/BigDecimal";
682     const char * bigIntegerClassName = "java/math/BigInteger";
683 
684     UErrorCode status = U_ZERO_ERROR;
685 
686     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
687 
688     jchar *str = (UChar *)env->GetStringChars(text, NULL);
689     int strlength = env->GetStringLength(text);
690 
691     jclass parsePositionClass = env->FindClass(parsePositionClassName);
692     jclass longClass =  env->FindClass(longClassName);
693     jclass doubleClass =  env->FindClass(doubleClassName);
694     jclass bigDecimalClass = env->FindClass(bigDecimalClassName);
695     jclass bigIntegerClass = env->FindClass(bigIntegerClassName);
696 
697     jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass,
698             "getIndex", "()I");
699     jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass,
700             "setIndex", "(I)V");
701     jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass,
702             "setErrorIndex", "(I)V");
703 
704     jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
705     jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
706     jmethodID bigDecimalInitMethodID = env->GetMethodID(bigDecimalClass, "<init>", "(Ljava/math/BigInteger;I)V");
707     jmethodID bigIntegerInitMethodID = env->GetMethodID(bigIntegerClass, "<init>", "(Ljava/lang/String;)V");
708     jmethodID doubleValueMethodID = env->GetMethodID(bigDecimalClass, "doubleValue", "()D");
709 
710     bool resultAssigned;
711     int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
712 
713     // make sure the ParsePosition is valid. Actually icu4c would parse a number
714     // correctly even if the parsePosition is set to -1, but since the RI fails
715     // for that case we have to fail too
716     if(parsePos < 0 || parsePos > strlength) {
717         return NULL;
718     }
719 
720     Formattable res;
721 
722     const UnicodeString src((UChar*)str, strlength, strlength);
723     ParsePosition pp;
724 
725     pp.setIndex(parsePos);
726 
727     DigitList digits;
728 
729     ((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits);
730 
731     env->ReleaseStringChars(text, str);
732 
733     if(pp.getErrorIndex() == -1) {
734         parsePos = pp.getIndex();
735     } else {
736         env->CallVoidMethod(position, setErrorIndexMethodID,
737                 (jint) pp.getErrorIndex());
738         return NULL;
739     }
740 
741     Formattable::Type numType;
742     numType = res.getType();
743     UErrorCode fmtStatus;
744 
745     double resultDouble;
746     long resultLong;
747     int64_t resultInt64;
748     UnicodeString resultString;
749     jstring resultStr;
750     int resLength;
751     const char * resultUTF;
752     jobject resultObject1, resultObject2;
753     jdouble doubleTest;
754     jchar * result;
755 
756     if (resultAssigned)
757     {
758         switch(numType) {
759         case Formattable::kDouble:
760             resultDouble = res.getDouble();
761             env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
762             return env->NewObject(doubleClass, dblInitMethodID,
763                     (jdouble) resultDouble);
764         case Formattable::kLong:
765             resultLong = res.getLong();
766             env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
767             return env->NewObject(longClass, longInitMethodID,
768                     (jlong) resultLong);
769         case Formattable::kInt64:
770             resultInt64 = res.getInt64();
771             env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
772             return env->NewObject(longClass, longInitMethodID,
773                     (jlong) resultInt64);
774         default:
775             return NULL;
776         }
777     }
778     else
779     {
780         int scale = digits.fCount - digits.fDecimalAt;
781         // ATTENTION: Abuse of Implementation Knowlegde!
782         digits.fDigits[digits.fCount] = 0;
783         if (digits.fIsPositive) {
784             resultStr = env->NewStringUTF(digits.fDigits);
785         } else {
786             if (digits.fCount == 0) {
787                 env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
788                 return env->NewObject(doubleClass, dblInitMethodID, (jdouble)-0);
789             } else {
790                 // ATTENTION: Abuse of Implementation Knowlegde!
791                 *(digits.fDigits - 1) = '-';
792                 resultStr = env->NewStringUTF(digits.fDigits - 1);
793             }
794         }
795 
796         env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
797 
798         resultObject1 = env->NewObject(bigIntegerClass, bigIntegerInitMethodID, resultStr);
799         resultObject2 = env->NewObject(bigDecimalClass, bigDecimalInitMethodID, resultObject1, scale);
800         return resultObject2;
801     }
802 }
803 
cloneImpl(JNIEnv * env,jclass clazz,jint addr)804 static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) {
805 
806     UErrorCode status = U_ZERO_ERROR;
807 
808     UNumberFormat *fmt = (UNumberFormat *)(int)addr;
809 
810     UNumberFormat *result = unum_clone(fmt, &status);
811 
812     if(icuError(env, status) != FALSE) {
813         return 0;
814     }
815 
816     return (long) result;
817 
818 }
819 
820 static JNINativeMethod gMethods[] = {
821     /* name, signature, funcPtr */
822     {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;)I",
823             (void*) openDecimalFormatImpl},
824     {"closeDecimalFormatImpl", "(I)V", (void*) closeDecimalFormatImpl},
825     {"setSymbol", "(IILjava/lang/String;)V", (void*) setSymbol},
826     {"getSymbol", "(II)Ljava/lang/String;", (void*) getSymbol},
827     {"setAttribute", "(III)V", (void*) setAttribute},
828     {"getAttribute", "(II)I", (void*) getAttribute},
829     {"setTextAttribute", "(IILjava/lang/String;)V", (void*) setTextAttribute},
830     {"getTextAttribute", "(II)Ljava/lang/String;", (void*) getTextAttribute},
831     {"applyPatternImpl", "(IZLjava/lang/String;)V", (void*) applyPatternImpl},
832     {"toPatternImpl", "(IZ)Ljava/lang/String;", (void*) toPatternImpl},
833     {"format",
834             "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
835             (void*) formatLong},
836     {"format",
837             "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;",
838             (void*) formatDouble},
839     {"format",
840             "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;",
841             (void*) formatDigitList},
842     {"parse",
843             "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;",
844             (void*) parse},
845     {"cloneImpl", "(I)I", (void*) cloneImpl}
846 };
register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv * env)847 int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) {
848     return jniRegisterNativeMethods(env,
849             "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods,
850             NELEM(gMethods));
851 }
852