StandardPlural::Form QuantityFormatter::selectPlural( const Formattable &number, const NumberFormat &fmt, const PluralRules &rules, UnicodeString &formattedNumber, FieldPosition &pos, UErrorCode &status) { if (U_FAILURE(status)) { return StandardPlural::OTHER; } UnicodeString pluralKeyword; const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); if (decFmt != NULL) { number::impl::DecimalQuantity dq; decFmt->formatToDecimalQuantity(number, dq, status); if (U_FAILURE(status)) { return StandardPlural::OTHER; } pluralKeyword = rules.select(dq); decFmt->format(number, formattedNumber, pos, status); } else { if (number.getType() == Formattable::kDouble) { pluralKeyword = rules.select(number.getDouble()); } else if (number.getType() == Formattable::kLong) { pluralKeyword = rules.select(number.getLong()); } else if (number.getType() == Formattable::kInt64) { pluralKeyword = rules.select((double) number.getInt64()); } else { status = U_ILLEGAL_ARGUMENT_ERROR; return StandardPlural::OTHER; } fmt.format(number, formattedNumber, pos, status); } return StandardPlural::orOtherFromString(pluralKeyword); }
static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jlong addr, jstring text, jobject position, jboolean parseBigDecimal) { static jmethodID gPP_getIndex = env->GetMethodID(JniConstants::parsePositionClass, "getIndex", "()I"); static jmethodID gPP_setIndex = env->GetMethodID(JniConstants::parsePositionClass, "setIndex", "(I)V"); static jmethodID gPP_setErrorIndex = env->GetMethodID(JniConstants::parsePositionClass, "setErrorIndex", "(I)V"); ScopedJavaUnicodeString src(env, text); if (!src.valid()) { return 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 int parsePos = env->CallIntMethod(position, gPP_getIndex, NULL); if (parsePos < 0 || parsePos > env->GetStringLength(text)) { return NULL; } Formattable res; ParsePosition pp(parsePos); DecimalFormat* fmt = toDecimalFormat(addr); fmt->parse(src.unicodeString(), res, pp); if (pp.getErrorIndex() == -1) { env->CallVoidMethod(position, gPP_setIndex, pp.getIndex()); } else { env->CallVoidMethod(position, gPP_setErrorIndex, pp.getErrorIndex()); return NULL; } if (parseBigDecimal) { UErrorCode status = U_ZERO_ERROR; StringPiece str = res.getDecimalNumber(status); if (U_SUCCESS(status)) { int len = str.length(); const char* data = str.data(); if (strncmp(data, "NaN", 3) == 0 || strncmp(data, "Inf", 3) == 0 || strncmp(data, "-Inf", 4) == 0) { double resultDouble = res.getDouble(status); return doubleValueOf(env, resultDouble); } return newBigDecimal(env, data, len); } return NULL; } switch (res.getType()) { case Formattable::kDouble: return doubleValueOf(env, res.getDouble()); case Formattable::kLong: return longValueOf(env, res.getLong()); case Formattable::kInt64: return longValueOf(env, res.getInt64()); default: return NULL; } }
U_CAPI int64_t U_EXPORT2 unum_parseInt64( const UNumberFormat* fmt, const UChar* text, int32_t textLength, int32_t *parsePos /* 0 = start */, UErrorCode *status) { Formattable res; parseRes(res, fmt, text, textLength, parsePos, FALSE, status); return res.getInt64(*status); }
U_DRAFT int64_t U_EXPORT2 ufmt_getInt64(UFormattable *fmt, UErrorCode *status) { Formattable *obj = Formattable::fromUFormattable(fmt); return obj->getInt64(*status); }
void MessageFormatRegressionTest::Test4031438() { UErrorCode status = U_ZERO_ERROR; UnicodeString pattern1("Impossible {1} has occurred -- status code is {0} and message is {2}."); UnicodeString pattern2("Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."); MessageFormat *messageFormatter = new MessageFormat("", status); failure(status, "new MessageFormat"); const UBool possibleDataError = TRUE; //try { logln("Apply with pattern : " + pattern1); messageFormatter->applyPattern(pattern1, status); failure(status, "messageFormat->applyPattern"); //Object[] params = {new Integer(7)}; Formattable params []= { Formattable((int32_t)7) }; UnicodeString tempBuffer; FieldPosition pos(FieldPosition::DONT_CARE); tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); if(tempBuffer != "Impossible {1} has occurred -- status code is 7 and message is {2}." || failure(status, "MessageFormat::format")) dataerrln("Tests arguments < substitution failed"); logln("Formatted with 7 : " + tempBuffer); ParsePosition pp(0); int32_t count = 0; Formattable *objs = messageFormatter->parse(tempBuffer, pp, count); //if(objs[7/*params.length*/] != NULL) // errln("Parse failed with more than expected arguments"); NumberFormat *fmt = 0; UnicodeString temp, temp1; for (int i = 0; i < count; i++) { // convert to string if not already Formattable obj = objs[i]; temp.remove(); if(obj.getType() == Formattable::kString) temp = obj.getString(temp); else { fmt = NumberFormat::createInstance(status); switch (obj.getType()) { case Formattable::kLong: fmt->format(obj.getLong(), temp); break; case Formattable::kInt64: fmt->format(obj.getInt64(), temp); break; case Formattable::kDouble: fmt->format(obj.getDouble(), temp); break; default: break; } } // convert to string if not already Formattable obj1 = params[i]; temp1.remove(); if(obj1.getType() == Formattable::kString) temp1 = obj1.getString(temp1); else { fmt = NumberFormat::createInstance(status); switch (obj1.getType()) { case Formattable::kLong: fmt->format(obj1.getLong(), temp1); break; case Formattable::kInt64: fmt->format(obj1.getInt64(), temp1); break; case Formattable::kDouble: fmt->format(obj1.getDouble(), temp1); break; default: break; } } //if (objs[i] != NULL && objs[i].getString(temp1) != params[i].getString(temp2)) { if (temp != temp1) { errln("Parse failed on object " + objs[i].getString(temp1) + " at index : " + i); } } delete fmt; delete [] objs; // {sfb} does this apply? no way to really pass a null Formattable, // only a null array /*tempBuffer = messageFormatter->format(null, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status); if (tempBuffer != "Impossible {1} has occurred -- status code is {0} and message is {2}." || failure(status, "messageFormat->format")) errln("Tests with no arguments failed"); logln("Formatted with null : " + tempBuffer);*/ logln("Apply with pattern : " + pattern2); messageFormatter->applyPattern(pattern2, status); failure(status, "messageFormatter->applyPattern", possibleDataError); tempBuffer.remove(); tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); if (tempBuffer != "Double ' Quotes 7 test and quoted {1} test plus other {2} stuff.") dataerrln("quote format test (w/ params) failed. - %s", u_errorName(status)); logln("Formatted with params : " + tempBuffer); /*tempBuffer = messageFormatter->format(null); if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff.")) errln("quote format test (w/ null) failed."); logln("Formatted with null : " + tempBuffer); logln("toPattern : " + messageFormatter.toPattern());*/ /*} catch (Exception foo) { errln("Exception when formatting in bug 4031438. "+foo.getMessage()); }*/ delete messageFormatter; }
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; }