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: 118 202 58.4 %
Date: 2014-08-04 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       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          37 : static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo,
      87             :                                                                                  intl_error& err TSRMLS_DC)
      88             : {
      89             :         HashTable *ret;
      90             :         int32_t parts_count;
      91             : 
      92          37 :         if (U_FAILURE(err.code)) {
      93           0 :                 return NULL;
      94             :         }
      95             : 
      96          37 :         if (mfo->mf_data.arg_types) {
      97             :                 /* already cached */
      98           1 :                 return mfo->mf_data.arg_types;
      99             :         }
     100             : 
     101             :         const Formattable::Type *types = MessageFormatAdapter::getArgTypeList(
     102          36 :                 *(MessageFormat*)mfo->mf_data.umsgf, parts_count);
     103             : 
     104             :         /* Hash table will store Formattable::Type objects directly,
     105             :          * so no need for destructor */
     106          36 :         ALLOC_HASHTABLE(ret);
     107          36 :         zend_hash_init(ret, parts_count, NULL, NULL, 0);
     108             : 
     109         112 :         for (int i = 0; i < parts_count; i++) {
     110          76 :                 const Formattable::Type t = types[i];
     111          76 :                 if (zend_hash_index_update(ret, (ulong)i, (void*)&t, sizeof(t), NULL)
     112             :                                 == FAILURE) {
     113             :                         intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     114           0 :                                 "Write to argument types hash table failed", 0 TSRMLS_CC);
     115           0 :                         break;
     116             :                 }
     117             :         }
     118             : 
     119          36 :         if (U_FAILURE(err.code)) {
     120           0 :                 zend_hash_destroy(ret);
     121           0 :                 efree(ret);
     122             : 
     123           0 :                 return NULL;
     124             :         }
     125             : 
     126          36 :         mfo->mf_data.arg_types = ret;
     127             : 
     128          36 :         return ret;
     129             : }
     130             : 
     131             : #ifdef HAS_MESSAGE_PATTERN
     132             : static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
     133             :                                                                         const MessagePattern& mp,
     134             :                                                                         intl_error& err TSRMLS_DC)
     135             : {
     136             :         HashTable *ret;
     137             :         int32_t parts_count;
     138             : 
     139             :         if (U_FAILURE(err.code)) {
     140             :                 return NULL;
     141             :         }
     142             : 
     143             :         if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) {
     144             :                 return umsg_get_numeric_types(mfo, err TSRMLS_CC);
     145             :         }
     146             : 
     147             :         if (mfo->mf_data.arg_types) {
     148             :                 /* already cached */
     149             :                 return mfo->mf_data.arg_types;
     150             :         }
     151             : 
     152             :         /* Hash table will store Formattable::Type objects directly,
     153             :          * so no need for destructor */
     154             :         ALLOC_HASHTABLE(ret);
     155             :         zend_hash_init(ret, 32, NULL, NULL, 0);
     156             : 
     157             :         parts_count = mp.countParts();
     158             : 
     159             :         // See MessageFormat::cacheExplicitFormats()
     160             :         /*
     161             :          * Looking through the pattern, go to each arg_start part type.
     162             :          * The arg-typeof that tells us the argument type (simple, complicated)
     163             :          * then the next part is either the arg_name or arg number
     164             :          * and then if it's simple after that there could be a part-type=arg-type
     165             :          * while substring will tell us number, spellout, etc.
     166             :          * If the next thing isn't an arg-type then assume string.
     167             :         */
     168             :         /* The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
     169             :          * which we need not examine. */
     170             :         for (int32_t i = 0; i < parts_count - 2 && U_SUCCESS(err.code); i++) {
     171             :                 MessagePattern::Part p = mp.getPart(i);
     172             : 
     173             :                 if (p.getType() != UMSGPAT_PART_TYPE_ARG_START) {
     174             :                         continue;
     175             :                 }
     176             : 
     177             :                 MessagePattern::Part name_part = mp.getPart(++i); /* Getting name, advancing i */
     178             :                 Formattable::Type type,
     179             :                                                   *storedType;
     180             : 
     181             :                 if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) {
     182             :                         UnicodeString argName = mp.getSubstring(name_part);
     183             :                         if (zend_hash_find(ret, (char*)argName.getBuffer(), argName.length(),
     184             :                                         (void**)&storedType) == FAILURE) {
     185             :                                 /* not found already; create new entry in HT */
     186             :                                 Formattable::Type bogusType = Formattable::kObject;
     187             :                                 if (zend_hash_update(ret, (char*)argName.getBuffer(), argName.length(),
     188             :                                                 (void*)&bogusType, sizeof(bogusType), (void**)&storedType) == FAILURE) {
     189             :                                         intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
     190             :                                                 "Write to argument types hash table failed", 0 TSRMLS_CC);
     191             :                                         continue;
     192             :                                 }
     193             :                         }
     194             :                 } else if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
     195             :                         int32_t argNumber = name_part.getValue();
     196             :                         if (argNumber < 0) {
     197             :                                 intl_errors_set(&err, U_INVALID_FORMAT_ERROR,
     198             :                                         "Found part with negative number", 0 TSRMLS_CC);
     199             :                                 continue;
     200             :                         }
     201             :                         if (zend_hash_index_find(ret, (ulong)argNumber, (void**)&storedType)
     202             :                                         == FAILURE) {
     203             :                                 /* not found already; create new entry in HT */
     204             :                                 Formattable::Type bogusType = Formattable::kObject;
     205             :                                 if (zend_hash_index_update(ret, (ulong)argNumber, (void*)&bogusType,
     206             :                                                 sizeof(bogusType), (void**)&storedType) == FAILURE) {
     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 = zval_used_for_init,
     348           4 :                                  *zvptr = &nullzv;
     349             :                         used_tz = timezone_process_timezone_argument(&zvptr, &err,
     350           4 :                                 "msgfmt_format" TSRMLS_CC);
     351           4 :                         if (used_tz == NULL) {
     352           0 :                                 continue;
     353             :                         }
     354             :                 }
     355             :                 
     356           7 :                 df->setTimeZone(*used_tz);
     357             :         }
     358             : 
     359          30 :         if (U_SUCCESS(err.code)) {
     360          30 :                 mfo->mf_data.tz_set = 1;
     361             :         }
     362             : }
     363             : 
     364          37 : U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
     365             :                                                                 HashTable *args,
     366             :                                                                 UChar **formatted,
     367             :                                                                 int *formatted_len TSRMLS_DC)
     368             : {
     369          37 :         int arg_count = zend_hash_num_elements(args);
     370          37 :         std::vector<Formattable> fargs;
     371          37 :         std::vector<UnicodeString> farg_names;
     372          37 :         MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
     373             :         HashTable *types;
     374          37 :         intl_error& err = INTL_DATA_ERROR(mfo);
     375             : 
     376          37 :         if (U_FAILURE(err.code)) {
     377             :                 return;
     378             :         }
     379             : 
     380          37 :         types = umsg_get_types(mfo, err TSRMLS_CC);
     381             :         
     382          37 :         umsg_set_timezone(mfo, err TSRMLS_CC);
     383             : 
     384          37 :         fargs.resize(arg_count);
     385          37 :         farg_names.resize(arg_count);
     386             : 
     387          37 :         int                             argNum = 0;
     388             :         HashPosition    pos;
     389             :         zval                    **elem;
     390             : 
     391             :         // Key related variables
     392             :         int                             key_type;
     393             :         char                    *str_index;
     394             :         uint                    str_len;
     395             :         ulong                   num_index;
     396             : 
     397         126 :         for (zend_hash_internal_pointer_reset_ex(args, &pos);
     398             :                 U_SUCCESS(err.code) &&
     399             :                         (key_type = zend_hash_get_current_key_ex(
     400             :                                         args, &str_index, &str_len, &num_index, 0, &pos),
     401             :                                 zend_hash_get_current_data_ex(args, (void **)&elem, &pos)
     402             :                         ) == SUCCESS;
     403             :                 zend_hash_move_forward_ex(args, &pos), argNum++)
     404             :         {
     405          89 :                 Formattable& formattable = fargs[argNum];
     406          89 :                 UnicodeString& key = farg_names[argNum];
     407          89 :                 Formattable::Type argType = Formattable::kObject, //unknown
     408          89 :                                                   *storedArgType = NULL;
     409             : 
     410             :                 /* Process key and retrieve type */
     411          89 :                 if (key_type == HASH_KEY_IS_LONG) {
     412             :                         /* includes case where index < 0 because it's exposed as unsigned */
     413          89 :                         if (num_index > (ulong)INT32_MAX) {
     414             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     415           0 :                                         "Found negative or too large array key", 0 TSRMLS_CC);
     416           0 :                                 continue;
     417             :                         }
     418             : 
     419             :                    UChar temp[16];
     420          89 :                    int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index);
     421          89 :                    key.append(temp, len);
     422             : 
     423          89 :                    zend_hash_index_find(types, (ulong)num_index, (void**)&storedArgType);
     424             :                 } else { //string; assumed to be in UTF-8
     425           0 :                         intl_stringFromChar(key, str_index, str_len-1, &err.code);
     426             : 
     427           0 :                         if (U_FAILURE(err.code)) {
     428             :                                 char *message;
     429             :                                 spprintf(&message, 0,
     430           0 :                                         "Invalid UTF-8 data in argument key: '%s'", str_index);
     431           0 :                                 intl_errors_set(&err, err.code,     message, 1 TSRMLS_CC);
     432           0 :                                 efree(message);
     433           0 :                                 continue;
     434             :                         }
     435             : 
     436             :                         zend_hash_find(types, (char*)key.getBuffer(), key.length(),
     437           0 :                                 (void**)&storedArgType);
     438             :                 }
     439             : 
     440          89 :                 if (storedArgType != NULL) {
     441          77 :                         argType = *storedArgType;
     442             :                 }
     443             : 
     444             :                 /* Convert zval to formattable according to message format type
     445             :                  * or (as a fallback) the zval type */
     446          89 :                 if (argType != Formattable::kObject) {
     447          77 :                         switch (argType) {
     448             :                         case Formattable::kString:
     449             :                                 {
     450             :         string_arg:
     451             :                                         /* This implicitly converts objects
     452             :                                          * Note that our vectors will leak if object conversion fails
     453             :                                          * and PHP ends up with a fatal error and calls longjmp
     454             :                                          * as a result of that.
     455             :                                          */
     456           6 :                                         convert_to_string_ex(elem);
     457             : 
     458           1 :                                         UnicodeString *text = new UnicodeString();
     459             :                                         intl_stringFromChar(*text,
     460           1 :                                                 Z_STRVAL_PP(elem), Z_STRLEN_PP(elem), &err.code);
     461             : 
     462           1 :                                         if (U_FAILURE(err.code)) {
     463             :                                                 char *message;
     464             :                                                 spprintf(&message, 0, "Invalid UTF-8 data in string argument: "
     465           0 :                                                         "'%s'", Z_STRVAL_PP(elem));
     466           0 :                                                 intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
     467           0 :                                                 efree(message);
     468           0 :                                                 delete text;
     469           0 :                                                 continue;
     470             :                                         }
     471           1 :                                         formattable.adoptString(text);
     472           1 :                                         break;
     473             :                                 }
     474             :                         case Formattable::kDouble:
     475             :                                 {
     476             :                                         double d;
     477          40 :                                         if (Z_TYPE_PP(elem) == IS_DOUBLE) {
     478          22 :                                                 d = Z_DVAL_PP(elem);
     479          18 :                                         } else if (Z_TYPE_PP(elem) == IS_LONG) {
     480          18 :                                                 d = (double)Z_LVAL_PP(elem);
     481             :                                         } else {
     482           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     483           0 :                                                 convert_scalar_to_number(*elem TSRMLS_CC);
     484             :                                                 d = (Z_TYPE_PP(elem) == IS_DOUBLE)
     485             :                                                         ? Z_DVAL_PP(elem)
     486           0 :                                                         : (double)Z_LVAL_PP(elem);
     487             :                                         }
     488          40 :                                         formattable.setDouble(d);
     489          40 :                                         break;
     490             :                                 }
     491             :                         case Formattable::kLong:
     492             :                                 {
     493          32 :                                         int32_t tInt32 = 0;
     494             : retry_klong:
     495          32 :                                         if (Z_TYPE_PP(elem) == IS_DOUBLE) {
     496           0 :                                                 if (Z_DVAL_PP(elem) > (double)INT32_MAX ||
     497             :                                                                 Z_DVAL_PP(elem) < (double)INT32_MIN) {
     498             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     499             :                                                                 "Found PHP float with absolute value too large for "
     500           0 :                                                                 "32 bit integer argument", 0 TSRMLS_CC);
     501             :                                                 } else {
     502           0 :                                                         tInt32 = (int32_t)Z_DVAL_PP(elem);
     503             :                                                 }
     504          32 :                                         } else if (Z_TYPE_PP(elem) == IS_LONG) {
     505          32 :                                                 if (Z_LVAL_PP(elem) > INT32_MAX ||
     506             :                                                                 Z_LVAL_PP(elem) < INT32_MIN) {
     507             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     508             :                                                                 "Found PHP integer with absolute value too large "
     509           0 :                                                                 "for 32 bit integer argument", 0 TSRMLS_CC);
     510             :                                                 } else {
     511          32 :                                                         tInt32 = (int32_t)Z_LVAL_PP(elem);
     512             :                                                 }
     513             :                                         } else {
     514           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     515           0 :                                                 convert_scalar_to_number(*elem TSRMLS_CC);
     516           0 :                                                 goto retry_klong;
     517             :                                         }
     518          32 :                                         formattable.setLong(tInt32);
     519          32 :                                         break;
     520             :                                 }
     521             :                         case Formattable::kInt64:
     522             :                                 {
     523           0 :                                         int64_t tInt64 = 0;
     524             : retry_kint64:
     525           0 :                                         if (Z_TYPE_PP(elem) == IS_DOUBLE) {
     526           0 :                                                 if (Z_DVAL_PP(elem) > (double)U_INT64_MAX ||
     527             :                                                                 Z_DVAL_PP(elem) < (double)U_INT64_MIN) {
     528             :                                                         intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     529             :                                                                 "Found PHP float with absolute value too large for "
     530           0 :                                                                 "64 bit integer argument", 0 TSRMLS_CC);
     531             :                                                 } else {
     532           0 :                                                         tInt64 = (int64_t)Z_DVAL_PP(elem);
     533             :                                                 }
     534           0 :                                         } else if (Z_TYPE_PP(elem) == IS_LONG) {
     535             :                                                 /* assume long is not wider than 64 bits */
     536           0 :                                                 tInt64 = (int64_t)Z_LVAL_PP(elem);
     537             :                                         } else {
     538           0 :                                                 SEPARATE_ZVAL_IF_NOT_REF(elem);
     539           0 :                                                 convert_scalar_to_number(*elem TSRMLS_CC);
     540           0 :                                                 goto retry_kint64;
     541             :                                         }
     542           0 :                                         formattable.setInt64(tInt64);
     543           0 :                                         break;
     544             :                                 }
     545             :                         case Formattable::kDate:
     546             :                                 {
     547           4 :                                         double dd = intl_zval_to_millis(*elem, &err, "msgfmt_format" TSRMLS_CC);
     548           4 :                                         if (U_FAILURE(err.code)) {
     549             :                                                 char *message, *key_char;
     550             :                                                 int key_len;
     551           0 :                                                 UErrorCode status = UErrorCode();
     552           0 :                                                 if (intl_charFromString(key, &key_char, &key_len,
     553             :                                                                 &status) == SUCCESS) {
     554             :                                                         spprintf(&message, 0, "The argument for key '%s' "
     555           0 :                                                                 "cannot be used as a date or time", key_char);
     556           0 :                                                         intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
     557           0 :                                                         efree(key_char);
     558           0 :                                                         efree(message);
     559             :                                                 }
     560           0 :                                                 continue;
     561             :                                         }
     562           4 :                                         formattable.setDate(dd);
     563           4 :                                         break;
     564             :                                 }
     565             :                         default:
     566             :                                 intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
     567           0 :                                         "Found unsupported argument type", 0 TSRMLS_CC);
     568             :                                 break;
     569             :                         }
     570             :                 } else {
     571             :                         /* We couldn't find any information about the argument in the pattern, this
     572             :                          * means it's an extra argument. So convert it to a number if it's a number or
     573             :                          * bool or null and to a string if it's anything else except arrays . */
     574          12 :                         switch (Z_TYPE_PP(elem)) {
     575             :                         case IS_DOUBLE:
     576           4 :                                 formattable.setDouble(Z_DVAL_PP(elem));
     577           4 :                                 break;
     578             :                         case IS_BOOL:
     579           0 :                                 convert_to_long_ex(elem);
     580             :                                 /* Intentional fallthrough */
     581             :                         case IS_LONG:
     582           8 :                                 formattable.setInt64((int64_t)Z_LVAL_PP(elem));
     583           8 :                                 break;
     584             :                         case IS_NULL:
     585           0 :                                 formattable.setInt64((int64_t)0);
     586           0 :                                 break;
     587             :                         case IS_STRING:
     588             :                         case IS_OBJECT:
     589           0 :                                 goto string_arg;
     590             :                         default:
     591             :                                 {
     592             :                                         char *message, *key_char;
     593             :                                         int key_len;
     594           0 :                                         UErrorCode status = UErrorCode();
     595           0 :                                         if (intl_charFromString(key, &key_char, &key_len,
     596             :                                                         &status) == SUCCESS) {
     597             :                                                 spprintf(&message, 0, "No strategy to convert the "
     598             :                                                         "value given for the argument with key '%s' "
     599           0 :                                                         "is available", key_char);
     600             :                                                 intl_errors_set(&err,
     601           0 :                                                         U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
     602           0 :                                                 efree(key_char);
     603           0 :                                                 efree(message);
     604             :                                         }
     605             :                                 }
     606             :                         }
     607             :                 }
     608             :         } // visiting each argument
     609             : 
     610          37 :         if (U_FAILURE(err.code)) {
     611             :                 return;
     612             :         }
     613             : 
     614          37 :         UnicodeString resultStr;
     615          37 :         FieldPosition fieldPosition(0);
     616             : 
     617             :         /* format the message */
     618             :         mf->format(farg_names.empty() ? NULL : &farg_names[0],
     619          37 :                 fargs.empty() ? NULL : &fargs[0], arg_count, resultStr, err.code);
     620             : 
     621          37 :         if (U_FAILURE(err.code)) {
     622             :                 intl_errors_set(&err, err.code,
     623           0 :                         "Call to ICU MessageFormat::format() has failed", 0 TSRMLS_CC);
     624             :                 return;
     625             :         }
     626             : 
     627          37 :         *formatted_len = resultStr.length();
     628          37 :         *formatted = eumalloc(*formatted_len+1);
     629          37 :         resultStr.extract(*formatted, *formatted_len+1, err.code);
     630          37 :         if (U_FAILURE(err.code)) {
     631             :                 intl_errors_set(&err, err.code,
     632           0 :                         "Error copying format() result", 0 TSRMLS_CC);
     633             :                 return;
     634           0 :         }
     635             : }
     636             : 
     637             : #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
     638             : 
     639          21 : U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UChar *source, int source_len, UErrorCode *status)
     640             : {
     641          21 :     UnicodeString srcString(source, source_len);
     642          21 :     Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
     643             : 
     644          21 :         if(U_FAILURE(*status)) {
     645             :                 return;
     646             :         }
     647             : 
     648          21 :         *args = (zval **)safe_emalloc(*count, sizeof(zval *), 0);
     649             : 
     650             :     // assign formattables to varargs
     651          21 :     for(int32_t i = 0; i < *count; i++) {
     652             :             int64_t aInt64;
     653             :                 double aDate;
     654          53 :                 UnicodeString temp;
     655             :                 char *stmp;
     656             :                 int stmp_len;
     657             : 
     658          53 :                 ALLOC_INIT_ZVAL((*args)[i]);
     659             : 
     660          53 :                 switch(fargs[i].getType()) {
     661             :         case Formattable::kDate:
     662           1 :                         aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
     663           1 :                         ZVAL_DOUBLE((*args)[i], aDate);
     664           1 :             break;
     665             : 
     666             :         case Formattable::kDouble:
     667          16 :                         ZVAL_DOUBLE((*args)[i], (double)fargs[i].getDouble());
     668          16 :             break;
     669             : 
     670             :         case Formattable::kLong:
     671          36 :                         ZVAL_LONG((*args)[i], fargs[i].getLong());
     672          36 :             break;
     673             : 
     674             :         case Formattable::kInt64:
     675           0 :             aInt64 = fargs[i].getInt64();
     676           0 :                         if(aInt64 > LONG_MAX || aInt64 < -LONG_MAX) {
     677           0 :                                 ZVAL_DOUBLE((*args)[i], (double)aInt64);
     678             :                         } else {
     679           0 :                                 ZVAL_LONG((*args)[i], (long)aInt64);
     680             :                         }
     681           0 :             break;
     682             : 
     683             :         case Formattable::kString:
     684           0 :             fargs[i].getString(temp);
     685           0 :                         intl_convert_utf16_to_utf8(&stmp, &stmp_len, temp.getBuffer(), temp.length(), status);
     686           0 :                         if(U_FAILURE(*status)) {
     687           0 :                                 cleanup_zvals();
     688             :                                 return;
     689             :                         }
     690           0 :                         ZVAL_STRINGL((*args)[i], stmp, stmp_len, 0);
     691           0 :             break;
     692             : 
     693             :         case Formattable::kObject:
     694             :         case Formattable::kArray:
     695           0 :             *status = U_ILLEGAL_ARGUMENT_ERROR;
     696           0 :                         cleanup_zvals();
     697             :             break;
     698             :         }
     699             :     }
     700          21 :         delete[] fargs;
     701             : }
     702             : 
     703             : /*
     704             :  * Local variables:
     705             :  * tab-width: 4
     706             :  * c-basic-offset: 4
     707             :  * End:
     708             :  * vim600: noet sw=4 ts=4 fdm=marker
     709             :  * vim<600: noet sw=4 ts=4
     710             :  */

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:05 +0000 (15 days ago)

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