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 208 58.7 %
Date: 2014-10-22 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 TSRMLS_DC)
      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 TSRMLS_CC);
     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 TSRMLS_DC)
     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 TSRMLS_CC);
     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 TSRMLS_CC);
     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 TSRMLS_CC);
     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 TSRMLS_CC);
     209             :                                         continue;
     210             :                                 }
     211             :                         }
     212             :                 } else {
     213             :                         intl_errors_set(&err, U_INVALID_FORMAT_ERROR, "Invalid part type encountered", 0 TSRMLS_CC);
     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 TSRMLS_CC);
     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             :                         } else {
     268             :                                 type = Formattable::kString;
     269             :                         }
     270             :                 } /* was type specified? */
     271             : 
     272             :                 /* We found a different type for the same arg! */
     273             :                 if (*storedType != Formattable::kObject && *storedType != type) {
     274             :                         intl_errors_set(&err, U_ARGUMENT_TYPE_MISMATCH,
     275             :                                 "Inconsistent types declared for an argument", 0 TSRMLS_CC);
     276             :                         continue;
     277             :                 }
     278             : 
     279             :                 *storedType = type;
     280             :         } /* visiting each part */
     281             : 
     282             :         if (U_FAILURE(err.code)) {
     283             :                 zend_hash_destroy(ret);
     284             :                 efree(ret);
     285             : 
     286             :                 return NULL;
     287             :         }
     288             : 
     289             :         mfo->mf_data.arg_types = ret;
     290             : 
     291             :         return ret;
     292             : }
     293             : #endif
     294             : 
     295          37 : static HashTable *umsg_get_types(MessageFormatter_object *mfo,
     296             :                                                                  intl_error& err TSRMLS_DC)
     297             : {
     298          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     299             : 
     300             : #ifdef HAS_MESSAGE_PATTERN
     301             :         const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf);
     302             : 
     303             :         return umsg_parse_format(mfo, mp, err TSRMLS_CC);
     304             : #else
     305          37 :         if (mf->usesNamedArguments()) {
     306             :                         intl_errors_set(&err, U_UNSUPPORTED_ERROR,
     307             :                                 "This extension supports named arguments only on ICU 4.8+",
     308           0 :                                 0 TSRMLS_CC);
     309           0 :                 return NULL;
     310             :         }
     311          37 :         return umsg_get_numeric_types(mfo, err TSRMLS_CC);
     312             : #endif
     313             : }
     314             : 
     315          37 : static void umsg_set_timezone(MessageFormatter_object *mfo,
     316             :                                                           intl_error& err TSRMLS_DC)
     317             : {
     318          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     319          37 :         TimeZone          *used_tz = NULL;
     320             :         const Format  **formats;
     321             :         int32_t           count;
     322             : 
     323             :         /* Unfortanely, this cannot change the time zone for arguments that
     324             :          * appear inside complex formats because ::getFormats() returns NULL
     325             :          * for all uncached formats, which is the case for complex formats
     326             :          * unless they were set via one of the ::setFormat() methods */
     327             :         
     328          37 :         if (mfo->mf_data.tz_set) {
     329           7 :                 return; /* already done */
     330             :         }
     331             : 
     332          30 :         formats = mf->getFormats(count);
     333             :         
     334          30 :         if (formats == NULL) {
     335             :                 intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     336           0 :                         "Out of memory retrieving subformats", 0 TSRMLS_CC);
     337             :         }
     338             : 
     339          97 :         for (int i = 0; U_SUCCESS(err.code) && i < count; i++) {
     340             :                 DateFormat* df = dynamic_cast<DateFormat*>(
     341          67 :                         const_cast<Format *>(formats[i]));
     342          67 :                 if (df == NULL) {
     343          60 :                         continue;
     344             :                 }
     345             :                 
     346           7 :                 if (used_tz == NULL) {
     347           4 :                         zval nullzv, *zvptr = &nullzv;
     348           4 :                         ZVAL_NULL(zvptr);
     349           4 :                         used_tz = timezone_process_timezone_argument(zvptr, &err, "msgfmt_format" TSRMLS_CC);
     350           4 :                         if (used_tz == NULL) {
     351           0 :                                 continue;
     352             :                         }
     353             :                 }
     354             :                 
     355           7 :                 df->setTimeZone(*used_tz);
     356             :         }
     357             : 
     358          30 :         if (U_SUCCESS(err.code)) {
     359          30 :                 mfo->mf_data.tz_set = 1;
     360             :         }
     361             : }
     362             : 
     363          37 : U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
     364             :                                                                 HashTable *args,
     365             :                                                                 UChar **formatted,
     366             :                                                                 int *formatted_len TSRMLS_DC)
     367             : {
     368          37 :         int arg_count = zend_hash_num_elements(args);
     369          37 :         std::vector<Formattable> fargs;
     370          37 :         std::vector<UnicodeString> farg_names;
     371          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     372             :         HashTable *types;
     373          37 :         intl_error& err = INTL_DATA_ERROR(mfo);
     374             : 
     375          37 :         if (U_FAILURE(err.code)) {
     376             :                 return;
     377             :         }
     378             : 
     379          37 :         types = umsg_get_types(mfo, err TSRMLS_CC);
     380             :         
     381          37 :         umsg_set_timezone(mfo, err TSRMLS_CC);
     382             : 
     383          37 :         fargs.resize(arg_count);
     384          37 :         farg_names.resize(arg_count);
     385             : 
     386          37 :         int                             argNum = 0;
     387             :         zval                    *elem;
     388             : 
     389             :         // Key related variables
     390             :         zend_string             *str_index;
     391             :         zend_ulong                      num_index;
     392             : 
     393         215 :         ZEND_HASH_FOREACH_KEY_VAL(args, num_index, str_index, elem) {
     394          89 :                 Formattable& formattable = fargs[argNum];
     395          89 :                 UnicodeString& key = farg_names[argNum];
     396          89 :                 Formattable::Type argType = Formattable::kObject, //unknown
     397          89 :                                                   *storedArgType = NULL;
     398          89 :                 if (!U_SUCCESS(err.code)) {
     399           0 :                         break;
     400             :                 }
     401             :                 /* Process key and retrieve type */
     402          89 :                 if (str_index == NULL) {
     403             :                         /* includes case where index < 0 because it's exposed as unsigned */
     404          89 :                         if (num_index > (zend_ulong)INT32_MAX) {
     405             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     406           0 :                                         "Found negative or too large array key", 0 TSRMLS_CC);
     407           0 :                                 continue;
     408             :                         }
     409             : 
     410             :                    UChar temp[16];
     411          89 :                    int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index);
     412          89 :                    key.append(temp, len);
     413             : 
     414          89 :                    storedArgType = (Formattable::Type*)zend_hash_index_find_ptr(types, (zend_ulong)num_index);
     415             :                 } else { //string; assumed to be in UTF-8
     416           0 :                         intl_stringFromChar(key, str_index->val, str_index->len, &err.code);
     417             : 
     418           0 :                         if (U_FAILURE(err.code)) {
     419             :                                 char *message;
     420             :                                 spprintf(&message, 0,
     421           0 :                                         "Invalid UTF-8 data in argument key: '%s'", str_index->val);
     422           0 :                                 intl_errors_set(&err, err.code,     message, 1 TSRMLS_CC);
     423           0 :                                 efree(message);
     424           0 :                                 continue;
     425             :                         }
     426             : 
     427           0 :                         storedArgType = (Formattable::Type*)zend_hash_str_find_ptr(types, (char*)key.getBuffer(), key.length());
     428             :                 }
     429             : 
     430          89 :                 if (storedArgType != NULL) {
     431          77 :                         argType = *storedArgType;
     432             :                 }
     433             : 
     434             :                 /* Convert zval to formattable according to message format type
     435             :                  * or (as a fallback) the zval type */
     436          89 :                 if (argType != Formattable::kObject) {
     437          77 :                         switch (argType) {
     438             :                         case Formattable::kString:
     439             :                                 {
     440             :         string_arg:
     441             :                                         /* This implicitly converts objects
     442             :                                          * Note that our vectors will leak if object conversion fails
     443             :                                          * and PHP ends up with a fatal error and calls longjmp
     444             :                                          * as a result of that.
     445             :                                          */
     446           2 :                                         convert_to_string_ex(elem);
     447             : 
     448           1 :                                         UnicodeString *text = new UnicodeString();
     449             :                                         intl_stringFromChar(*text,
     450           1 :                                                 Z_STRVAL_P(elem), Z_STRLEN_P(elem), &err.code);
     451             : 
     452           1 :                                         if (U_FAILURE(err.code)) {
     453             :                                                 char *message;
     454             :                                                 spprintf(&message, 0, "Invalid UTF-8 data in string argument: "
     455           0 :                                                         "'%s'", Z_STRVAL_P(elem));
     456           0 :                                                 intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
     457           0 :                                                 efree(message);
     458           0 :                                                 delete text;
     459           0 :                                                 continue;
     460             :                                         }
     461           1 :                                         formattable.adoptString(text);
     462           1 :                                         break;
     463             :                                 }
     464             :                         case Formattable::kDouble:
     465             :                                 {
     466             :                                         double d;
     467          40 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     468          22 :                                                 d = Z_DVAL_P(elem);
     469          18 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     470          18 :                                                 d = (double)Z_LVAL_P(elem);
     471             :                                         } else {
     472           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     473           0 :                                                 convert_scalar_to_number(elem TSRMLS_CC);
     474             :                                                 d = (Z_TYPE_P(elem) == IS_DOUBLE)
     475             :                                                         ? Z_DVAL_P(elem)
     476           0 :                                                         : (double)Z_LVAL_P(elem);
     477             :                                         }
     478          40 :                                         formattable.setDouble(d);
     479          40 :                                         break;
     480             :                                 }
     481             :                         case Formattable::kLong:
     482             :                                 {
     483          32 :                                         int32_t tInt32 = 0;
     484             : retry_klong:
     485          32 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     486           0 :                                                 if (Z_DVAL_P(elem) > (double)INT32_MAX ||
     487             :                                                                 Z_DVAL_P(elem) < (double)INT32_MIN) {
     488             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     489             :                                                                 "Found PHP float with absolute value too large for "
     490           0 :                                                                 "32 bit integer argument", 0 TSRMLS_CC);
     491             :                                                 } else {
     492           0 :                                                         tInt32 = (int32_t)Z_DVAL_P(elem);
     493             :                                                 }
     494          32 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     495          32 :                                                 if (Z_LVAL_P(elem) > INT32_MAX ||
     496             :                                                                 Z_LVAL_P(elem) < INT32_MIN) {
     497             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     498             :                                                                 "Found PHP integer with absolute value too large "
     499           0 :                                                                 "for 32 bit integer argument", 0 TSRMLS_CC);
     500             :                                                 } else {
     501          32 :                                                         tInt32 = (int32_t)Z_LVAL_P(elem);
     502             :                                                 }
     503             :                                         } else {
     504           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     505           0 :                                                 convert_scalar_to_number(elem TSRMLS_CC);
     506           0 :                                                 goto retry_klong;
     507             :                                         }
     508          32 :                                         formattable.setLong(tInt32);
     509          32 :                                         break;
     510             :                                 }
     511             :                         case Formattable::kInt64:
     512             :                                 {
     513           0 :                                         int64_t tInt64 = 0;
     514             : retry_kint64:
     515           0 :                                         if (Z_TYPE_P(elem) == IS_DOUBLE) {
     516           0 :                                                 if (Z_DVAL_P(elem) > (double)U_INT64_MAX ||
     517             :                                                                 Z_DVAL_P(elem) < (double)U_INT64_MIN) {
     518             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     519             :                                                                 "Found PHP float with absolute value too large for "
     520           0 :                                                                 "64 bit integer argument", 0 TSRMLS_CC);
     521             :                                                 } else {
     522           0 :                                                         tInt64 = (int64_t)Z_DVAL_P(elem);
     523             :                                                 }
     524           0 :                                         } else if (Z_TYPE_P(elem) == IS_LONG) {
     525             :                                                 /* assume long is not wider than 64 bits */
     526           0 :                                                 tInt64 = (int64_t)Z_LVAL_P(elem);
     527             :                                         } else {
     528           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     529           0 :                                                 convert_scalar_to_number(elem TSRMLS_CC);
     530           0 :                                                 goto retry_kint64;
     531             :                                         }
     532           0 :                                         formattable.setInt64(tInt64);
     533           0 :                                         break;
     534             :                                 }
     535             :                         case Formattable::kDate:
     536             :                                 {
     537           4 :                                         double dd = intl_zval_to_millis(elem, &err, "msgfmt_format" TSRMLS_CC);
     538           4 :                                         if (U_FAILURE(err.code)) {
     539             :                                                 char *message, *key_char;
     540             :                                                 int key_len;
     541           0 :                                                 UErrorCode status = UErrorCode();
     542           0 :                                                 if (intl_charFromString(key, &key_char, &key_len,
     543             :                                                                 &status) == SUCCESS) {
     544             :                                                         spprintf(&message, 0, "The argument for key '%s' "
     545           0 :                                                                 "cannot be used as a date or time", key_char);
     546           0 :                                                         intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
     547           0 :                                                         efree(key_char);
     548           0 :                                                         efree(message);
     549             :                                                 }
     550           0 :                                                 continue;
     551             :                                         }
     552           4 :                                         formattable.setDate(dd);
     553           4 :                                         break;
     554             :                                 }
     555             :                         default:
     556             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     557           0 :                                         "Found unsupported argument type", 0 TSRMLS_CC);
     558             :                                 break;
     559             :                         }
     560             :                 } else {
     561             :                         /* We couldn't find any information about the argument in the pattern, this
     562             :                          * means it's an extra argument. So convert it to a number if it's a number or
     563             :                          * bool or null and to a string if it's anything else except arrays . */
     564          12 :                         switch (Z_TYPE_P(elem)) {
     565             :                         case IS_DOUBLE:
     566           4 :                                 formattable.setDouble(Z_DVAL_P(elem));
     567           4 :                                 break;
     568             :                         case IS_TRUE:
     569             :                         case IS_FALSE:
     570           0 :                                 convert_to_long_ex(elem);
     571             :                                 /* Intentional fallthrough */
     572             :                         case IS_LONG:
     573           8 :                                 formattable.setInt64((int64_t)Z_LVAL_P(elem));
     574           8 :                                 break;
     575             :                         case IS_NULL:
     576           0 :                                 formattable.setInt64((int64_t)0);
     577           0 :                                 break;
     578             :                         case IS_STRING:
     579             :                         case IS_OBJECT:
     580           0 :                                 goto string_arg;
     581             :                         default:
     582             :                                 {
     583             :                                         char *message, *key_char;
     584             :                                         int key_len;
     585           0 :                                         UErrorCode status = UErrorCode();
     586           0 :                                         if (intl_charFromString(key, &key_char, &key_len,
     587             :                                                         &status) == SUCCESS) {
     588             :                                                 spprintf(&message, 0, "No strategy to convert the "
     589             :                                                         "value given for the argument with key '%s' "
     590           0 :                                                         "is available", key_char);
     591             :                                                 intl_errors_set(&err,
     592           0 :                                                         U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
     593           0 :                                                 efree(key_char);
     594           0 :                                                 efree(message);
     595             :                                         }
     596             :                                 }
     597             :                         }
     598             :                 }
     599          89 :                 argNum++;
     600             :         } ZEND_HASH_FOREACH_END(); // visiting each argument
     601             : 
     602          37 :         if (U_FAILURE(err.code)) {
     603             :                 return;
     604             :         }
     605             : 
     606          37 :         UnicodeString resultStr;
     607          37 :         FieldPosition fieldPosition(0);
     608             : 
     609             :         /* format the message */
     610             :         mf->format(farg_names.empty() ? NULL : &farg_names[0],
     611          37 :                 fargs.empty() ? NULL : &fargs[0], arg_count, resultStr, err.code);
     612             : 
     613          37 :         if (U_FAILURE(err.code)) {
     614             :                 intl_errors_set(&err, err.code,
     615           0 :                         "Call to ICU MessageFormat::format() has failed", 0 TSRMLS_CC);
     616             :                 return;
     617             :         }
     618             : 
     619          37 :         *formatted_len = resultStr.length();
     620          37 :         *formatted = eumalloc(*formatted_len+1);
     621          37 :         resultStr.extract(*formatted, *formatted_len+1, err.code);
     622          37 :         if (U_FAILURE(err.code)) {
     623             :                 intl_errors_set(&err, err.code,
     624           0 :                         "Error copying format() result", 0 TSRMLS_CC);
     625             :                 return;
     626           0 :         }
     627             : }
     628             : 
     629             : #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
     630             : 
     631          21 : U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval **args, UChar *source, int source_len, UErrorCode *status)
     632             : {
     633          21 :     UnicodeString srcString(source, source_len);
     634          21 :     Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
     635             : 
     636          21 :         if(U_FAILURE(*status)) {
     637             :                 return;
     638             :         }
     639             : 
     640          21 :         *args = (zval *)safe_emalloc(*count, sizeof(zval), 0);
     641             : 
     642             :     // assign formattables to varargs
     643          21 :     for(int32_t i = 0; i < *count; i++) {
     644             :             int64_t aInt64;
     645             :                 double aDate;
     646          53 :                 UnicodeString temp;
     647             :                 char *stmp;
     648             :                 int stmp_len;
     649             : 
     650          53 :                 switch(fargs[i].getType()) {
     651             :         case Formattable::kDate:
     652           1 :                         aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
     653           1 :                         ZVAL_DOUBLE(&(*args)[i], aDate);
     654           1 :             break;
     655             : 
     656             :         case Formattable::kDouble:
     657          16 :                         ZVAL_DOUBLE(&(*args)[i], (double)fargs[i].getDouble());
     658          16 :             break;
     659             : 
     660             :         case Formattable::kLong:
     661          36 :                         ZVAL_LONG(&(*args)[i], fargs[i].getLong());
     662          36 :             break;
     663             : 
     664             :         case Formattable::kInt64:
     665           0 :             aInt64 = fargs[i].getInt64();
     666           0 :                         if(aInt64 > ZEND_LONG_MAX || aInt64 < -ZEND_LONG_MAX) {
     667           0 :                                 ZVAL_DOUBLE(&(*args)[i], (double)aInt64);
     668             :                         } else {
     669           0 :                                 ZVAL_LONG(&(*args)[i], (zend_long)aInt64);
     670             :                         }
     671           0 :             break;
     672             : 
     673             :         case Formattable::kString:
     674           0 :             fargs[i].getString(temp);
     675           0 :                         intl_convert_utf16_to_utf8(&stmp, &stmp_len, temp.getBuffer(), temp.length(), status);
     676           0 :                         if(U_FAILURE(*status)) {
     677           0 :                                 cleanup_zvals();
     678             :                                 return;
     679             :                         }
     680           0 :                         ZVAL_STRINGL(&(*args)[i], stmp, stmp_len);
     681             :                         //???
     682           0 :                         efree(stmp);
     683           0 :             break;
     684             : 
     685             :         case Formattable::kObject:
     686             :         case Formattable::kArray:
     687           0 :             *status = U_ILLEGAL_ARGUMENT_ERROR;
     688           0 :                         cleanup_zvals();
     689             :             break;
     690             :         }
     691             :     }
     692          21 :         delete[] fargs;
     693             : }
     694             : 
     695             : /*
     696             :  * Local variables:
     697             :  * tab-width: 4
     698             :  * c-basic-offset: 4
     699             :  * End:
     700             :  * vim600: noet sw=4 ts=4 fdm=marker
     701             :  * vim<600: noet sw=4 ts=4
     702             :  */

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:50 +0000 (3 days ago)

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