diff --git a/ext/intl/formatter/formatter_attr.cpp b/ext/intl/formatter/formatter_attr.cpp index 905a4415ef59b..ffab2a9aa3c16 100644 --- a/ext/intl/formatter/formatter_attr.cpp +++ b/ext/intl/formatter/formatter_attr.cpp @@ -16,13 +16,16 @@ #include #endif +#include +#include "../intl_convertcpp.h" +#include "formatter_class.h" + extern "C" { #include "php_intl.h" #include "intl_convert.h" } -#include "formatter_class.h" -#include +#define FORMATTER_UNUM(nfo) reinterpret_cast(FORMATTER_OBJECT(nfo)) /* {{{ Get formatter attribute value. */ U_CFUNC PHP_FUNCTION( numfmt_get_attribute ) @@ -62,7 +65,7 @@ U_CFUNC PHP_FUNCTION( numfmt_get_attribute ) case UNUM_MIN_SIGNIFICANT_DIGITS: case UNUM_MAX_SIGNIFICANT_DIGITS: case UNUM_LENIENT_PARSE: - value = unum_getAttribute(FORMATTER_OBJECT(nfo), attribute); + value = unum_getAttribute(FORMATTER_UNUM(nfo), attribute); if(value == -1) { INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR; } else { @@ -71,7 +74,7 @@ U_CFUNC PHP_FUNCTION( numfmt_get_attribute ) break; case UNUM_ROUNDING_INCREMENT: { - double value_double = unum_getDoubleAttribute(FORMATTER_OBJECT(nfo), attribute); + double value_double = unum_getDoubleAttribute(FORMATTER_UNUM(nfo), attribute); if(value_double == -1) { INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR; } else { @@ -110,12 +113,12 @@ U_CFUNC PHP_FUNCTION( numfmt_get_text_attribute ) UNumberFormatTextAttribute attribute = static_cast(lattribute); - length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, value_buf_size, &INTL_DATA_ERROR_CODE(nfo) ); + length = unum_getTextAttribute( FORMATTER_UNUM(nfo), attribute, value, value_buf_size, &INTL_DATA_ERROR_CODE(nfo) ); if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= value_buf_size) { ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */ INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR; value = eumalloc(length); - length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, length, &INTL_DATA_ERROR_CODE(nfo) ); + length = unum_getTextAttribute( FORMATTER_UNUM(nfo), attribute, value, length, &INTL_DATA_ERROR_CODE(nfo) ); if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { efree(value); value = value_buf; @@ -166,10 +169,10 @@ U_CFUNC PHP_FUNCTION( numfmt_set_attribute ) case UNUM_MIN_SIGNIFICANT_DIGITS: case UNUM_MAX_SIGNIFICANT_DIGITS: case UNUM_LENIENT_PARSE: - unum_setAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_long(value)); + unum_setAttribute(FORMATTER_UNUM(nfo), attribute, zval_get_long(value)); break; case UNUM_ROUNDING_INCREMENT: - unum_setDoubleAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_double(value)); + unum_setDoubleAttribute(FORMATTER_UNUM(nfo), attribute, zval_get_double(value)); break; default: INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR; @@ -185,8 +188,6 @@ U_CFUNC PHP_FUNCTION( numfmt_set_attribute ) /* {{{ Get formatter attribute value. */ U_CFUNC PHP_FUNCTION( numfmt_set_text_attribute ) { - int32_t slength = 0; - UChar *svalue = NULL; zend_long attribute; char *value; size_t len; @@ -203,14 +204,12 @@ U_CFUNC PHP_FUNCTION( numfmt_set_text_attribute ) FORMATTER_METHOD_FETCH_OBJECT; /* Convert given attribute value to UTF-16. */ - intl_convert_utf8_to_utf16(&svalue, &slength, value, len, &INTL_DATA_ERROR_CODE(nfo)); + UnicodeString svalue; + intl_stringFromChar(svalue, value, len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error converting attribute value to UTF-16" ); /* Actually set new attribute value. */ - unum_setTextAttribute(FORMATTER_OBJECT(nfo), static_cast(attribute), svalue, slength, &INTL_DATA_ERROR_CODE(nfo)); - if (svalue) { - efree(svalue); - } + unum_setTextAttribute(FORMATTER_UNUM(nfo), static_cast(attribute), svalue.getBuffer(), svalue.length(), &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error setting text attribute" ); RETURN_TRUE; @@ -243,12 +242,12 @@ U_CFUNC PHP_FUNCTION( numfmt_get_symbol ) /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; - length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo)); + length = unum_getSymbol(FORMATTER_UNUM(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo)); if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) { ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */ INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR; value = eumalloc(length); - length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo)); + length = unum_getSymbol(FORMATTER_UNUM(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo)); if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { efree(value); value = value_buf; @@ -266,8 +265,6 @@ U_CFUNC PHP_FUNCTION( numfmt_set_symbol ) zend_long lsymbol; char* value = NULL; size_t value_len = 0; - UChar* svalue = 0; - int32_t slength = 0; FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ @@ -288,14 +285,12 @@ U_CFUNC PHP_FUNCTION( numfmt_set_symbol ) FORMATTER_METHOD_FETCH_OBJECT; /* Convert given symbol to UTF-16. */ - intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo)); + UnicodeString svalue; + intl_stringFromChar(svalue, value, value_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error converting symbol value to UTF-16" ); /* Actually set the symbol. */ - unum_setSymbol(FORMATTER_OBJECT(nfo), symbol, svalue, slength, &INTL_DATA_ERROR_CODE(nfo)); - if (svalue) { - efree(svalue); - } + unum_setSymbol(FORMATTER_UNUM(nfo), symbol, svalue.getBuffer(), svalue.length(), &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error setting symbol value" ); RETURN_TRUE; @@ -320,12 +315,12 @@ U_CFUNC PHP_FUNCTION( numfmt_get_pattern ) /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; - length = unum_toPattern(FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo)); + length = unum_toPattern(FORMATTER_UNUM(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo)); if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) { ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */ INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR; value = eumalloc(length); - length = unum_toPattern( FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) ); + length = unum_toPattern( FORMATTER_UNUM(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) ); if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { efree(value); value = value_buf; @@ -342,8 +337,6 @@ U_CFUNC PHP_FUNCTION( numfmt_set_pattern ) { char* value = NULL; size_t value_len = 0; - int32_t slength = 0; - UChar* svalue = NULL; UParseError spattern_error = {0}; FORMATTER_METHOD_INIT_VARS; @@ -357,13 +350,11 @@ U_CFUNC PHP_FUNCTION( numfmt_set_pattern ) FORMATTER_METHOD_FETCH_OBJECT; /* Convert given pattern to UTF-16. */ - intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo)); + UnicodeString svalue; + intl_stringFromChar(svalue, value, value_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error converting pattern to UTF-16" ); - unum_applyPattern(FORMATTER_OBJECT(nfo), 0, svalue, slength, &spattern_error, &INTL_DATA_ERROR_CODE(nfo)); - if (svalue) { - efree(svalue); - } + unum_applyPattern(FORMATTER_UNUM(nfo), 0, svalue.getBuffer(), svalue.length(), &spattern_error, &INTL_DATA_ERROR_CODE(nfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { char *msg; spprintf(&msg, 0, "Error setting pattern value at line %d, offset %d", spattern_error.line, spattern_error.offset); @@ -393,7 +384,7 @@ U_CFUNC PHP_FUNCTION( numfmt_get_locale ) /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; - loc = unum_getLocaleByType(FORMATTER_OBJECT(nfo), static_cast(type), &INTL_DATA_ERROR_CODE(nfo)); + loc = unum_getLocaleByType(FORMATTER_UNUM(nfo), static_cast(type), &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Error getting locale" ); RETURN_STRING(loc); } diff --git a/ext/intl/formatter/formatter_class.cpp b/ext/intl/formatter/formatter_class.cpp index 214e1e57dae8a..780ae07694f94 100644 --- a/ext/intl/formatter/formatter_class.cpp +++ b/ext/intl/formatter/formatter_class.cpp @@ -12,8 +12,6 @@ +----------------------------------------------------------------------+ */ -#include - #include "formatter_class.h" extern "C" { #include "php_intl.h" @@ -72,10 +70,9 @@ U_CFUNC zend_object *NumberFormatter_object_clone(zend_object *object) zend_objects_clone_members(&new_nfo->zo, &nfo->zo); /* clone formatter object. It may fail, the destruction code must handle this case */ - if (FORMATTER_OBJECT(nfo) != NULL) { - UErrorCode error = U_ZERO_ERROR; - FORMATTER_OBJECT(new_nfo) = unum_clone(FORMATTER_OBJECT(nfo), &error); - if (U_FAILURE(error)) { + if (FORMATTER_OBJECT(nfo) != nullptr) { + FORMATTER_OBJECT(new_nfo) = FORMATTER_OBJECT(nfo)->clone(); + if (FORMATTER_OBJECT(new_nfo) == nullptr) { zend_throw_error(NULL, "Failed to clone NumberFormatter"); } } else { diff --git a/ext/intl/formatter/formatter_class.h b/ext/intl/formatter/formatter_class.h index bf21825b5f5f4..a56e50c6d0253 100644 --- a/ext/intl/formatter/formatter_class.h +++ b/ext/intl/formatter/formatter_class.h @@ -15,7 +15,7 @@ #ifndef FORMATTER_CLASS_H #define FORMATTER_CLASS_H -#include +#include "formatter_data.h" #ifdef __cplusplus extern "C" { @@ -23,7 +23,6 @@ extern "C" { #include "intl_common.h" #include "intl_error.h" #include "intl_data.h" -#include "formatter_data.h" #ifdef __cplusplus } #endif diff --git a/ext/intl/formatter/formatter_data.cpp b/ext/intl/formatter/formatter_data.cpp index 095be92ed29e1..6c9669dc7ac48 100644 --- a/ext/intl/formatter/formatter_data.cpp +++ b/ext/intl/formatter/formatter_data.cpp @@ -26,7 +26,7 @@ void formatter_data_init( formatter_data* nf_data ) if( !nf_data ) return; - nf_data->unum = NULL; + nf_data->unum = nullptr; intl_error_reset( &nf_data->error ); } /* }}} */ @@ -39,10 +39,8 @@ void formatter_data_free( formatter_data* nf_data ) if( !nf_data ) return; - if( nf_data->unum ) - unum_close( nf_data->unum ); - - nf_data->unum = NULL; + delete nf_data->unum; + nf_data->unum = nullptr; intl_error_reset( &nf_data->error ); } /* }}} */ diff --git a/ext/intl/formatter/formatter_data.h b/ext/intl/formatter/formatter_data.h index 35acc242a8db9..3e66f43471b1d 100644 --- a/ext/intl/formatter/formatter_data.h +++ b/ext/intl/formatter/formatter_data.h @@ -15,9 +15,21 @@ #ifndef FORMATTER_DATA_H #define FORMATTER_DATA_H +#ifdef __cplusplus +extern "C" { +#endif #include +#ifdef __cplusplus +} +#endif + +#include -#include +#ifdef __cplusplus +using icu::NumberFormat; +#else +typedef void NumberFormat; +#endif #ifdef __cplusplus extern "C" { @@ -32,7 +44,7 @@ typedef struct { intl_error error; // formatter handling - UNumberFormat* unum; + NumberFormat* unum; } formatter_data; #ifdef __cplusplus diff --git a/ext/intl/formatter/formatter_format.cpp b/ext/intl/formatter/formatter_format.cpp index f28ea30b9ff8f..26eb03b2c5386 100644 --- a/ext/intl/formatter/formatter_format.cpp +++ b/ext/intl/formatter/formatter_format.cpp @@ -16,24 +16,21 @@ #include #endif +#include +#include +#include "../intl_convertcpp.h" +#include "formatter_class.h" +#include "formatter_format.h" + extern "C" { #include "php_intl.h" -#include "intl_convert.h" } -#include - -#include "formatter_class.h" -#include "formatter_format.h" - /* {{{ Format a number. */ U_CFUNC PHP_FUNCTION( numfmt_format ) { zval *number; zend_long type = FORMAT_TYPE_DEFAULT; - UChar format_buf[32]; - UChar* formatted = format_buf; - int32_t formatted_len = USIZE(format_buf); FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ @@ -59,50 +56,27 @@ U_CFUNC PHP_FUNCTION( numfmt_format ) } } + icu::UnicodeString result; + icu::FieldPosition pos; + switch(type) { case FORMAT_TYPE_INT32: convert_to_long(number); - formatted_len = unum_format(FORMATTER_OBJECT(nfo), (int32_t)Z_LVAL_P(number), - formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) { - intl_error_reset(INTL_DATA_ERROR_P(nfo)); - formatted = eumalloc(formatted_len); - formatted_len = unum_format(FORMATTER_OBJECT(nfo), (int32_t)Z_LVAL_P(number), - formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) { - efree(formatted); - } - } + FORMATTER_OBJECT(nfo)->format((int32_t)Z_LVAL_P(number), result, pos, INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" ); break; case FORMAT_TYPE_INT64: { int64_t value = (Z_TYPE_P(number) == IS_DOUBLE)?(int64_t)Z_DVAL_P(number):Z_LVAL_P(number); - formatted_len = unum_formatInt64(FORMATTER_OBJECT(nfo), value, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) { - intl_error_reset(INTL_DATA_ERROR_P(nfo)); - formatted = eumalloc(formatted_len); - formatted_len = unum_formatInt64(FORMATTER_OBJECT(nfo), value, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) { - efree(formatted); - } - } + FORMATTER_OBJECT(nfo)->format(value, result, pos, INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" ); } break; case FORMAT_TYPE_DOUBLE: convert_to_double(number); - formatted_len = unum_formatDouble(FORMATTER_OBJECT(nfo), Z_DVAL_P(number), formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) { - intl_error_reset(INTL_DATA_ERROR_P(nfo)); - formatted = eumalloc(formatted_len); - unum_formatDouble(FORMATTER_OBJECT(nfo), Z_DVAL_P(number), formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) { - efree(formatted); - } - } + FORMATTER_OBJECT(nfo)->format(Z_DVAL_P(number), result, pos, INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" ); break; case FORMAT_TYPE_CURRENCY: @@ -120,7 +94,9 @@ U_CFUNC PHP_FUNCTION( numfmt_format ) RETURN_THROWS(); } - INTL_METHOD_RETVAL_UTF8( nfo, formatted, formatted_len, ( formatted != format_buf ) ); + zend_string *u8str = intl_charFromString(result, &INTL_DATA_ERROR_CODE(nfo)); + INTL_METHOD_CHECK_STATUS(nfo, "Error converting result to UTF-8"); + RETVAL_STR(u8str); } /* }}} */ @@ -128,13 +104,8 @@ U_CFUNC PHP_FUNCTION( numfmt_format ) U_CFUNC PHP_FUNCTION( numfmt_format_currency ) { double number; - UChar format_buf[32]; - UChar* formatted = format_buf; - int32_t formatted_len = USIZE(format_buf); char* currency = NULL; size_t currency_len = 0; - UChar* scurrency = NULL; - int32_t scurrency_len = 0; FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ @@ -148,36 +119,31 @@ U_CFUNC PHP_FUNCTION( numfmt_format_currency ) FORMATTER_METHOD_FETCH_OBJECT; /* Convert currency to UTF-16. */ - intl_convert_utf8_to_utf16(&scurrency, &scurrency_len, currency, currency_len, &INTL_DATA_ERROR_CODE(nfo)); + icu::UnicodeString ucurrency; + intl_stringFromChar(ucurrency, currency, currency_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Currency conversion to UTF-16 failed" ); - /* Format the number using a fixed-length buffer. */ - formatted_len = unum_formatDoubleCurrency(FORMATTER_OBJECT(nfo), number, scurrency, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); - - /* If the buffer turned out to be too small - * then allocate another buffer dynamically - * and use it to format the number. - */ - if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) { - intl_error_reset(INTL_DATA_ERROR_P(nfo)); - formatted = eumalloc(formatted_len); - unum_formatDoubleCurrency(FORMATTER_OBJECT(nfo), number, scurrency, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo)); + /* Format using CurrencyAmount. */ + icu::CurrencyAmount *currAmt = new icu::CurrencyAmount(number, ucurrency.getTerminatedBuffer(), INTL_DATA_ERROR_CODE(nfo)); + if (U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { + delete currAmt; + intl_errors_set_custom_msg(INTL_DATA_ERROR_P(nfo), "Number formatting failed"); + RETURN_FALSE; } - - if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) ) { - intl_error_set_code( NULL, INTL_DATA_ERROR_CODE((nfo)) ); - intl_errors_set_custom_msg( INTL_DATA_ERROR_P(nfo), "Number formatting failed"); - RETVAL_FALSE; - if (formatted != format_buf) { - efree(formatted); - } - } else { - INTL_METHOD_RETVAL_UTF8( nfo, formatted, formatted_len, ( formatted != format_buf ) ); + icu::Formattable fmt; + fmt.adoptObject(currAmt); + icu::UnicodeString result; + icu::FieldPosition pos; + FORMATTER_OBJECT(nfo)->format(fmt, result, pos, INTL_DATA_ERROR_CODE(nfo)); + + if (U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { + intl_errors_set_custom_msg(INTL_DATA_ERROR_P(nfo), "Number formatting failed"); + RETURN_FALSE; } - if(scurrency) { - efree(scurrency); - } + zend_string *u8str = intl_charFromString(result, &INTL_DATA_ERROR_CODE(nfo)); + INTL_METHOD_CHECK_STATUS(nfo, "Error converting result to UTF-8"); + RETVAL_STR(u8str); } /* }}} */ diff --git a/ext/intl/formatter/formatter_main.cpp b/ext/intl/formatter/formatter_main.cpp index a014323089a7e..be2c8b8d1100c 100644 --- a/ext/intl/formatter/formatter_main.cpp +++ b/ext/intl/formatter/formatter_main.cpp @@ -16,14 +16,17 @@ #include #endif -#include -#include +#include +#include +#include +#include +#include +#include "../intl_convertcpp.h" +#include "formatter_class.h" extern "C" { #include "php_intl.h" -#include "intl_convert.h" } -#include "formatter_class.h" /* {{{ */ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) @@ -32,8 +35,7 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) char* pattern = NULL; size_t locale_len = 0, pattern_len = 0; zend_long style; - UChar* spattern = NULL; - int32_t spattern_len = 0; + UnicodeString upattern; FORMATTER_METHOD_INIT_VARS; ZEND_PARSE_PARAMETERS_START(2, 3) @@ -53,7 +55,7 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) /* Convert pattern (if specified) to UTF-16. */ if(pattern && pattern_len) { - intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo)); + intl_stringFromChar(upattern, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_CTOR_CHECK_STATUS(nfo, "error converting pattern to UTF-16"); } @@ -61,7 +63,7 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) locale = (char *)intl_locale_get_default(); } - if (strlen(uloc_getISO3Language(locale)) == 0) { + if (icu::Locale(locale).getISO3Language()[0] == '\0') { zend_argument_value_error(1, "\"%s\" is invalid", locale); return FAILURE; } @@ -70,12 +72,55 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) const char* final_locale = canonicalized_locale ? canonicalized_locale : locale; /* Create an ICU number formatter. */ - FORMATTER_OBJECT(nfo) = unum_open(static_cast(style), spattern, spattern_len, final_locale, nullptr, &INTL_DATA_ERROR_CODE(nfo)); - - if (spattern) { - efree(spattern); + icu::Locale loc(final_locale); + switch (style) { + case UNUM_PATTERN_DECIMAL: { + icu::DecimalFormatSymbols *syms = new icu::DecimalFormatSymbols(loc, INTL_DATA_ERROR_CODE(nfo)); + if (U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) { + delete syms; + break; + } + FORMATTER_OBJECT(nfo) = new icu::DecimalFormat(upattern, syms, INTL_DATA_ERROR_CODE(nfo)); + if (FORMATTER_OBJECT(nfo) == nullptr) { + delete syms; + } + break; + } + case UNUM_PATTERN_RULEBASED: { + UParseError parseError; + FORMATTER_OBJECT(nfo) = new icu::RuleBasedNumberFormat(upattern, loc, parseError, INTL_DATA_ERROR_CODE(nfo)); + break; + } + case UNUM_SPELLOUT: + FORMATTER_OBJECT(nfo) = new icu::RuleBasedNumberFormat(icu::URBNF_SPELLOUT, loc, INTL_DATA_ERROR_CODE(nfo)); + break; + case UNUM_ORDINAL: + FORMATTER_OBJECT(nfo) = new icu::RuleBasedNumberFormat(icu::URBNF_ORDINAL, loc, INTL_DATA_ERROR_CODE(nfo)); + break; + case UNUM_DURATION: + FORMATTER_OBJECT(nfo) = new icu::RuleBasedNumberFormat(icu::URBNF_DURATION, loc, INTL_DATA_ERROR_CODE(nfo)); + break; + case UNUM_NUMBERING_SYSTEM: { + UErrorCode localErr = U_ZERO_ERROR; + int32_t keywordLength = loc.getKeywordValue("numbers", nullptr, 0, localErr); + if (keywordLength > 0) { + FORMATTER_OBJECT(nfo) = NumberFormat::createInstance(loc, UNUM_DEFAULT, INTL_DATA_ERROR_CODE(nfo)); + } else { + FORMATTER_OBJECT(nfo) = new icu::RuleBasedNumberFormat(icu::URBNF_NUMBERING_SYSTEM, loc, INTL_DATA_ERROR_CODE(nfo)); + } + break; + } + case UNUM_DECIMAL_COMPACT_SHORT: + FORMATTER_OBJECT(nfo) = icu::CompactDecimalFormat::createInstance(loc, UNUM_SHORT, INTL_DATA_ERROR_CODE(nfo)); + break; + case UNUM_DECIMAL_COMPACT_LONG: + FORMATTER_OBJECT(nfo) = icu::CompactDecimalFormat::createInstance(loc, UNUM_LONG, INTL_DATA_ERROR_CODE(nfo)); + break; + default: + FORMATTER_OBJECT(nfo) = NumberFormat::createInstance(loc, static_cast(style), INTL_DATA_ERROR_CODE(nfo)); + break; } - + if (canonicalized_locale) { efree(canonicalized_locale); } diff --git a/ext/intl/formatter/formatter_parse.cpp b/ext/intl/formatter/formatter_parse.cpp index c7d0df8cbda02..07ad42dcf07ca 100644 --- a/ext/intl/formatter/formatter_parse.cpp +++ b/ext/intl/formatter/formatter_parse.cpp @@ -16,31 +16,27 @@ #include #endif +#include +#include +#include "../intl_convertcpp.h" +#include "formatter_class.h" +#include "formatter_format.h" + extern "C" { #include "php_intl.h" -#include "intl_convert.h" } -#include #include -#include "formatter_class.h" -#include "formatter_format.h" - #define ICU_LOCALE_BUG 1 /* {{{ Parse a number. */ U_CFUNC PHP_FUNCTION( numfmt_parse ) { zend_long type = FORMAT_TYPE_DOUBLE; - UChar* sstr = NULL; - int32_t sstr_len = 0; char* str = NULL; size_t str_len; - int32_t val32, position = 0; - int64_t val64; - double val_double; - int32_t* position_p = NULL; + int32_t position = 0; zval *zposition = NULL; char *oldlocale; FORMATTER_METHOD_INIT_VARS; @@ -54,14 +50,14 @@ U_CFUNC PHP_FUNCTION( numfmt_parse ) if (zposition) { position = (int32_t) zval_get_long(zposition); - position_p = &position; } /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; /* Convert given string to UTF-16. */ - intl_convert_utf8_to_utf16(&sstr, &sstr_len, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); + icu::UnicodeString ustr; + intl_stringFromChar(ustr, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" ); #if ICU_LOCALE_BUG && defined(LC_NUMERIC) @@ -72,21 +68,38 @@ U_CFUNC PHP_FUNCTION( numfmt_parse ) switch(type) { case FORMAT_TYPE_INT32: - val32 = unum_parse(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo)); - RETVAL_LONG(val32); - break; case FORMAT_TYPE_INT64: - val64 = unum_parseInt64(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo)); - if(val64 > ZEND_LONG_MAX || val64 < ZEND_LONG_MIN) { - RETVAL_DOUBLE(val64); + case FORMAT_TYPE_DOUBLE: + { + icu::Formattable result; + icu::ParsePosition pp(position); + FORMATTER_OBJECT(nfo)->parse(ustr, result, pp); + + if (pp.getErrorIndex() >= 0) { + INTL_DATA_ERROR_CODE(nfo) = U_PARSE_ERROR; } else { - RETVAL_LONG((zend_long)val64); + position = pp.getIndex(); + switch(type) { + case FORMAT_TYPE_INT32: + RETVAL_LONG(result.getLong(INTL_DATA_ERROR_CODE(nfo))); + break; + case FORMAT_TYPE_INT64: + { + int64_t val64 = result.getInt64(INTL_DATA_ERROR_CODE(nfo)); + if(val64 > ZEND_LONG_MAX || val64 < ZEND_LONG_MIN) { + RETVAL_DOUBLE(val64); + } else { + RETVAL_LONG((zend_long)val64); + } + break; + } + case FORMAT_TYPE_DOUBLE: + RETVAL_DOUBLE(result.getDouble(INTL_DATA_ERROR_CODE(nfo))); + break; + } } break; - case FORMAT_TYPE_DOUBLE: - val_double = unum_parseDouble(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo)); - RETVAL_DOUBLE(val_double); - break; + } case FORMAT_TYPE_CURRENCY: if (hasThis()) { const char *space; @@ -113,10 +126,6 @@ U_CFUNC PHP_FUNCTION( numfmt_parse ) efree(oldlocale); #endif - if (sstr) { - efree(sstr); - } - INTL_METHOD_CHECK_STATUS( nfo, "Number parsing failed" ); } /* }}} */ @@ -124,14 +133,8 @@ U_CFUNC PHP_FUNCTION( numfmt_parse ) /* {{{ Parse a number as currency. */ U_CFUNC PHP_FUNCTION( numfmt_parse_currency ) { - double number; - UChar currency[5] = {0}; - UChar* sstr = NULL; - int32_t sstr_len = 0; - zend_string *u8str; char *str; size_t str_len; - int32_t* position_p = NULL; int32_t position = 0; zval *zcurrency, *zposition = NULL; FORMATTER_METHOD_INIT_VARS; @@ -147,27 +150,36 @@ U_CFUNC PHP_FUNCTION( numfmt_parse_currency ) FORMATTER_METHOD_FETCH_OBJECT; /* Convert given string to UTF-16. */ - intl_convert_utf8_to_utf16(&sstr, &sstr_len, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); + icu::UnicodeString ustr; + intl_stringFromChar(ustr, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" ); if(zposition) { position = (int32_t) zval_get_long(zposition); - position_p = &position; } - number = unum_parseDoubleCurrency(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, currency, &INTL_DATA_ERROR_CODE(nfo)); - if(zposition) { - ZEND_TRY_ASSIGN_REF_LONG(zposition, position); + icu::ParsePosition pp(position); + icu::CurrencyAmount *currAmt = FORMATTER_OBJECT(nfo)->parseCurrency(ustr, pp); + + if (currAmt == nullptr || pp.getErrorIndex() >= 0) { + delete currAmt; + INTL_DATA_ERROR_CODE(nfo) = U_PARSE_ERROR; + INTL_METHOD_CHECK_STATUS( nfo, "Number parsing failed" ); } - if (sstr) { - efree(sstr); + + if(zposition) { + ZEND_TRY_ASSIGN_REF_LONG(zposition, pp.getIndex()); } - INTL_METHOD_CHECK_STATUS( nfo, "Number parsing failed" ); + + double number = currAmt->getNumber().getDouble(INTL_DATA_ERROR_CODE(nfo)); /* Convert parsed currency to UTF-8 and pass it back to caller. */ - u8str = intl_convert_utf16_to_utf8(currency, u_strlen(currency), &INTL_DATA_ERROR_CODE(nfo)); + icu::UnicodeString ucurrency(currAmt->getISOCurrency()); + delete currAmt; + + zend_string *u8str = intl_charFromString(ucurrency, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "Currency conversion to UTF-8 failed" ); - ZEND_TRY_ASSIGN_REF_NEW_STR(zcurrency, u8str); + ZEND_TRY_ASSIGN_REF_STR(zcurrency, u8str); RETVAL_DOUBLE( number ); } diff --git a/ext/intl/listformatter/listformatter_class.cpp b/ext/intl/listformatter/listformatter_class.cpp index 8a7f9ffef9c2b..52643a857b388 100644 --- a/ext/intl/listformatter/listformatter_class.cpp +++ b/ext/intl/listformatter/listformatter_class.cpp @@ -14,10 +14,15 @@ extern "C" { #include "php.h" +} + +#include +#include +#include "../intl_convertcpp.h" + +extern "C" { #include "php_intl.h" -#include "intl_convert.h" } -#include #include "listformatter_class.h" #include "listformatter_arginfo.h" @@ -27,9 +32,7 @@ static void listformatter_free_obj(zend_object *object) { ListFormatter_object *obj = php_intl_listformatter_fetch_object(object); - if( obj->lf_data.ulistfmt ) - ulistfmt_close( obj->lf_data.ulistfmt ); - + delete obj->lf_data.ulistfmt; obj->lf_data.ulistfmt = nullptr; intl_error_reset( &obj->lf_data.error ); @@ -78,7 +81,7 @@ PHP_METHOD(IntlListFormatter, __construct) RETURN_THROWS(); } - if (strlen(uloc_getISO3Language(locale)) == 0) { + if (icu::Locale(locale).getISO3Language()[0] == '\0') { zend_argument_value_error(1, "\"%s\" is invalid", locale); RETURN_THROWS(); } @@ -89,13 +92,13 @@ PHP_METHOD(IntlListFormatter, __construct) zend_argument_value_error(2, "must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS"); RETURN_THROWS(); } - + if (width != ULISTFMT_WIDTH_WIDE && width != ULISTFMT_WIDTH_SHORT && width != ULISTFMT_WIDTH_NARROW) { zend_argument_value_error(3, "must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW"); RETURN_THROWS(); } - LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(locale, static_cast(type), static_cast(width), &status); + LISTFORMATTER_OBJECT(obj) = ListFormatter::createInstance(icu::Locale(locale), static_cast(type), static_cast(width), status); #else if (type != INTL_LISTFORMATTER_FALLBACK_TYPE_AND) { zend_argument_value_error(2, "contains an unsupported type. ICU 66 and below only support IntlListFormatter::TYPE_AND"); @@ -107,7 +110,7 @@ PHP_METHOD(IntlListFormatter, __construct) RETURN_THROWS(); } - LISTFORMATTER_OBJECT(obj) = ulistfmt_open(locale, &status); + LISTFORMATTER_OBJECT(obj) = ListFormatter::createInstance(icu::Locale(locale), status); #endif if (U_FAILURE(status)) { @@ -131,84 +134,50 @@ PHP_METHOD(IntlListFormatter, format) RETURN_EMPTY_STRING(); } - const UChar **items = (const UChar **)safe_emalloc(count, sizeof(const UChar *), 0); - int32_t *itemLengths = (int32_t *)safe_emalloc(count, sizeof(int32_t), 0); + UnicodeString *items = new UnicodeString[count]; uint32_t i = 0; zval *val; ZEND_HASH_FOREACH_VAL(ht, val) { zend_string *str_val, *tmp_str; - - str_val = zval_get_tmp_string(val, &tmp_str); - - // Convert PHP string to UTF-16 - UChar *ustr = nullptr; - int32_t ustr_len = 0; - UErrorCode status = U_ZERO_ERROR; - - intl_convert_utf8_to_utf16(&ustr, &ustr_len, ZSTR_VAL(str_val), ZSTR_LEN(str_val), &status); + UErrorCode conv_status = U_ZERO_ERROR; + + str_val = zval_try_get_tmp_string(val, &tmp_str); + if (UNEXPECTED(!str_val)) { + delete[] items; + RETURN_THROWS(); + } + intl_stringFromChar(items[i], ZSTR_VAL(str_val), ZSTR_LEN(str_val), &conv_status); zend_tmp_string_release(tmp_str); - if (U_FAILURE(status)) { - // We can't use goto cleanup because items and itemLengths are incompletely allocated - for (uint32_t j = 0; j < i; j++) { - efree((void *)items[j]); - } - efree(items); - efree(itemLengths); - intl_error_set(nullptr, status, "Failed to convert string to UTF-16"); + if (U_FAILURE(conv_status)) { + delete[] items; + intl_error_set(nullptr, conv_status, "Failed to convert string to UTF-16"); RETURN_FALSE; } - - items[i] = ustr; - itemLengths[i] = ustr_len; + i++; } ZEND_HASH_FOREACH_END(); UErrorCode status = U_ZERO_ERROR; - int32_t resultLength; - UChar *result = nullptr; - zend_string *ret = nullptr; - - resultLength = ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, nullptr, 0, &status); - - if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) { - intl_error_set(nullptr, status, "Failed to format list"); - RETVAL_FALSE; - goto cleanup; - } + UnicodeString result; - // Allocate buffer and try again - status = U_ZERO_ERROR; - result = (UChar *)safe_emalloc(resultLength + 1, sizeof(UChar), 0); - ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, result, resultLength, &status); + LISTFORMATTER_OBJECT(obj)->format(items, count, result, status); + delete[] items; if (U_FAILURE(status)) { - if (result) { - efree(result); - } intl_error_set(nullptr, status, "Failed to format list"); - RETVAL_FALSE; - goto cleanup; + RETURN_FALSE; } - // Convert result back to UTF-8 - ret = intl_convert_utf16_to_utf8(result, resultLength, &status); - efree(result); - + zend_string *ret = intl_charFromString(result, &status); + if (!ret) { intl_error_set(nullptr, status, "Failed to convert result to UTF-8"); - RETVAL_FALSE; - } else { - RETVAL_NEW_STR(ret); + RETURN_FALSE; } -cleanup: - for (i = 0; i < count; i++) { - efree((void *)items[i]); - } - efree(items); - efree(itemLengths); + RETVAL_STR(ret); } PHP_METHOD(IntlListFormatter, getErrorCode) @@ -236,7 +205,7 @@ void listformatter_register_class(void) { zend_class_entry *class_entry = register_class_IntlListFormatter(); class_entry->create_object = listformatter_create_object; - + memcpy(&listformatter_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); listformatter_handlers.offset = XtOffsetOf(ListFormatter_object, zo); listformatter_handlers.free_obj = listformatter_free_obj; diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h index 8edbf8d63e2d0..3497932eca36c 100644 --- a/ext/intl/listformatter/listformatter_class.h +++ b/ext/intl/listformatter/listformatter_class.h @@ -21,14 +21,20 @@ #include "intl_error.h" #include "intl_data.h" -#include +#include + +#ifdef __cplusplus +using icu::ListFormatter; +#else +typedef void ListFormatter; +#endif typedef struct { // error handling intl_error error; // formatter handling - UListFormatter* ulistfmt; + ListFormatter* ulistfmt; } listformatter_data; typedef struct { diff --git a/ext/intl/rangeformatter/rangeformatter_class.cpp b/ext/intl/rangeformatter/rangeformatter_class.cpp index 2042966177cb2..f0854f91b8f85 100644 --- a/ext/intl/rangeformatter/rangeformatter_class.cpp +++ b/ext/intl/rangeformatter/rangeformatter_class.cpp @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include #include "../intl_convertcpp.h" extern "C" { @@ -30,7 +31,6 @@ extern "C" { #include "../intl_data.h" #include "rangeformatter_arginfo.h" #include "rangeformatter_class.h" - #include "intl_convert.h" } using icu::number::NumberRangeFormatter; @@ -91,7 +91,7 @@ U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, createFromSkeleton) RETURN_THROWS(); } - if (strlen(uloc_getISO3Language(locale)) == 0) { + if (icu::Locale(locale).getISO3Language()[0] == '\0') { zend_argument_value_error(2, "\"%s\" is invalid", locale); RETURN_THROWS(); } diff --git a/ext/intl/tests/formatter_fail.phpt b/ext/intl/tests/formatter_fail.phpt index 53f6b4ac7c7b0..678b87b8c1b89 100644 --- a/ext/intl/tests/formatter_fail.phpt +++ b/ext/intl/tests/formatter_fail.phpt @@ -137,9 +137,9 @@ TypeError: numfmt_create(): Argument #1 ($locale) must be of type string, array 'U_ZERO_ERROR' IntlException: NumberFormatter::__construct(): number formatter creation failed -'NumberFormatter::__construct(): number formatter creation failed: U_UNSUPPORTED_ERROR' -'NumberFormatter::create(): number formatter creation failed: U_UNSUPPORTED_ERROR' -'numfmt_create(): number formatter creation failed: U_UNSUPPORTED_ERROR' +'NumberFormatter::__construct(): number formatter creation failed: U_ILLEGAL_ARGUMENT_ERROR' +'NumberFormatter::create(): number formatter creation failed: U_ILLEGAL_ARGUMENT_ERROR' +'numfmt_create(): number formatter creation failed: U_ILLEGAL_ARGUMENT_ERROR' IntlException: NumberFormatter::__construct(): number formatter creation failed 'NumberFormatter::__construct(): number formatter creation failed: U_MEMORY_ALLOCATION_ERROR'