summaryrefslogtreecommitdiff
path: root/ext/intl/msgformat/msgformat_helpers.cpp
diff options
context:
space:
mode:
authorGustavo André dos Santos Lopes <cataphract@php.net>2012-05-13 20:14:14 +0200
committerGustavo André dos Santos Lopes <cataphract@php.net>2012-05-13 20:55:02 +0100
commit53860672f3636049e5fbc29d49eb017893fa6808 (patch)
treef0157796a38d60dd8123f8fb4c17952e21e37764 /ext/intl/msgformat/msgformat_helpers.cpp
parent43ff66e0953e3664de11ffa7af27c695057cc4d6 (diff)
downloadphp-git-53860672f3636049e5fbc29d49eb017893fa6808.tar.gz
ICU < 4.8 compat in MessageFormatter
Restricted support for named arguments to ICU 4.8+. Also added bound checks when converting arguments to Formattables.
Diffstat (limited to 'ext/intl/msgformat/msgformat_helpers.cpp')
-rwxr-xr-xext/intl/msgformat/msgformat_helpers.cpp136
1 files changed, 128 insertions, 8 deletions
diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp
index b13c4c466f..42c5466153 100755
--- a/ext/intl/msgformat/msgformat_helpers.cpp
+++ b/ext/intl/msgformat/msgformat_helpers.cpp
@@ -25,7 +25,6 @@
#include <limits.h>
#include <unicode/msgfmt.h>
#include <unicode/chariter.h>
-#include <unicode/messagepattern.h>
#include <unicode/ustdio.h>
#include <vector>
@@ -51,6 +50,10 @@ extern "C" {
#define NAN (INFINITY-INFINITY)
#endif
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+#define HAS_MESSAGE_PATTERN 1
+#endif
+
U_NAMESPACE_BEGIN
/**
* This class isolates our access to private internal methods of
@@ -61,17 +64,23 @@ class MessageFormatAdapter {
public:
static const Formattable::Type* getArgTypeList(const MessageFormat& m,
int32_t& count);
+#ifdef HAS_MESSAGE_PATTERN
static const MessagePattern getMessagePattern(MessageFormat* m);
+#endif
};
+
const Formattable::Type*
MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
int32_t& count) {
return m.getArgTypeList(count);
}
+
+#ifdef HAS_MESSAGE_PATTERN
const MessagePattern
MessageFormatAdapter::getMessagePattern(MessageFormat* m) {
return m->msgPattern;
}
+#endif
U_NAMESPACE_END
U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
@@ -133,6 +142,52 @@ static double umsg_helper_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC)
return rv;
}
+static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo,
+ intl_error& err TSRMLS_DC)
+{
+ HashTable *ret;
+ int32_t parts_count;
+
+ if (U_FAILURE(err.code)) {
+ return NULL;
+ }
+
+ if (mfo->mf_data.arg_types) {
+ /* already cached */
+ return mfo->mf_data.arg_types;
+ }
+
+ const Formattable::Type *types = MessageFormatAdapter::getArgTypeList(
+ *(MessageFormat*)mfo->mf_data.umsgf, parts_count);
+
+ /* Hash table will store Formattable::Type objects directly,
+ * so no need for destructor */
+ ALLOC_HASHTABLE(ret);
+ zend_hash_init(ret, parts_count, NULL, NULL, 0);
+
+ for (int i = 0; i < parts_count; i++) {
+ const Formattable::Type t = types[i];
+ if (zend_hash_index_update(ret, (ulong)i, (void*)&t, sizeof(t), NULL)
+ == FAILURE) {
+ intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
+ "Write to argument types hash table failed", 0 TSRMLS_CC);
+ break;
+ }
+ }
+
+ if (U_FAILURE(err.code)) {
+ zend_hash_destroy(ret);
+ efree(ret);
+
+ return NULL;
+ }
+
+ mfo->mf_data.arg_types = ret;
+
+ return ret;
+}
+
+#ifdef HAS_MESSAGE_PATTERN
static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
const MessagePattern& mp,
intl_error& err TSRMLS_DC)
@@ -144,6 +199,10 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
return NULL;
}
+ if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) {
+ return umsg_get_numeric_types(mfo, err TSRMLS_CC);
+ }
+
if (mfo->mf_data.arg_types) {
/* already cached */
return mfo->mf_data.arg_types;
@@ -287,6 +346,27 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
return ret;
}
+#endif
+
+static HashTable *umsg_get_types(MessageFormatter_object *mfo,
+ intl_error& err TSRMLS_DC)
+{
+ MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
+
+#ifdef HAS_MESSAGE_PATTERN
+ const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf);
+
+ return umsg_parse_format(mfo, mp, err TSRMLS_CC);
+#else
+ if (mf->usesNamedArguments()) {
+ intl_errors_set(&err, U_UNSUPPORTED_ERROR,
+ "This extension supports named arguments only on ICU 4.8+",
+ 0 TSRMLS_CC);
+ return NULL;
+ }
+ return umsg_get_numeric_types(mfo, err TSRMLS_CC);
+#endif
+}
U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
HashTable *args,
@@ -297,7 +377,6 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
std::vector<Formattable> fargs;
std::vector<UnicodeString> farg_names;
MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
- const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf);
HashTable *types;
intl_error& err = INTL_DATA_ERROR(mfo);
@@ -305,11 +384,11 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
return;
}
+ types = umsg_get_types(mfo, err TSRMLS_CC);
+
fargs.resize(arg_count);
farg_names.resize(arg_count);
- types = umsg_parse_format(mfo, mp, err TSRMLS_CC);
-
int argNum = 0;
HashPosition pos;
zval **elem;
@@ -414,19 +493,56 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
formattable.setDouble(d);
break;
}
+ case Formattable::kLong:
+ {
+ int32_t tInt32;
+retry_klong:
+ if (Z_TYPE_PP(elem) == IS_DOUBLE) {
+ if (Z_DVAL_PP(elem) > (double)INT32_MAX ||
+ Z_DVAL_PP(elem) < (double)INT32_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP float with absolute value too large for "
+ "32 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt32 = (int32_t)Z_DVAL_PP(elem);
+ }
+ } else if (Z_TYPE_PP(elem) == IS_LONG) {
+ if (Z_LVAL_PP(elem) > INT32_MAX ||
+ Z_LVAL_PP(elem) < INT32_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP integer with absolute value too large "
+ "for 32 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt32 = (int32_t)Z_LVAL_PP(elem);
+ }
+ } else {
+ SEPARATE_ZVAL_IF_NOT_REF(elem);
+ convert_scalar_to_number(*elem TSRMLS_CC);
+ goto retry_klong;
+ }
+ formattable.setLong(tInt32);
+ break;
+ }
case Formattable::kInt64:
{
int64_t tInt64;
+retry_kint64:
if (Z_TYPE_PP(elem) == IS_DOUBLE) {
- tInt64 = (int64_t)Z_DVAL_PP(elem);
+ if (Z_DVAL_PP(elem) > (double)U_INT64_MAX ||
+ Z_DVAL_PP(elem) < (double)U_INT64_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP float with absolute value too large for "
+ "64 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt64 = (int64_t)Z_DVAL_PP(elem);
+ }
} else if (Z_TYPE_PP(elem) == IS_LONG) {
+ /* assume long is not wider than 64 bits */
tInt64 = (int64_t)Z_LVAL_PP(elem);
} else {
SEPARATE_ZVAL_IF_NOT_REF(elem);
convert_scalar_to_number(*elem TSRMLS_CC);
- tInt64 = (Z_TYPE_PP(elem) == IS_DOUBLE)
- ? (int64_t)Z_DVAL_PP(elem)
- : Z_LVAL_PP(elem);
+ goto retry_kint64;
}
formattable.setInt64(tInt64);
break;
@@ -451,6 +567,10 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
formattable.setDate(dd);
break;
}
+ default:
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found unsupported argument type", 0 TSRMLS_CC);
+ break;
}
} else {
/* We couldn't find any information about the argument in the pattern, this