]> granicus.if.org Git - php/commitdiff
ICU < 4.8 compat in MessageFormatter
authorGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 13 May 2012 18:14:14 +0000 (20:14 +0200)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 13 May 2012 19:55:02 +0000 (20:55 +0100)
Restricted support for named arguments to ICU 4.8+.

Also added bound checks when converting arguments to Formattables.

12 files changed:
ext/intl/msgformat/msgformat_helpers.cpp
ext/intl/tests/msgfmt_format_error1.phpt
ext/intl/tests/msgfmt_format_error2.phpt
ext/intl/tests/msgfmt_format_error3.phpt
ext/intl/tests/msgfmt_format_error4.phpt
ext/intl/tests/msgfmt_format_error5.phpt
ext/intl/tests/msgfmt_format_error6.phpt
ext/intl/tests/msgfmt_format_mixed_params.phpt
ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt
ext/intl/tests/msgfmt_format_subpatterns.phpt
ext/intl/tests/msgfmt_format_subpatterns_named.phpt
ext/intl/tests/msgfmt_get_error.phpt [deleted file]

index b13c4c466f34081431d9d4e51e61026d14555849..42c54661533e0830ff1b1dff4ceb94bd00319eb2 100755 (executable)
@@ -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
index 09d022bdfdcce9317a9cfcd71c55c8c312e1732e..684b05970a462371e394b2af89de18e58bc372ce 100644 (file)
@@ -16,6 +16,4 @@ $mf = new MessageFormatter('en_US', $fmt);
 var_dump($mf->format(array(7)));
 
 --EXPECTF--
-
-Warning: MessageFormatter::format(): msgfmt_format: not enough parameters in %s on line %d
-bool(false)
+string(5) "7 {1}"
index 00b8542ed18b02f78c08a9c6ee787133a90e4b5d..85d1b1c83d3dfab29c73716def2bfd675833b534 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format() inconsistent types in named argument
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index 98eebd7e645bab982ac8b9c462456193c1f9ed3e..6dfbee3c908cee27b3ff2b670d2ac37bd1647798 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format() given negative arg key
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index 5f4d006178daf298704c5f68d27e76f7735f9de9..3b92b48b8b037e0849690c344b306c09c796d3ad 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format() invalid UTF-8 for arg key or value
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index 951cd3ff2ef9e8bb6573abe72cd2c45543fa16fc..0ea5169d456d1ef3e0d427760282e7a0da727412 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format() invalid date/time argument
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index aefed90e97ef9e4d533dbe2f273f122b066f6f91..b07d2ab7748438cceb25250ea76adba0d6882aa8 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format() invalid type for key not in pattern
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index 3ab7688b550395c497aa443388295d6c1ca72036..93412f49e22a1037863569b028c4cdc61d0e00e7 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format(): mixed named and numeric parameters
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index 39cf815b01c4d6a1fdba3ed24a36b5c9555e1278..c52c359807e4977c6b543d0757f1b5049168a016 100644 (file)
@@ -4,6 +4,8 @@ MessageFormatter::format(): simple types handling with numeric strings
 <?php
 if (!extension_loaded('intl'))
        die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 ini_set("intl.error_level", E_WARNING);
index ec7443f24dda64d7c683ca0736968f734ebbb334..9f11e3e2554431c9ab8dbe8c247af826b1943f76 100644 (file)
@@ -1,7 +1,11 @@
 --TEST--
 msgfmt_format() with subpatterns
 --SKIPIF--
-<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php
+if (!extension_loaded('intl'))
+       die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 
@@ -45,7 +49,7 @@ $str_res = '';
         $fmt = ut_msgfmt_create( 'en_US', $pattern );
                if(!$fmt) {
                        $str_res .= dump(intl_get_error_message())."\n";
-                       continue;
+                       return $str_res;
                }
         foreach ($args as $arg) {
             $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n";
index 98a6e011936737b60b14ac35d14cba28180a89f0..f6af02561bc99044bcc81ee6cdce58e49f4ffe0c 100644 (file)
@@ -1,7 +1,11 @@
 --TEST--
 msgfmt_format() with named subpatterns
 --SKIPIF--
-<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php
+if (!extension_loaded('intl'))
+       die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+       die('skip for ICU 4.8+');
 --FILE--
 <?php
 
@@ -45,7 +49,7 @@ $str_res = '';
         $fmt = ut_msgfmt_create( 'en_US', $pattern );
                if(!$fmt) {
                        $str_res .= dump(intl_get_error_message())."\n";
-                       continue;
+                       return $str_res;
                }
         foreach ($args as $arg) {
             $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n";
diff --git a/ext/intl/tests/msgfmt_get_error.phpt b/ext/intl/tests/msgfmt_get_error.phpt
deleted file mode 100755 (executable)
index 015c50d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-msgmfmt_get_error_message/code()
---SKIPIF--
-<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
---FILE--
-<?php
-
-/*
- * Error handling.
- */
-
-
-function ut_main()
-{
-    $fmt = ut_msgfmt_create( "en_US", "{0, number} monkeys on {1, number} trees" );
-    $num = ut_msgfmt_format( $fmt, array());
-    if( $num === false )
-        return $fmt->getErrorMessage() . " (" . $fmt->getErrorCode() . ")\n";
-    else
-        return "Ooops, an error should have occured.";
-}
-
-include_once( 'ut_common.inc' );
-
-// Run the test
-ut_run();
-?>
---EXPECT--
-msgfmt_format: not enough parameters: U_ILLEGAL_ARGUMENT_ERROR (1)