/* {{{ * Internal function which fetches an element from the passed array for the key_name passed */ static int32_t internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* hash_arr, char* key_name, intl_error *err) { zval *ele_value = NULL; int32_t result = 0; char *message; if (U_FAILURE(err->code)) { return result; } if ((ele_value = zend_hash_str_find(hash_arr, key_name, strlen(key_name))) != NULL) { if(Z_TYPE_P(ele_value) != IS_LONG) { spprintf(&message, 0, "datefmt_format: parameter array contains " "a non-integer element for key '%s'", key_name); intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1); efree(message); } else { if (Z_LVAL_P(ele_value) > INT32_MAX || Z_LVAL_P(ele_value) < INT32_MIN) { spprintf(&message, 0, "datefmt_format: value " ZEND_LONG_FMT " is out of " "bounds for a 32-bit integer in key '%s'", Z_LVAL_P(ele_value), key_name); intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1); efree(message); } else { result = Z_LVAL_P(ele_value); } } } return result; }
/* {{{ proto bool datefmt_set_calendar(IntlDateFormatter $mf, mixed $calendar) * Set formatter's calendar. */ U_CFUNC PHP_FUNCTION(datefmt_set_calendar) { zval *calendar_zv; DATE_FORMAT_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &object, IntlDateFormatter_ce_ptr, &calendar_zv) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC); RETURN_FALSE; } DATE_FORMAT_METHOD_FETCH_OBJECT; Calendar *cal; long cal_type; bool cal_owned; Locale locale = Locale::createFromName(dfo->requested_locale); // getting the actual locale from the DateFormat is not enough // because we would have lost modifiers such as @calendar. We // must store the requested locale on object creation if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_set_calendar", INTL_DATA_ERROR_P(dfo), cal, cal_type, cal_owned TSRMLS_CC) == FAILURE) { RETURN_FALSE; } if (cal_owned) { /* a non IntlCalendar was specified, we want to keep the timezone */ TimeZone *old_timezone = fetch_datefmt(dfo)->getTimeZone().clone(); if (old_timezone == NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_set_calendar: Out of memory when cloning calendar", 0 TSRMLS_CC); delete cal; RETURN_FALSE; } cal->adoptTimeZone(old_timezone); } else { cal = cal->clone(); if (cal == NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_set_calendar: Out of memory when cloning calendar", 0 TSRMLS_CC); RETURN_FALSE; } } fetch_datefmt(dfo)->adoptCalendar(cal); dfo->calendar = cal_type; RETURN_TRUE; }
/* {{{ proto IntlTimeZone datefmt_get_timezone(IntlDateFormatter $mf) * Get formatter timezone. */ U_CFUNC PHP_FUNCTION(datefmt_get_timezone) { DATE_FORMAT_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_get_timezone: unable to parse input params", 0 TSRMLS_CC ); RETURN_FALSE; } DATE_FORMAT_METHOD_FETCH_OBJECT; const TimeZone& tz = fetch_datefmt(dfo)->getTimeZone(); TimeZone *tz_clone = tz.clone(); if (tz_clone == NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_get_timezone: Out of memory when cloning time zone", 0 TSRMLS_CC); RETURN_FALSE; } object_init_ex(return_value, TimeZone_ce_ptr); timezone_object_construct(tz_clone, return_value, 1 TSRMLS_CC); }
U_CFUNC PHP_FUNCTION(rbbi_get_binary_rules) { BREAKITER_METHOD_INIT_VARS; object = getThis(); if (zend_parse_parameters_none() == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "rbbi_get_binary_rules: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } BREAKITER_METHOD_FETCH_OBJECT; uint32_t rules_len; const uint8_t *rules = fetch_rbbi(bio)->getBinaryRules(rules_len); if (rules_len > INT_MAX - 1) { intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), "rbbi_get_binary_rules: the rules are too large", 0 TSRMLS_CC); RETURN_FALSE; } char *ret_rules = static_cast<char*>(emalloc(rules_len + 1)); memcpy(ret_rules, rules, rules_len); ret_rules[rules_len] = '\0'; RETURN_STRINGL(ret_rules, rules_len, 0); }
U_CFUNC PHP_FUNCTION(intlcal_equals) { zval *other_object; Calendar_object *other_co; CALENDAR_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_equals: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } CALENDAR_METHOD_FETCH_OBJECT; other_co = Z_INTL_CALENDAR_P(other_object); if (other_co->ucal == NULL) { intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_equals: The second IntlCalendar is unconstructed", 0 TSRMLS_CC); RETURN_FALSE; } UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co)); INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals"); RETURN_BOOL((int)result); }
U_CFUNC PHP_FUNCTION(rbbi_get_rules) { BREAKITER_METHOD_INIT_VARS; object = getThis(); if (zend_parse_parameters_none() == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "rbbi_get_rules: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } BREAKITER_METHOD_FETCH_OBJECT; const UnicodeString rules = fetch_rbbi(bio)->getRules(); Z_TYPE_P(return_value) = IS_STRING; if (intl_charFromString(rules, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), BREAKITER_ERROR_CODE_P(bio)) == FAILURE) { intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), "rbbi_hash_code: Error converting result to UTF-8 string", 0 TSRMLS_CC); RETURN_FALSE; } }
/* {{{ IntlDateFormatter_object_clone */ zend_object *IntlDateFormatter_object_clone(zval *object) { IntlDateFormatter_object *dfo, *new_dfo; zend_object *new_obj; DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK; new_obj = IntlDateFormatter_ce_ptr->create_object(Z_OBJCE_P(object)); new_dfo = php_intl_dateformatter_fetch_object(new_obj); /* clone standard parts */ zend_objects_clone_members(&new_dfo->zo, &dfo->zo); /* clone formatter object */ if (dfo->datef_data.udatf != NULL) { DATE_FORMAT_OBJECT(new_dfo) = udat_clone(DATE_FORMAT_OBJECT(dfo), &INTL_DATA_ERROR_CODE(dfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { /* set up error in case error handler is interested */ intl_errors_set(INTL_DATA_ERROR_P(dfo), INTL_DATA_ERROR_CODE(dfo), "Failed to clone IntlDateFormatter object", 0 ); zend_throw_exception(NULL, "Failed to clone IntlDateFormatter object", 0); } } else { zend_throw_exception(NULL, "Cannot clone unconstructed IntlDateFormatter", 0); } return new_obj; }
U_CFUNC PHP_FUNCTION(rbbi_get_rules) { BREAKITER_METHOD_INIT_VARS; object = getThis(); if (zend_parse_parameters_none() == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "rbbi_get_rules: bad arguments", 0); RETURN_FALSE; } BREAKITER_METHOD_FETCH_OBJECT; char *str; int str_len; const UnicodeString rules = fetch_rbbi(bio)->getRules(); if (intl_charFromString(rules, &str, &str_len, BREAKITER_ERROR_CODE_P(bio)) == FAILURE) { intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), "rbbi_hash_code: Error converting result to UTF-8 string", 0); RETURN_FALSE; } RETVAL_STRINGL(str, str_len); //??? efree(str); }
static void _php_intlcal_before_after( UBool (Calendar::*func)(const Calendar&, UErrorCode&) const, INTERNAL_FUNCTION_PARAMETERS) { zval *when_object; Calendar_object *when_co; CALENDAR_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, Calendar_ce_ptr, &when_object, Calendar_ce_ptr) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_before/after: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } CALENDAR_METHOD_FETCH_OBJECT; when_co = Z_INTL_CALENDAR_P(when_object); if (when_co->ucal == NULL) { intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_before/after: Other IntlCalendar was unconstructed", 0 TSRMLS_CC); RETURN_FALSE; } UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co)); INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method"); RETURN_BOOL((int)res); }
/* {{{ proto IntlCalendar datefmt_get_calendar_object(IntlDateFormatter $mf) * Get formatter calendar. */ U_CFUNC PHP_FUNCTION(datefmt_get_calendar_object) { DATE_FORMAT_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_get_calendar_object: unable to parse input params", 0 TSRMLS_CC); RETURN_FALSE; } DATE_FORMAT_METHOD_FETCH_OBJECT; const Calendar *cal = fetch_datefmt(dfo)->getCalendar(); if (cal == NULL) { RETURN_NULL(); } Calendar *cal_clone = cal->clone(); if (cal_clone == NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_get_calendar_object: Out of memory when cloning " "calendar", 0 TSRMLS_CC); RETURN_FALSE; } calendar_object_create(return_value, cal_clone TSRMLS_CC); }
/* {{{ ResourceBundle_extract_value */ void resourcebundle_extract_value( zval *return_value, ResourceBundle_object *source ) { UResType restype; const UChar* ufield; const uint8_t* bfield; const int32_t* vfield; int32_t ilen; int i; zend_long lfield; ResourceBundle_object* newrb; restype = ures_getType( source->child ); switch (restype) { case URES_STRING: ufield = ures_getString( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) ); INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve string value"); INTL_METHOD_RETVAL_UTF8(source, (UChar *)ufield, ilen, 0); break; case URES_BINARY: bfield = ures_getBinary( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) ); INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve binary value"); ZVAL_STRINGL( return_value, (char *) bfield, ilen ); break; case URES_INT: lfield = ures_getInt( source->child, &INTL_DATA_ERROR_CODE(source) ); INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve integer value"); ZVAL_LONG( return_value, lfield ); break; case URES_INT_VECTOR: vfield = ures_getIntVector( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) ); INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve vector value"); array_init( return_value ); for (i=0; i<ilen; i++) { add_next_index_long( return_value, vfield[i] ); } break; case URES_ARRAY: case URES_TABLE: object_init_ex( return_value, ResourceBundle_ce_ptr ); newrb = Z_INTL_RESOURCEBUNDLE_P(return_value); newrb->me = source->child; source->child = NULL; intl_errors_reset(INTL_DATA_ERROR_P(source)); break; default: intl_errors_set(INTL_DATA_ERROR_P(source), U_ILLEGAL_ARGUMENT_ERROR, "Unknown resource type", 0); RETURN_FALSE; break; } }
/* {{{ php_converter_throw_failure */ static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error TSRMLS_DC, const char *format, ...) { intl_error *err = objval ? &(objval->error) : NULL; char message[1024]; va_list vargs; va_start(vargs, format); vsnprintf(message, sizeof(message), format, vargs); va_end(vargs); intl_errors_set(err, error, message, 1 TSRMLS_CC); }
inline BreakIterator *_breakiter_prolog(zend_object_iterator *iter) { BreakIterator_object *bio; bio = Z_INTL_BREAKITERATOR_P(&iter->data); intl_errors_reset(BREAKITER_ERROR_P(bio)); if (bio->biter == NULL) { intl_errors_set(BREAKITER_ERROR_P(bio), U_INVALID_STATE_ERROR, "The BreakIterator object backing the PHP iterator is not " "properly constructed", 0); } return bio->biter; }
/* {{{ resourcebundle_array_fetch */ static void resourcebundle_array_fetch(zval *object, zval *offset, zval *return_value, int fallback) { int32_t meindex = 0; char * mekey = NULL; zend_bool is_numeric = 0; char *pbuf; ResourceBundle_object *rb; intl_error_reset( NULL ); RESOURCEBUNDLE_METHOD_FETCH_OBJECT; if(Z_TYPE_P(offset) == IS_LONG) { is_numeric = 1; meindex = (int32_t)Z_LVAL_P(offset); rb->child = ures_getByIndex( rb->me, meindex, rb->child, &INTL_DATA_ERROR_CODE(rb) ); } else if(Z_TYPE_P(offset) == IS_STRING) { mekey = Z_STRVAL_P(offset); rb->child = ures_getByKey(rb->me, mekey, rb->child, &INTL_DATA_ERROR_CODE(rb) ); } else { intl_errors_set(INTL_DATA_ERROR_P(rb), U_ILLEGAL_ARGUMENT_ERROR, "resourcebundle_get: index should be integer or string", 0); RETURN_NULL(); } intl_error_set_code( NULL, INTL_DATA_ERROR_CODE(rb) ); if (U_FAILURE(INTL_DATA_ERROR_CODE(rb))) { if (is_numeric) { spprintf( &pbuf, 0, "Cannot load resource element %d", meindex ); } else { spprintf( &pbuf, 0, "Cannot load resource element '%s'", mekey ); } intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 ); efree(pbuf); RETURN_NULL(); } if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) { UErrorCode icuerror; const char * locale = ures_getLocaleByType( rb->me, ULOC_ACTUAL_LOCALE, &icuerror ); if (is_numeric) { spprintf( &pbuf, 0, "Cannot load element %d without fallback from to %s", meindex, locale ); } else { spprintf( &pbuf, 0, "Cannot load element '%s' without fallback from to %s", mekey, locale ); } intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 ); efree(pbuf); RETURN_NULL(); } resourcebundle_extract_value( return_value, rb ); }
/* {{{ resourcebundle_array_count */ int resourcebundle_array_count(zend_object *object, zend_long *count) { ResourceBundle_object *rb = php_intl_resourcebundle_fetch_object(object); if (rb->me == NULL) { intl_errors_set(&rb->error, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed ResourceBundle", 0); return 0; } *count = ures_getSize( rb->me ); return SUCCESS; }
/* {{{ resourcebundle_array_count */ int resourcebundle_array_count(zval *object, zend_long *count) { ResourceBundle_object *rb; RESOURCEBUNDLE_METHOD_FETCH_OBJECT_NO_CHECK; if (rb->me == NULL) { intl_errors_set(&rb->error, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed ResourceBundle", 0); return 0; } *count = ures_getSize( rb->me ); return SUCCESS; }
static void umsg_set_timezone(MessageFormatter_object *mfo, intl_error& err) { MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; TimeZone *used_tz = NULL; const Format **formats; int32_t count; /* Unfortanely, this cannot change the time zone for arguments that * appear inside complex formats because ::getFormats() returns NULL * for all uncached formats, which is the case for complex formats * unless they were set via one of the ::setFormat() methods */ if (mfo->mf_data.tz_set) { return; /* already done */ } formats = mf->getFormats(count); if (formats == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Out of memory retrieving subformats", 0); } for (int i = 0; U_SUCCESS(err.code) && i < count; i++) { DateFormat* df = dynamic_cast<DateFormat*>( const_cast<Format *>(formats[i])); if (df == NULL) { continue; } if (used_tz == NULL) { zval nullzv, *zvptr = &nullzv; ZVAL_NULL(zvptr); used_tz = timezone_process_timezone_argument(zvptr, &err, "msgfmt_format"); if (used_tz == NULL) { continue; } } df->setTimeZone(*used_tz); } if (U_SUCCESS(err.code)) { mfo->mf_data.tz_set = 1; } }
/* {{{ * Internal function which sets UCalendar from the passed array and retrieves timestamp */ static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable *hash_arr) { int32_t year, month, hour, minute, second, mday; UCalendar *pcal; UDate result; intl_error *err = &dfo->datef_data.error; #define INTL_GET_ELEM(elem) \ internal_get_arr_ele(dfo, hash_arr, (elem), err) /* Fetch values from the incoming array */ year = INTL_GET_ELEM(CALENDAR_YEAR) + 1900; /* tm_year is years since 1900 */ /* Month in ICU and PHP starts from January =0 */ month = INTL_GET_ELEM(CALENDAR_MON); hour = INTL_GET_ELEM(CALENDAR_HOUR); minute = INTL_GET_ELEM(CALENDAR_MIN); second = INTL_GET_ELEM(CALENDAR_SEC); /* For the ucal_setDateTime() function, this is the 'date' value */ mday = INTL_GET_ELEM(CALENDAR_MDAY); #undef INTL_GET_ELEM pcal = ucal_clone(udat_getCalendar(DATE_FORMAT_OBJECT(dfo)), &INTL_DATA_ERROR_CODE(dfo)); if (INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR) { intl_errors_set(err, INTL_DATA_ERROR_CODE(dfo), "datefmt_format: " "error cloning calendar", 0); return 0; } /* set the incoming values for the calendar */ ucal_setDateTime(pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo)); /* actually, ucal_setDateTime cannot fail */ /* Fetch the timestamp from the UCalendar */ result = ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo)); ucal_close(pcal); return result; }
static HashTable *umsg_get_types(MessageFormatter_object *mfo, intl_error& err) { MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; #ifdef HAS_MESSAGE_PATTERN const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf); return umsg_parse_format(mfo, mp, err); #else if (mf->usesNamedArguments()) { intl_errors_set(&err, U_UNSUPPORTED_ERROR, "This extension supports named arguments only on ICU 4.8+", 0); return NULL; } return umsg_get_numeric_types(mfo, err); #endif }
static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo, intl_error& err) { HashTable *ret; int32_t parts_count; if (U_FAILURE(err.code)) { return NULL; } if (mfo->mf_data.arg_types) { /* already cached */ return mfo->mf_data.arg_types; } const Formattable::Type *types = MessageFormatAdapter::getArgTypeList( *(MessageFormat*)mfo->mf_data.umsgf, parts_count); /* Hash table will store Formattable::Type objects directly, * so no need for destructor */ ALLOC_HASHTABLE(ret); zend_hash_init(ret, parts_count, NULL, arg_types_dtor, 0); for (int i = 0; i < parts_count; i++) { const Formattable::Type t = types[i]; if (zend_hash_index_update_mem(ret, (zend_ulong)i, (void*)&t, sizeof(t)) == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Write to argument types hash table failed", 0); break; } } if (U_FAILURE(err.code)) { zend_hash_destroy(ret); efree(ret); return NULL; } mfo->mf_data.arg_types = ret; return ret; }
U_CFUNC PHP_FUNCTION(rbbi_get_rule_status_vec) { BREAKITER_METHOD_INIT_VARS; object = getThis(); if (zend_parse_parameters_none() == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "rbbi_get_rule_status_vec: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } BREAKITER_METHOD_FETCH_OBJECT; int32_t num_rules = fetch_rbbi(bio)->getRuleStatusVec(NULL, 0, BREAKITER_ERROR_CODE(bio)); if (BREAKITER_ERROR_CODE(bio) == U_BUFFER_OVERFLOW_ERROR) { BREAKITER_ERROR_CODE(bio) = U_ZERO_ERROR; } else { // should not happen INTL_METHOD_CHECK_STATUS(bio, "rbbi_get_rule_status_vec: failed " " determining the number of status values"); } int32_t *rules = new int32_t[num_rules]; num_rules = fetch_rbbi(bio)->getRuleStatusVec(rules, num_rules, BREAKITER_ERROR_CODE(bio)); if (U_FAILURE(BREAKITER_ERROR_CODE(bio))) { delete[] rules; intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), "rbbi_get_rule_status_vec: failed obtaining the status values", 0 TSRMLS_CC); RETURN_FALSE; } array_init_size(return_value, num_rules); for (int32_t i = 0; i < num_rules; i++) { add_next_index_long(return_value, rules[i]); } delete[] rules; }
U_CFUNC PHP_FUNCTION(intlcal_get_time_zone) { CALENDAR_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, Calendar_ce_ptr) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_get_time_zone: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } CALENDAR_METHOD_FETCH_OBJECT; TimeZone *tz = co->ucal->getTimeZone().clone(); if (tz == NULL) { intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR, "intlcal_get_time_zone: could not clone TimeZone", 0 TSRMLS_CC); RETURN_FALSE; } timezone_object_construct(tz, return_value, 1 TSRMLS_CC); }
U_CFUNC PHP_FUNCTION(intltz_has_same_rules) { zval *other_object; TimeZone_object *other_to; TIMEZONE_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, TimeZone_ce_ptr, &other_object, TimeZone_ce_ptr) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intltz_has_same_rules: bad arguments", 0); RETURN_FALSE; } TIMEZONE_METHOD_FETCH_OBJECT; other_to = Z_INTL_TIMEZONE_P(other_object); if (other_to->utimezone == NULL) { intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR, "intltz_has_same_rules: The second IntlTimeZone is unconstructed", 0); RETURN_FALSE; } RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone)); }
/* {{{ timezone_process_timezone_argument * TimeZone argument processor. outside_error may be NULL (for static functions/constructors) */ U_CFUNC TimeZone *timezone_process_timezone_argument(zval *zv_timezone, intl_error *outside_error, const char *func) { zval local_zv_tz; char *message = NULL; TimeZone *timeZone; if (zv_timezone == NULL || Z_TYPE_P(zv_timezone) == IS_NULL) { timelib_tzinfo *tzinfo = get_timezone_info(); ZVAL_STRING(&local_zv_tz, tzinfo->name); zv_timezone = &local_zv_tz; } else { ZVAL_NULL(&local_zv_tz); } if (Z_TYPE_P(zv_timezone) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv_timezone), TimeZone_ce_ptr)) { TimeZone_object *to = Z_INTL_TIMEZONE_P(zv_timezone); if (to->utimezone == NULL) { spprintf(&message, 0, "%s: passed IntlTimeZone is not " "properly constructed", func); if (message) { intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); efree(message); } zval_dtor(&local_zv_tz); return NULL; } timeZone = to->utimezone->clone(); if (timeZone == NULL) { spprintf(&message, 0, "%s: could not clone TimeZone", func); if (message) { intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1); efree(message); } zval_dtor(&local_zv_tz); return NULL; } } else if (Z_TYPE_P(zv_timezone) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv_timezone), php_date_get_timezone_ce())) { php_timezone_obj *tzobj = Z_PHPTIMEZONE_P(zv_timezone); zval_dtor(&local_zv_tz); return timezone_convert_datetimezone(tzobj->type, tzobj, 0, outside_error, func); } else { UnicodeString id, gottenId; UErrorCode status = U_ZERO_ERROR; /* outside_error may be NULL */ convert_to_string_ex(zv_timezone); if (intl_stringFromChar(id, Z_STRVAL_P(zv_timezone), Z_STRLEN_P(zv_timezone), &status) == FAILURE) { spprintf(&message, 0, "%s: Time zone identifier given is not a " "valid UTF-8 string", func); if (message) { intl_errors_set(outside_error, status, message, 1); efree(message); } zval_dtor(&local_zv_tz); return NULL; } timeZone = TimeZone::createTimeZone(id); if (timeZone == NULL) { spprintf(&message, 0, "%s: could not create time zone", func); if (message) { intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1); efree(message); } zval_dtor(&local_zv_tz); return NULL; } if (timeZone->getID(gottenId) != id) { spprintf(&message, 0, "%s: no such time zone: '%s'", func, Z_STRVAL_P(zv_timezone)); if (message) { intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); efree(message); } zval_dtor(&local_zv_tz); delete timeZone; return NULL; } } zval_dtor(&local_zv_tz); return timeZone; }
/* {{{ */ static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS) { char* locale; int locale_len = 0; zval* object; long date_type = 0; long time_type = 0; long calendar = UCAL_GREGORIAN; char* timezone_str = NULL; int timezone_str_len = 0; char* pattern_str = NULL; int pattern_str_len = 0; UChar* svalue = NULL; /* UTF-16 pattern_str */ int slength = 0; UChar* timezone_utf16 = NULL; /* UTF-16 timezone_str */ int timezone_utf16_len = 0; UCalendar ucal_obj = NULL; IntlDateFormatter_object* dfo; intl_error_reset( NULL TSRMLS_CC ); object = return_value; /* Parse parameters. */ if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|sls", &locale, &locale_len, &date_type, &time_type, &timezone_str, &timezone_str_len, &calendar,&pattern_str, &pattern_str_len ) == FAILURE ) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: unable to parse input parameters", 0 TSRMLS_CC ); zval_dtor(return_value); RETURN_NULL(); } INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); if (calendar != UCAL_TRADITIONAL && calendar != UCAL_GREGORIAN) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: " "invalid value for calendar type; it must be one of " "IntlDateFormatter::TRADITIONAL (locale's default calendar) " "or IntlDateFormatter::GREGORIAN", 0 TSRMLS_CC); goto error; } DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK; if (DATE_FORMAT_OBJECT(dfo) != NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: cannot call constructor twice", 0 TSRMLS_CC); return; } /* Convert pattern (if specified) to UTF-16. */ if( pattern_str && pattern_str_len>0 ){ intl_convert_utf8_to_utf16(&svalue, &slength, pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { /* object construction -> only set global error */ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " "error converting pattern to UTF-16", 0 TSRMLS_CC); goto error; } } /* resources allocated from now on */ /* Convert pattern (if specified) to UTF-16. */ if( timezone_str && timezone_str_len >0 ){ intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(dfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " "error converting timezone_str to UTF-16", 0 TSRMLS_CC); goto error; } } if(locale_len == 0) { locale = INTL_G(default_locale); } if( pattern_str && pattern_str_len>0 ){ DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } else { DATE_FORMAT_OBJECT(dfo) = udat_open(time_type, date_type, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { if (calendar != UCAL_TRADITIONAL) { ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale, calendar, &INTL_DATA_ERROR_CODE(dfo)); if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { udat_setCalendar(DATE_FORMAT_OBJECT(dfo), ucal_obj); ucal_close(ucal_obj); } else { intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create" ": error opening calendar", 0 TSRMLS_CC); goto error; } } } else { intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date " "formatter creation failed", 0 TSRMLS_CC); goto error; } /* Set the class variables */ dfo->date_type = date_type; dfo->time_type = time_type; dfo->calendar = calendar; if( timezone_str && timezone_str_len > 0){ dfo->timezone_id = estrndup( timezone_str, timezone_str_len); } error: if (svalue) { efree(svalue); } if (timezone_utf16) { efree(timezone_utf16); } if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) { /* free_object handles partially constructed instances fine */ zval_dtor(return_value); RETVAL_NULL(); } }
U_CFUNC PHP_FUNCTION(intlcal_to_date_time) { zval retval; CALENDAR_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, Calendar_ce_ptr) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; } CALENDAR_METHOD_FETCH_OBJECT; /* There are no exported functions in ext/date to this * in a more native fashion */ double date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.; int64_t ts; char ts_str[sizeof("@-9223372036854775808")]; int ts_str_len; zval ts_tmp, ts_zval, tmp; INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed"); if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) { intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: The calendar date is out of the " "range for a 64-bit integer", 0 TSRMLS_CC); RETURN_FALSE; } ZVAL_UNDEF(&retval); ts = (int64_t)date; ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts); ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len); /* Now get the time zone */ const TimeZone& tz = co->ucal->getTimeZone(); zval *timezone_zval = timezone_convert_to_datetimezone( &tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time", &tmp TSRMLS_CC); if (timezone_zval == NULL) { RETURN_FALSE; } /* resources allocated from now on */ /* Finally, instantiate object and call constructor */ object_init_ex(return_value, php_date_get_date_ce()); zend_call_method_with_2_params(return_value, NULL, NULL, "__construct", NULL, &ts_zval, timezone_zval); if (EG(exception)) { intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: DateTime constructor has thrown exception", 1 TSRMLS_CC); zend_object_store_ctor_failed(Z_OBJ_P(return_value) TSRMLS_CC); zval_ptr_dtor(return_value); zval_ptr_dtor(&ts_zval); RETVAL_FALSE; goto error; } zval_ptr_dtor(&ts_zval); /* due to bug #40743, we have to set the time zone again */ zend_call_method_with_1_params(return_value, NULL, NULL, "settimezone", &retval, timezone_zval); if (Z_ISUNDEF(retval) || Z_TYPE(retval) == IS_FALSE) { intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: call to DateTime::setTimeZone has failed", 1 TSRMLS_CC); zval_ptr_dtor(return_value); RETVAL_FALSE; goto error; } error: zval_ptr_dtor(timezone_zval); zval_ptr_dtor(&retval); }
/* {{{ timezone_convert_to_datetimezone * Convert from TimeZone to DateTimeZone object */ U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, intl_error *outside_error, const char *func, zval *ret) { UnicodeString id; char *message = NULL; php_timezone_obj *tzobj; zval arg; timeZone->getID(id); if (id.isBogus()) { spprintf(&message, 0, "%s: could not obtain TimeZone id", func); intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); goto error; } object_init_ex(ret, php_date_get_timezone_ce()); tzobj = Z_PHPTIMEZONE_P(ret); if (id.compare(0, 3, UnicodeString("GMT", sizeof("GMT")-1, US_INV)) == 0) { /* The DateTimeZone constructor doesn't support offset time zones, * so we must mess with DateTimeZone structure ourselves */ tzobj->initialized = 1; tzobj->type = TIMELIB_ZONETYPE_OFFSET; //convert offset from milliseconds to minutes tzobj->tzi.utc_offset = -1 * timeZone->getRawOffset() / (60 * 1000); } else { char *str; size_t str_len; /* Call the constructor! */ if (intl_charFromString(id, &str, &str_len, &INTL_ERROR_CODE(*outside_error)) == FAILURE) { spprintf(&message, 0, "%s: could not convert id to UTF-8", func); intl_errors_set(outside_error, INTL_ERROR_CODE(*outside_error), message, 1); goto error; } ZVAL_STRINGL(&arg, str, str_len); //??? efree(str); zend_call_method_with_1_params(ret, NULL, NULL, "__construct", NULL, &arg); if (EG(exception)) { spprintf(&message, 0, "%s: DateTimeZone constructor threw exception", func); intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); zend_object_store_ctor_failed(Z_OBJ_P(ret)); zval_ptr_dtor(&arg); goto error; } zval_ptr_dtor(&arg); } if (0) { error: if (ret) { zval_ptr_dtor(ret); } ret = NULL; } if (message) { efree(message); } return ret; }
static HashTable *umsg_parse_format(MessageFormatter_object *mfo, const MessagePattern& mp, intl_error& err) { HashTable *ret; int32_t parts_count; if (U_FAILURE(err.code)) { return NULL; } if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) { return umsg_get_numeric_types(mfo, err); } if (mfo->mf_data.arg_types) { /* already cached */ return mfo->mf_data.arg_types; } /* Hash table will store Formattable::Type objects directly, * so no need for destructor */ ALLOC_HASHTABLE(ret); zend_hash_init(ret, 32, NULL, arg_types_dtor, 0); parts_count = mp.countParts(); // See MessageFormat::cacheExplicitFormats() /* * Looking through the pattern, go to each arg_start part type. * The arg-typeof that tells us the argument type (simple, complicated) * then the next part is either the arg_name or arg number * and then if it's simple after that there could be a part-type=arg-type * while substring will tell us number, spellout, etc. * If the next thing isn't an arg-type then assume string. */ /* The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT * which we need not examine. */ for (int32_t i = 0; i < parts_count - 2 && U_SUCCESS(err.code); i++) { MessagePattern::Part p = mp.getPart(i); if (p.getType() != UMSGPAT_PART_TYPE_ARG_START) { continue; } MessagePattern::Part name_part = mp.getPart(++i); /* Getting name, advancing i */ Formattable::Type type, *storedType; if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) { UnicodeString argName = mp.getSubstring(name_part); if ((storedType = (Formattable::Type*)zend_hash_str_find_ptr(ret, (char*)argName.getBuffer(), argName.length())) == NULL) { /* not found already; create new entry in HT */ Formattable::Type bogusType = Formattable::kObject; if ((storedType = (Formattable::Type*)zend_hash_str_update_mem(ret, (char*)argName.getBuffer(), argName.length(), (void*)&bogusType, sizeof(bogusType))) == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Write to argument types hash table failed", 0); continue; } } } else if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { int32_t argNumber = name_part.getValue(); if (argNumber < 0) { intl_errors_set(&err, U_INVALID_FORMAT_ERROR, "Found part with negative number", 0); continue; } if ((storedType = (Formattable::Type*)zend_hash_index_find_ptr(ret, (zend_ulong)argNumber)) == NULL) { /* not found already; create new entry in HT */ Formattable::Type bogusType = Formattable::kObject; if ((storedType = (Formattable::Type*)zend_hash_index_update_mem(ret, (zend_ulong)argNumber, (void*)&bogusType, sizeof(bogusType))) == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Write to argument types hash table failed", 0); continue; } } } else { intl_errors_set(&err, U_INVALID_FORMAT_ERROR, "Invalid part type encountered", 0); continue; } UMessagePatternArgType argType = p.getArgType(); /* No type specified, treat it as a string */ if (argType == UMSGPAT_ARG_TYPE_NONE) { type = Formattable::kString; } else { /* Some type was specified, might be simple or complicated */ if (argType == UMSGPAT_ARG_TYPE_SIMPLE) { /* For a SIMPLE arg, after the name part, there should be * an ARG_TYPE part whose string value tells us what to do */ MessagePattern::Part type_part = mp.getPart(++i); /* Getting type, advancing i */ if (type_part.getType() == UMSGPAT_PART_TYPE_ARG_TYPE) { UnicodeString typeString = mp.getSubstring(type_part); /* This is all based on the rules in the docs for MessageFormat * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html */ if (typeString == "number") { MessagePattern::Part style_part = mp.getPart(i + 1); /* Not advancing i */ if (style_part.getType() == UMSGPAT_PART_TYPE_ARG_STYLE) { UnicodeString styleString = mp.getSubstring(style_part); if (styleString == "integer") { type = Formattable::kInt64; } else if (styleString == "currency") { type = Formattable::kDouble; } else if (styleString == "percent") { type = Formattable::kDouble; } else { /* some style invalid/unknown to us */ type = Formattable::kDouble; } } else { // if missing style, part, make it a double type = Formattable::kDouble; } } else if ((typeString == "date") || (typeString == "time")) { type = Formattable::kDate; } else if ((typeString == "spellout") || (typeString == "ordinal") || (typeString == "duration")) { type = Formattable::kDouble; } } else { /* If there's no UMSGPAT_PART_TYPE_ARG_TYPE right after a * UMSGPAT_ARG_TYPE_SIMPLE argument, then the pattern * is broken. */ intl_errors_set(&err, U_PARSE_ERROR, "Expected UMSGPAT_PART_TYPE_ARG_TYPE part following " "UMSGPAT_ARG_TYPE_SIMPLE part", 0); continue; } } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) { type = Formattable::kDouble; } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) { type = Formattable::kDouble; } else if (argType == UMSGPAT_ARG_TYPE_SELECT) { type = Formattable::kString; } else { type = Formattable::kString; } } /* was type specified? */ /* We found a different type for the same arg! */ if (*storedType != Formattable::kObject && *storedType != type) { intl_errors_set(&err, U_ARGUMENT_TYPE_MISMATCH, "Inconsistent types declared for an argument", 0); continue; } *storedType = type; } /* visiting each part */ if (U_FAILURE(err.code)) { zend_hash_destroy(ret); efree(ret); return NULL; } mfo->mf_data.arg_types = ret; return ret; }
/* {{{ */ static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS) { zval *object; const char *locale_str; size_t locale_len = 0; Locale locale; zend_long date_type = 0; zend_long time_type = 0; zval *calendar_zv = NULL; Calendar *calendar = NULL; zend_long calendar_type; bool calendar_owned; zval *timezone_zv = NULL; TimeZone *timezone = NULL; bool explicit_tz; char* pattern_str = NULL; size_t pattern_str_len = 0; UChar* svalue = NULL; /* UTF-16 pattern_str */ int32_t slength = 0; IntlDateFormatter_object* dfo; intl_error_reset(NULL); object = return_value; /* Parse parameters. */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|zzs", &locale_str, &locale_len, &date_type, &time_type, &timezone_zv, &calendar_zv, &pattern_str, &pattern_str_len) == FAILURE) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: " "unable to parse input parameters", 0); Z_OBJ_P(return_value) = NULL; return; } INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); if (locale_len == 0) { locale_str = intl_locale_get_default(); } locale = Locale::createFromName(locale_str); DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK; if (DATE_FORMAT_OBJECT(dfo) != NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: cannot call constructor twice", 0); return; } /* process calendar */ if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create", INTL_DATA_ERROR_P(dfo), calendar, calendar_type, calendar_owned) == FAILURE) { goto error; } /* process timezone */ explicit_tz = timezone_zv != NULL && Z_TYPE_P(timezone_zv) != IS_NULL; if (explicit_tz || calendar_owned ) { //we have an explicit time zone or a non-object calendar timezone = timezone_process_timezone_argument(timezone_zv, INTL_DATA_ERROR_P(dfo), "datefmt_create"); if (timezone == NULL) { goto error; } } /* Convert pattern (if specified) to UTF-16. */ if (pattern_str && pattern_str_len > 0) { intl_convert_utf8_to_utf16(&svalue, &slength, pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { /* object construction -> only set global error */ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " "error converting pattern to UTF-16", 0); goto error; } } if (pattern_str && pattern_str_len > 0) { DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale_str, NULL, 0, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } else { DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type, (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { DateFormat *df = (DateFormat*)DATE_FORMAT_OBJECT(dfo); if (calendar_owned) { df->adoptCalendar(calendar); calendar_owned = false; } else { df->setCalendar(*calendar); } if (timezone != NULL) { df->adoptTimeZone(timezone); } } else { intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date " "formatter creation failed", 0); goto error; } /* Set the class variables */ dfo->date_type = date_type; dfo->time_type = time_type; dfo->calendar = calendar_type; dfo->requested_locale = estrdup(locale_str); error: if (svalue) { efree(svalue); } if (timezone != NULL && DATE_FORMAT_OBJECT(dfo) == NULL) { delete timezone; } if (calendar != NULL && calendar_owned) { delete calendar; } if (U_FAILURE(intl_error_get_code(NULL))) { /* free_object handles partially constructed instances fine */ Z_OBJ_P(return_value) = NULL; } }
U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, HashTable *args, UChar **formatted, int32_t *formatted_len) { int arg_count = zend_hash_num_elements(args); std::vector<Formattable> fargs; std::vector<UnicodeString> farg_names; MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; HashTable *types; intl_error& err = INTL_DATA_ERROR(mfo); if (U_FAILURE(err.code)) { return; } types = umsg_get_types(mfo, err); umsg_set_timezone(mfo, err); fargs.resize(arg_count); farg_names.resize(arg_count); int argNum = 0; zval *elem; // Key related variables zend_string *str_index; zend_ulong num_index; ZEND_HASH_FOREACH_KEY_VAL(args, num_index, str_index, elem) { Formattable& formattable = fargs[argNum]; UnicodeString& key = farg_names[argNum]; Formattable::Type argType = Formattable::kObject, //unknown *storedArgType = NULL; if (!U_SUCCESS(err.code)) { break; } /* Process key and retrieve type */ if (str_index == NULL) { /* includes case where index < 0 because it's exposed as unsigned */ if (num_index > (zend_ulong)INT32_MAX) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found negative or too large array key", 0); continue; } UChar temp[16]; int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index); key.append(temp, len); storedArgType = (Formattable::Type*)zend_hash_index_find_ptr(types, (zend_ulong)num_index); } else { //string; assumed to be in UTF-8 intl_stringFromChar(key, ZSTR_VAL(str_index), ZSTR_LEN(str_index), &err.code); if (U_FAILURE(err.code)) { char *message; spprintf(&message, 0, "Invalid UTF-8 data in argument key: '%s'", ZSTR_VAL(str_index)); intl_errors_set(&err, err.code, message, 1); efree(message); continue; } storedArgType = (Formattable::Type*)zend_hash_str_find_ptr(types, (char*)key.getBuffer(), key.length()); } if (storedArgType != NULL) { argType = *storedArgType; } /* Convert zval to formattable according to message format type * or (as a fallback) the zval type */ if (argType != Formattable::kObject) { switch (argType) { case Formattable::kString: { string_arg: /* This implicitly converts objects * Note that our vectors will leak if object conversion fails * and PHP ends up with a fatal error and calls longjmp * as a result of that. */ convert_to_string_ex(elem); UnicodeString *text = new UnicodeString(); intl_stringFromChar(*text, Z_STRVAL_P(elem), Z_STRLEN_P(elem), &err.code); if (U_FAILURE(err.code)) { char *message; spprintf(&message, 0, "Invalid UTF-8 data in string argument: " "'%s'", Z_STRVAL_P(elem)); intl_errors_set(&err, err.code, message, 1); efree(message); delete text; continue; } formattable.adoptString(text); break; } case Formattable::kDouble: { double d; if (Z_TYPE_P(elem) == IS_DOUBLE) { d = Z_DVAL_P(elem); } else if (Z_TYPE_P(elem) == IS_LONG) { d = (double)Z_LVAL_P(elem); } else { SEPARATE_ZVAL_IF_NOT_REF(elem); convert_scalar_to_number(elem); d = (Z_TYPE_P(elem) == IS_DOUBLE) ? Z_DVAL_P(elem) : (double)Z_LVAL_P(elem); } formattable.setDouble(d); break; } case Formattable::kLong: { int32_t tInt32 = 0; retry_klong: if (Z_TYPE_P(elem) == IS_DOUBLE) { if (Z_DVAL_P(elem) > (double)INT32_MAX || Z_DVAL_P(elem) < (double)INT32_MIN) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP float with absolute value too large for " "32 bit integer argument", 0); } else { tInt32 = (int32_t)Z_DVAL_P(elem); } } else if (Z_TYPE_P(elem) == IS_LONG) { if (Z_LVAL_P(elem) > INT32_MAX || Z_LVAL_P(elem) < INT32_MIN) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP integer with absolute value too large " "for 32 bit integer argument", 0); } else { tInt32 = (int32_t)Z_LVAL_P(elem); } } else { SEPARATE_ZVAL_IF_NOT_REF(elem); convert_scalar_to_number(elem); goto retry_klong; } formattable.setLong(tInt32); break; } case Formattable::kInt64: { int64_t tInt64 = 0; retry_kint64: if (Z_TYPE_P(elem) == IS_DOUBLE) { if (Z_DVAL_P(elem) > (double)U_INT64_MAX || Z_DVAL_P(elem) < (double)U_INT64_MIN) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP float with absolute value too large for " "64 bit integer argument", 0); } else { tInt64 = (int64_t)Z_DVAL_P(elem); } } else if (Z_TYPE_P(elem) == IS_LONG) { /* assume long is not wider than 64 bits */ tInt64 = (int64_t)Z_LVAL_P(elem); } else { SEPARATE_ZVAL_IF_NOT_REF(elem); convert_scalar_to_number(elem); goto retry_kint64; } formattable.setInt64(tInt64); break; } case Formattable::kDate: { double dd = intl_zval_to_millis(elem, &err, "msgfmt_format"); if (U_FAILURE(err.code)) { char *message; zend_string *u8key; UErrorCode status = UErrorCode(); u8key = intl_charFromString(key, &status); if (u8key) { spprintf(&message, 0, "The argument for key '%s' " "cannot be used as a date or time", ZSTR_VAL(u8key)); intl_errors_set(&err, err.code, message, 1); zend_string_release(u8key); efree(message); } continue; } formattable.setDate(dd); break; } default: intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found unsupported argument type", 0); break; } } else { /* We couldn't find any information about the argument in the pattern, this * means it's an extra argument. So convert it to a number if it's a number or * bool or null and to a string if it's anything else except arrays . */ switch (Z_TYPE_P(elem)) { case IS_DOUBLE: formattable.setDouble(Z_DVAL_P(elem)); break; case IS_TRUE: case IS_FALSE: convert_to_long_ex(elem); /* Intentional fallthrough */ case IS_LONG: formattable.setInt64((int64_t)Z_LVAL_P(elem)); break; case IS_NULL: formattable.setInt64((int64_t)0); break; case IS_STRING: case IS_OBJECT: goto string_arg; default: { char *message; zend_string *u8key; UErrorCode status = UErrorCode(); u8key = intl_charFromString(key, &status); if (u8key) { spprintf(&message, 0, "No strategy to convert the " "value given for the argument with key '%s' " "is available", ZSTR_VAL(u8key)); intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, message, 1); zend_string_release(u8key); efree(message); } } } } argNum++; } ZEND_HASH_FOREACH_END(); // visiting each argument