PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/intl/msgformat - msgformat_helpers.cpp (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 122 207 58.9 %
Date: 2016-08-28 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | This source file is subject to version 3.01 of the PHP license,      |
       6             :    | that is bundled with this package in the file LICENSE, and is        |
       7             :    | available through the world-wide-web at the following url:           |
       8             :    | http://www.php.net/license/3_01.txt                                  |
       9             :    | If you did not receive a copy of the PHP license and are unable to   |
      10             :    | obtain it through the world-wide-web, please send a note to          |
      11             :    | license@php.net so we can mail you a copy immediately.               |
      12             :    +----------------------------------------------------------------------+
      13             :    | Authors: Stanislav Malyshev <stas@zend.com>                          |
      14             :    +----------------------------------------------------------------------+
      15             :  */
      16             : 
      17             : #ifdef HAVE_CONFIG_H
      18             : #include "config.h"
      19             : #endif
      20             : 
      21             : #include "../intl_cppshims.h"
      22             : 
      23             : #include <limits.h>
      24             : #include <unicode/msgfmt.h>
      25             : #include <unicode/chariter.h>
      26             : #include <unicode/ustdio.h>
      27             : #include <unicode/timezone.h>
      28             : #include <unicode/datefmt.h>
      29             : #include <unicode/calendar.h>
      30             : 
      31             : #include <vector>
      32             : 
      33             : #include "../intl_convertcpp.h"
      34             : #include "../common/common_date.h"
      35             : 
      36             : extern "C" {
      37             : #include "php_intl.h"
      38             : #include "msgformat_class.h"
      39             : #include "msgformat_format.h"
      40             : #include "msgformat_helpers.h"
      41             : #include "intl_convert.h"
      42             : #define USE_TIMEZONE_POINTER
      43             : #include "../timezone/timezone_class.h"
      44             : }
      45             : 
      46             : #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
      47             : #define HAS_MESSAGE_PATTERN 1
      48             : #endif
      49             : 
      50             : U_NAMESPACE_BEGIN
      51             : /**
      52             :  * This class isolates our access to private internal methods of
      53             :  * MessageFormat.  It is never instantiated; it exists only for C++
      54             :  * access management.
      55             :  */
      56             : class MessageFormatAdapter {
      57             : public:
      58             :     static const Formattable::Type* getArgTypeList(const MessageFormat& m,
      59             :                                                    int32_t& count);
      60             : #ifdef HAS_MESSAGE_PATTERN
      61             :     static const MessagePattern getMessagePattern(MessageFormat* m);
      62             : #endif
      63             : };
      64             : 
      65             : const Formattable::Type*
      66          36 : MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
      67             :                                      int32_t& count) {
      68          36 :     return m.getArgTypeList(count);
      69             : }
      70             : 
      71             : #ifdef HAS_MESSAGE_PATTERN
      72             : const MessagePattern
      73             : MessageFormatAdapter::getMessagePattern(MessageFormat* m) {
      74             :     return m->msgPattern;
      75             : }
      76             : #endif
      77             : U_NAMESPACE_END
      78             : 
      79           0 : U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
      80             : {
      81           0 :         int32_t fmt_count = 0;
      82           0 :         MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
      83           0 :         return fmt_count;
      84             : }
      85             : 
      86          76 : static void arg_types_dtor(zval *el) {
      87          76 :         efree(Z_PTR_P(el));
      88          76 : }
      89             : 
      90          37 : static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo,
      91             :                                                                                  intl_error& err)
      92             : {
      93             :         HashTable *ret;
      94             :         int32_t parts_count;
      95             : 
      96          37 :         if (U_FAILURE(err.code)) {
      97           0 :                 return NULL;
      98             :         }
      99             : 
     100          37 :         if (mfo->mf_data.arg_types) {
     101             :                 /* already cached */
     102           1 :                 return mfo->mf_data.arg_types;
     103             :         }
     104             : 
     105             :         const Formattable::Type *types = MessageFormatAdapter::getArgTypeList(
     106          36 :                 *(MessageFormat*)mfo->mf_data.umsgf, parts_count);
     107             : 
     108             :         /* Hash table will store Formattable::Type objects directly,
     109             :          * so no need for destructor */
     110          36 :         ALLOC_HASHTABLE(ret);
     111          36 :         zend_hash_init(ret, parts_count, NULL, arg_types_dtor, 0);
     112             : 
     113         112 :         for (int i = 0; i < parts_count; i++) {
     114          76 :                 const Formattable::Type t = types[i];
     115         152 :                 if (zend_hash_index_update_mem(ret, (zend_ulong)i, (void*)&t, sizeof(t)) == NULL) {
     116             :                         intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     117           0 :                                 "Write to argument types hash table failed", 0);
     118           0 :                         break;
     119             :                 }
     120             :         }
     121             : 
     122          36 :         if (U_FAILURE(err.code)) {
     123           0 :                 zend_hash_destroy(ret);
     124           0 :                 efree(ret);
     125             : 
     126           0 :                 return NULL;
     127             :         }
     128             : 
     129          36 :         mfo->mf_data.arg_types = ret;
     130             : 
     131          36 :         return ret;
     132             : }
     133             : 
     134             : #ifdef HAS_MESSAGE_PATTERN
     135             : static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
     136             :                                                                         const MessagePattern& mp,
     137             :                                                                         intl_error& err)
     138             : {
     139             :         HashTable *ret;
     140             :         int32_t parts_count;
     141             : 
     142             :         if (U_FAILURE(err.code)) {
     143             :                 return NULL;
     144             :         }
     145             : 
     146             :         if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) {
     147             :                 return umsg_get_numeric_types(mfo, err);
     148             :         }
     149             : 
     150             :         if (mfo->mf_data.arg_types) {
     151             :                 /* already cached */
     152             :                 return mfo->mf_data.arg_types;
     153             :         }
     154             : 
     155             :         /* Hash table will store Formattable::Type objects directly,
     156             :          * so no need for destructor */
     157             :         ALLOC_HASHTABLE(ret);
     158             :         zend_hash_init(ret, 32, NULL, arg_types_dtor, 0);
     159             : 
     160             :         parts_count = mp.countParts();
     161             : 
     162             :         // See MessageFormat::cacheExplicitFormats()
     163             :         /*
     164             :          * Looking through the pattern, go to each arg_start part type.
     165             :          * The arg-typeof that tells us the argument type (simple, complicated)
     166             :          * then the next part is either the arg_name or arg number
     167             :          * and then if it's simple after that there could be a part-type=arg-type
     168             :          * while substring will tell us number, spellout, etc.
     169             :          * If the next thing isn't an arg-type then assume string.
     170             :         */
     171             :         /* The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
     172             :          * which we need not examine. */
     173             :         for (int32_t i = 0; i < parts_count - 2 && U_SUCCESS(err.code); i++) {
     174             :                 MessagePattern::Part p = mp.getPart(i);
     175             : 
     176             :                 if (p.getType() != UMSGPAT_PART_TYPE_ARG_START) {
     177             :                         continue;
     178             :                 }
     179             : 
     180             :                 MessagePattern::Part name_part = mp.getPart(++i); /* Getting name, advancing i */
     181             :                 Formattable::Type type,
     182             :                                                   *storedType;
     183             : 
     184             :                 if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) {
     185             :                         UnicodeString argName = mp.getSubstring(name_part);
     186             :                         if ((storedType = (Formattable::Type*)zend_hash_str_find_ptr(ret, (char*)argName.getBuffer(), argName.length())) == NULL) {
     187             :                                 /* not found already; create new entry in HT */
     188             :                                 Formattable::Type bogusType = Formattable::kObject;
     189             :                                 if ((storedType = (Formattable::Type*)zend_hash_str_update_mem(ret, (char*)argName.getBuffer(), argName.length(),
     190             :                                                 (void*)&bogusType, sizeof(bogusType))) == NULL) {
     191             :                                         intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     192             :                                                 "Write to argument types hash table failed", 0);
     193             :                                         continue;
     194             :                                 }
     195             :                         }
     196             :                 } else if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
     197             :                         int32_t argNumber = name_part.getValue();
     198             :                         if (argNumber < 0) {
     199             :                                 intl_errors_set(&err, U_INVALID_FORMAT_ERROR,
     200             :                                         "Found part with negative number", 0);
     201             :                                 continue;
     202             :                         }
     203             :                         if ((storedType = (Formattable::Type*)zend_hash_index_find_ptr(ret, (zend_ulong)argNumber)) == NULL) {
     204             :                                 /* not found already; create new entry in HT */
     205             :                                 Formattable::Type bogusType = Formattable::kObject;
     206             :                                 if ((storedType = (Formattable::Type*)zend_hash_index_update_mem(ret, (zend_ulong)argNumber, (void*)&bogusType, sizeof(bogusType))) == NULL) {
     207             :                                         intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     208             :                                                 "Write to argument types hash table failed", 0);
     209             :                                         continue;
     210             :                                 }
     211             :                         }
     212             :                 } else {
     213             :                         intl_errors_set(&err, U_INVALID_FORMAT_ERROR, "Invalid part type encountered", 0);
     214             :                         continue;
     215             :                 }
     216             : 
     217             :                 UMessagePatternArgType argType = p.getArgType();
     218             :                 /* No type specified, treat it as a string */
     219             :                 if (argType == UMSGPAT_ARG_TYPE_NONE) {
     220             :                         type = Formattable::kString;
     221             :                 } else { /* Some type was specified, might be simple or complicated */
     222             :                         if (argType == UMSGPAT_ARG_TYPE_SIMPLE) {
     223             :                                 /* For a SIMPLE arg, after the name part, there should be
     224             :                                  * an ARG_TYPE part whose string value tells us what to do */
     225             :                                 MessagePattern::Part type_part = mp.getPart(++i); /* Getting type, advancing i */
     226             :                                 if (type_part.getType() == UMSGPAT_PART_TYPE_ARG_TYPE) {
     227             :                                         UnicodeString typeString = mp.getSubstring(type_part);
     228             :                                         /* This is all based on the rules in the docs for MessageFormat
     229             :                                          * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html */
     230             :                                         if (typeString == "number") {
     231             :                                                 MessagePattern::Part style_part = mp.getPart(i + 1); /* Not advancing i */
     232             :                                                 if (style_part.getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
     233             :                                                         UnicodeString styleString = mp.getSubstring(style_part);
     234             :                                                         if (styleString == "integer") {
     235             :                                                                 type = Formattable::kInt64;
     236             :                                                         } else if (styleString == "currency") {
     237             :                                                                 type = Formattable::kDouble;
     238             :                                                         } else if (styleString == "percent") {
     239             :                                                                 type = Formattable::kDouble;
     240             :                                                         } else { /* some style invalid/unknown to us */
     241             :                                                                 type = Formattable::kDouble;
     242             :                                                         }
     243             :                                                 } else { // if missing style, part, make it a double
     244             :                                                         type = Formattable::kDouble;
     245             :                                                 }
     246             :                                         } else if ((typeString == "date") || (typeString == "time")) {
     247             :                                                 type = Formattable::kDate;
     248             :                                         } else if ((typeString == "spellout") || (typeString == "ordinal")
     249             :                                                         || (typeString == "duration")) {
     250             :                                                 type = Formattable::kDouble;
     251             :                                         }
     252             :                                 } else {
     253             :                                         /* If there's no UMSGPAT_PART_TYPE_ARG_TYPE right after a
     254             :                                          * UMSGPAT_ARG_TYPE_SIMPLE argument, then the pattern
     255             :                                          * is broken. */
     256             :                                         intl_errors_set(&err, U_PARSE_ERROR,
     257             :                                                 "Expected UMSGPAT_PART_TYPE_ARG_TYPE part following "
     258             :                                                 "UMSGPAT_ARG_TYPE_SIMPLE part", 0);
     259             :                                         continue;
     260             :                                 }
     261             :                         } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) {
     262             :                                 type = Formattable::kDouble;
     263             :                         } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
     264             :                                 type = Formattable::kDouble;
     265             :                         } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
     266             :                                 type = Formattable::kString;
     267             : #if U_ICU_VERSION_MAJOR_NUM >= 50
     268             :                         } else if (argType == UMSGPAT_ARG_TYPE_SELECTORDINAL) {
     269             :                                 type = Formattable::kDouble;
     270             : #endif
     271             :                         } else {
     272             :                                 type = Formattable::kString;
     273             :                         }
     274             :                 } /* was type specified? */
     275             : 
     276             :                 /* We found a different type for the same arg! */
     277             :                 if (*storedType != Formattable::kObject && *storedType != type) {
     278             :                         intl_errors_set(&err, U_ARGUMENT_TYPE_MISMATCH,
     279             :                                 "Inconsistent types declared for an argument", 0);
     280             :                         continue;
     281             :                 }
     282             : 
     283             :                 *storedType = type;
     284             :         } /* visiting each part */
     285             : 
     286             :         if (U_FAILURE(err.code)) {
     287             :                 zend_hash_destroy(ret);
     288             :                 efree(ret);
     289             : 
     290             :                 return NULL;
     291             :         }
     292             : 
     293             :         mfo->mf_data.arg_types = ret;
     294             : 
     295             :         return ret;
     296             : }
     297             : #endif
     298             : 
     299          37 : static HashTable *umsg_get_types(MessageFormatter_object *mfo,
     300             :                                                                  intl_error& err)
     301             : {
     302          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     303             : 
     304             : #ifdef HAS_MESSAGE_PATTERN
     305             :         const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf);
     306             : 
     307             :         return umsg_parse_format(mfo, mp, err);
     308             : #else
     309          37 :         if (mf->usesNamedArguments()) {
     310             :                         intl_errors_set(&err, U_UNSUPPORTED_ERROR,
     311             :                                 "This extension supports named arguments only on ICU 4.8+",
     312           0 :                                 0);
     313           0 :                 return NULL;
     314             :         }
     315          37 :         return umsg_get_numeric_types(mfo, err);
     316             : #endif
     317             : }
     318             : 
     319          37 : static void umsg_set_timezone(MessageFormatter_object *mfo,
     320             :                                                           intl_error& err)
     321             : {
     322          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     323          37 :         TimeZone          *used_tz = NULL;
     324             :         const Format  **formats;
     325             :         int32_t           count;
     326             : 
     327             :         /* Unfortanely, this cannot change the time zone for arguments that
     328             :          * appear inside complex formats because ::getFormats() returns NULL
     329             :          * for all uncached formats, which is the case for complex formats
     330             :          * unless they were set via one of the ::setFormat() methods */
     331             : 
     332          37 :         if (mfo->mf_data.tz_set) {
     333           7 :                 return; /* already done */
     334             :         }
     335             : 
     336          30 :         formats = mf->getFormats(count);
     337             : 
     338          30 :         if (formats == NULL) {
     339             :                 intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     340           0 :                         "Out of memory retrieving subformats", 0);
     341             :         }
     342             : 
     343          97 :         for (int i = 0; U_SUCCESS(err.code) && i < count; i++) {
     344             :                 DateFormat* df = dynamic_cast<DateFormat*>(
     345          67 :                         const_cast<Format *>(formats[i]));
     346          67 :                 if (df == NULL) {
     347          60 :                         continue;
     348             :                 }
     349             : 
     350           7 :                 if (used_tz == NULL) {
     351           4 :                         zval nullzv, *zvptr = &nullzv;
     352           4 :                         ZVAL_NULL(zvptr);
     353           4 :                         used_tz = timezone_process_timezone_argument(zvptr, &err, "msgfmt_format");
     354           4 :                         if (used_tz == NULL) {
     355           0 :                                 continue;
     356             :                         }
     357             :                 }
     358             : 
     359           7 :                 df->setTimeZone(*used_tz);
     360             :         }
     361             : 
     362          30 :         if (U_SUCCESS(err.code)) {
     363          30 :                 mfo->mf_data.tz_set = 1;
     364             :         }
     365             : }
     366             : 
     367          37 : U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
     368             :                                                                 HashTable *args,
     369             :                                                                 UChar **formatted,
     370             :                                                                 int32_t *formatted_len)
     371             : {
     372          37 :         int arg_count = zend_hash_num_elements(args);
     373          37 :         std::vector<Formattable> fargs;
     374          37 :         std::vector<UnicodeString> farg_names;
     375          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     376             :         HashTable *types;
     377          37 :         intl_error& err = INTL_DATA_ERROR(mfo);
     378             : 
     379          37 :         if (U_FAILURE(err.code)) {
     380             :                 return;
     381             :         }
     382             : 
     383          37 :         types = umsg_get_types(mfo, err);
     384             : 
     385          37 :         umsg_set_timezone(mfo, err);
     386             : 
     387          37 :         fargs.resize(arg_count);
     388          37 :         farg_names.resize(arg_count);
     389             : 
     390          37 :         int                             argNum = 0;
     391             :         zval                    *elem;
     392             : 
     393             :         // Key related variables
     394             :         zend_string             *str_index;
     395             :         zend_ulong               num_index;
     396             : 
     397         215 :         ZEND_HASH_FOREACH_KEY_VAL(args, num_index, str_index, elem) {
     398          89 :                 Formattable& formattable = fargs[argNum];
     399          89 :                 UnicodeString& key = farg_names[argNum];
     400          89 :                 Formattable::Type argType = Formattable::kObject, //unknown
     401          89 :                                                   *storedArgType = NULL;
     402          89 :                 if (!U_SUCCESS(err.code)) {
     403           0 :                         break;
     404             :                 }
     405             :                 /* Process key and retrieve type */
     406          89 :                 if (str_index == NULL) {
     407             :                         /* includes case where index < 0 because it's exposed as unsigned */
     408          89 :                         if (num_index > (zend_ulong)INT32_MAX) {
     409             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     410           0 :                                         "Found negative or too large array key", 0);
     411           0 :                                 continue;
     412             :                         }
     413             : 
     414             :                    UChar temp[16];
     415          89 :                    int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index);
     416          89 :                    key.append(temp, len);
     417             : 
     418          89 :                    storedArgType = (Formattable::Type*)zend_hash_index_find_ptr(types, (zend_ulong)num_index);
     419             :                 } else { //string; assumed to be in UTF-8
     420           0 :                         intl_stringFromChar(key, ZSTR_VAL(str_index), ZSTR_LEN(str_index), &err.code);
     421             : 
     422           0 :                         if (U_FAILURE(err.code)) {
     423             :                                 char *message;
     424             :                                 spprintf(&message, 0,
     425           0 :                                         "Invalid UTF-8 data in argument key: '%s'", ZSTR_VAL(str_index));
     426           0 :                                 intl_errors_set(&err, err.code,     message, 1);
     427           0 :                                 efree(message);
     428           0 :                                 continue;
     429             :                         }
     430             : 
     431           0 :                         storedArgType = (Formattable::Type*)zend_hash_str_find_ptr(types, (char*)key.getBuffer(), key.length());
     432             :                 }
     433             : 
     434          89 :                 if (storedArgType != NULL) {
     435          77 :                         argType = *storedArgType;
     436             :                 }
     437             : 
     438             :                 /* Convert zval to formattable according to message format type
     439             :                  * or (as a fallback) the zval type */
     440          89 :                 if (argType != Formattable::kObject) {
     441          77 :                         switch (argType) {
     442             :                         case Formattable::kString:
     443             :                                 {
     444             :         string_arg:
     445             :                                         /* This implicitly converts objects
     446             :                                          * Note that our vectors will leak if object conversion fails
     447             :                                          * and PHP ends up with a fatal error and calls longjmp
     448             :                                          * as a result of that.
     449             :                                          */
     450           2 :                                         convert_to_string_ex(elem);
     451             : 
     452           1 :                                         UnicodeString *text = new UnicodeString();
     453             :                                         intl_stringFromChar(*text,
     454           1 :                                                 Z_STRVAL_P(elem), Z_STRLEN_P(elem), &err.code);
     455             : 
     456           1 :                                         if (U_FAILURE(err.code)) {
     457             :                                                 char *message;
     458             :                                                 spprintf(&message, 0, "Invalid UTF-8 data in string argument: "
     459           0 :                                                         "'%s'", Z_STRVAL_P(elem));
     460           0 :                                                 intl_errors_set(&err, err.code, message, 1);
     461           0 :                                                 efree(message);
     462           0 :                                                 delete text;
     463           0 :                                                 continue;
     464             :                                         }
     465           1 :                                         formattable.adoptString(text);
     466           1 :                                         break;
     467             :                                 }
     468             :                         case Formattable::kDouble:
     469             :                                 {
     470             :                                         double d;
     471          40 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     472          22 :                                                 d = Z_DVAL_P(elem);
     473          18 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     474          18 :                                                 d = (double)Z_LVAL_P(elem);
     475             :                                         } else {
     476           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     477           0 :                                                 convert_scalar_to_number(elem);
     478             :                                                 d = (Z_TYPE_P(elem) == IS_DOUBLE)
     479             :                                                         ? Z_DVAL_P(elem)
     480           0 :                                                         : (double)Z_LVAL_P(elem);
     481             :                                         }
     482          40 :                                         formattable.setDouble(d);
     483          40 :                                         break;
     484             :                                 }
     485             :                         case Formattable::kLong:
     486             :                                 {
     487          32 :                                         int32_t tInt32 = 0;
     488             : retry_klong:
     489          32 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     490           0 :                                                 if (Z_DVAL_P(elem) > (double)INT32_MAX ||
     491             :                                                                 Z_DVAL_P(elem) < (double)INT32_MIN) {
     492             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     493             :                                                                 "Found PHP float with absolute value too large for "
     494           0 :                                                                 "32 bit integer argument", 0);
     495             :                                                 } else {
     496           0 :                                                         tInt32 = (int32_t)Z_DVAL_P(elem);
     497             :                                                 }
     498          32 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     499          32 :                                                 if (Z_LVAL_P(elem) > INT32_MAX ||
     500             :                                                                 Z_LVAL_P(elem) < INT32_MIN) {
     501             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     502             :                                                                 "Found PHP integer with absolute value too large "
     503           0 :                                                                 "for 32 bit integer argument", 0);
     504             :                                                 } else {
     505          32 :                                                         tInt32 = (int32_t)Z_LVAL_P(elem);
     506             :                                                 }
     507             :                                         } else {
     508           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     509           0 :                                                 convert_scalar_to_number(elem);
     510           0 :                                                 goto retry_klong;
     511             :                                         }
     512          32 :                                         formattable.setLong(tInt32);
     513          32 :                                         break;
     514             :                                 }
     515             :                         case Formattable::kInt64:
     516             :                                 {
     517           0 :                                         int64_t tInt64 = 0;
     518             : retry_kint64:
     519           0 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     520           0 :                                                 if (Z_DVAL_P(elem) > (double)U_INT64_MAX ||
     521             :                                                                 Z_DVAL_P(elem) < (double)U_INT64_MIN) {
     522             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     523             :                                                                 "Found PHP float with absolute value too large for "
     524           0 :                                                                 "64 bit integer argument", 0);
     525             :                                                 } else {
     526           0 :                                                         tInt64 = (int64_t)Z_DVAL_P(elem);
     527             :                                                 }
     528           0 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     529             :                                                 /* assume long is not wider than 64 bits */
     530           0 :                                                 tInt64 = (int64_t)Z_LVAL_P(elem);
     531             :                                         } else {
     532           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     533           0 :                                                 convert_scalar_to_number(elem);
     534           0 :                                                 goto retry_kint64;
     535             :                                         }
     536           0 :                                         formattable.setInt64(tInt64);
     537           0 :                                         break;
     538             :                                 }
     539             :                         case Formattable::kDate:
     540             :                                 {
     541           4 :                                         double dd = intl_zval_to_millis(elem, &err, "msgfmt_format");
     542           4 :                                         if (U_FAILURE(err.code)) {
     543             :                                                 char *message;
     544             :                                                 zend_string *u8key;
     545           0 :                                                 UErrorCode status = UErrorCode();
     546           0 :                                                 u8key = intl_charFromString(key, &status);
     547           0 :                                                 if (u8key) {
     548             :                                                         spprintf(&message, 0, "The argument for key '%s' "
     549           0 :                                                                 "cannot be used as a date or time", ZSTR_VAL(u8key));
     550           0 :                                                         intl_errors_set(&err, err.code, message, 1);
     551             :                                                         zend_string_release(u8key);
     552           0 :                                                         efree(message);
     553             :                                                 }
     554           0 :                                                 continue;
     555             :                                         }
     556           4 :                                         formattable.setDate(dd);
     557           4 :                                         break;
     558             :                                 }
     559             :                         default:
     560             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     561           0 :                                         "Found unsupported argument type", 0);
     562             :                                 break;
     563             :                         }
     564             :                 } else {
     565             :                         /* We couldn't find any information about the argument in the pattern, this
     566             :                          * means it's an extra argument. So convert it to a number if it's a number or
     567             :                          * bool or null and to a string if it's anything else except arrays . */
     568          12 :                         switch (Z_TYPE_P(elem)) {
     569             :                         case IS_DOUBLE:
     570           4 :                                 formattable.setDouble(Z_DVAL_P(elem));
     571           4 :                                 break;
     572             :                         case IS_TRUE:
     573             :                         case IS_FALSE:
     574           0 :                                 convert_to_long_ex(elem);
     575             :                                 /* Intentional fallthrough */
     576             :                         case IS_LONG:
     577           8 :                                 formattable.setInt64((int64_t)Z_LVAL_P(elem));
     578           8 :                                 break;
     579             :                         case IS_NULL:
     580           0 :                                 formattable.setInt64((int64_t)0);
     581           0 :                                 break;
     582             :                         case IS_STRING:
     583             :                         case IS_OBJECT:
     584           0 :                                 goto string_arg;
     585             :                         default:
     586             :                                 {
     587             :                                         char *message;
     588             :                                         zend_string *u8key;
     589           0 :                                         UErrorCode status = UErrorCode();
     590           0 :                                         u8key = intl_charFromString(key, &status);
     591           0 :                                         if (u8key) {
     592             :                                                 spprintf(&message, 0, "No strategy to convert the "
     593             :                                                         "value given for the argument with key '%s' "
     594           0 :                                                         "is available", ZSTR_VAL(u8key));
     595             :                                                 intl_errors_set(&err,
     596           0 :                                                         U_ILLEGAL_ARGUMENT_ERROR, message, 1);
     597             :                                                 zend_string_release(u8key);
     598           0 :                                                 efree(message);
     599             :                                         }
     600             :                                 }
     601             :                         }
     602             :                 }
     603          89 :                 argNum++;
     604             :         } ZEND_HASH_FOREACH_END(); // visiting each argument
     605             : 
     606          37 :         if (U_FAILURE(err.code)) {
     607             :                 return;
     608             :         }
     609             : 
     610          37 :         UnicodeString resultStr;
     611          37 :         FieldPosition fieldPosition(0);
     612             : 
     613             :         /* format the message */
     614             :         mf->format(farg_names.empty() ? NULL : &farg_names[0],
     615          37 :                 fargs.empty() ? NULL : &fargs[0], arg_count, resultStr, err.code);
     616             : 
     617          37 :         if (U_FAILURE(err.code)) {
     618             :                 intl_errors_set(&err, err.code,
     619           0 :                         "Call to ICU MessageFormat::format() has failed", 0);
     620             :                 return;
     621             :         }
     622             : 
     623          37 :         *formatted_len = resultStr.length();
     624          37 :         *formatted = eumalloc(*formatted_len+1);
     625          37 :         resultStr.extract(*formatted, *formatted_len+1, err.code);
     626          37 :         if (U_FAILURE(err.code)) {
     627             :                 intl_errors_set(&err, err.code,
     628           0 :                         "Error copying format() result", 0);
     629             :                 return;
     630           0 :         }
     631             : }
     632             : 
     633             : #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
     634             : 
     635          21 : U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval **args, UChar *source, int32_t source_len, UErrorCode *status)
     636             : {
     637          21 :     UnicodeString srcString(source, source_len);
     638          21 :     Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
     639             : 
     640          21 :         if(U_FAILURE(*status)) {
     641             :                 return;
     642             :         }
     643             : 
     644          21 :         *args = (zval *)safe_emalloc(*count, sizeof(zval), 0);
     645             : 
     646             :     // assign formattables to varargs
     647          21 :     for(int32_t i = 0; i < *count; i++) {
     648             :             int64_t aInt64;
     649             :                 double aDate;
     650          53 :                 UnicodeString temp;
     651             :                 zend_string *u8str;
     652             : 
     653          53 :                 switch(fargs[i].getType()) {
     654             :         case Formattable::kDate:
     655           1 :                         aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
     656           1 :                         ZVAL_DOUBLE(&(*args)[i], aDate);
     657           1 :             break;
     658             : 
     659             :         case Formattable::kDouble:
     660          16 :                         ZVAL_DOUBLE(&(*args)[i], (double)fargs[i].getDouble());
     661          16 :             break;
     662             : 
     663             :         case Formattable::kLong:
     664          36 :                         ZVAL_LONG(&(*args)[i], fargs[i].getLong());
     665          36 :             break;
     666             : 
     667             :         case Formattable::kInt64:
     668           0 :             aInt64 = fargs[i].getInt64();
     669           0 :                         if(aInt64 > ZEND_LONG_MAX || aInt64 < -ZEND_LONG_MAX) {
     670           0 :                                 ZVAL_DOUBLE(&(*args)[i], (double)aInt64);
     671             :                         } else {
     672           0 :                                 ZVAL_LONG(&(*args)[i], (zend_long)aInt64);
     673             :                         }
     674           0 :             break;
     675             : 
     676             :         case Formattable::kString:
     677           0 :             fargs[i].getString(temp);
     678           0 :                         u8str = intl_convert_utf16_to_utf8(temp.getBuffer(), temp.length(), status);
     679           0 :                         if(!u8str) {
     680           0 :                                 cleanup_zvals();
     681             :                                 return;
     682             :                         }
     683           0 :                         ZVAL_NEW_STR(&(*args)[i], u8str);
     684           0 :             break;
     685             : 
     686             :         case Formattable::kObject:
     687             :         case Formattable::kArray:
     688           0 :             *status = U_ILLEGAL_ARGUMENT_ERROR;
     689           0 :                         cleanup_zvals();
     690             :             break;
     691             :         }
     692             :     }
     693          21 :         delete[] fargs;
     694             : }
     695             : 
     696             : /*
     697             :  * Local variables:
     698             :  * tab-width: 4
     699             :  * c-basic-offset: 4
     700             :  * End:
     701             :  * vim600: noet sw=4 ts=4 fdm=marker
     702             :  * vim<600: noet sw=4 ts=4
     703             :  */

Generated by: LCOV version 1.10

Generated at Sun, 28 Aug 2016 17:10:02 +0000 (24 hours ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.