From: Andrei Zmievski Date: Thu, 11 Aug 2005 23:35:03 +0000 (+0000) Subject: Unicode support X-Git-Tag: PRE_NEW_OCI8_EXTENSION~337 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b80cb7bd2f721dad13a97a1300c6dc56934daaf7;p=php Unicode support --- diff --git a/Zend/Makefile.am b/Zend/Makefile.am index 42ae4d5424..93229c280d 100644 --- a/Zend/Makefile.am +++ b/Zend/Makefile.am @@ -17,7 +17,7 @@ libZend_la_SOURCES=\ zend_objects_API.c zend_ts_hash.c zend_stream.c zend_mm.c \ zend_default_classes.c zend_reflection_api.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ - zend_strtod.c zend_multibyte.c + zend_strtod.c zend_multibyte.c zend_strtod.c zend_strtol.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index b1d4995988..ea3bf18ee6 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -160,12 +160,15 @@ AC_ARG_ENABLE(memory-limit, ZEND_MEMORY_LIMIT=no ]) -AC_ARG_ENABLE(zend-multibyte, -[ --enable-zend-multibyte Compile with zend multibyte support], [ - ZEND_MULTIBYTE=$enableval -],[ - ZEND_MULTIBYTE=no -]) +dnl AC_ARG_ENABLE(zend-multibyte, +dnl [ --enable-zend-multibyte Compile with zend multibyte support], [ +dnl ZEND_MULTIBYTE=$enableval +dnl ],[ +dnl ZEND_MULTIBYTE=no +dnl ]) + +dnl Unicode PHP doesn't need ZEND_MULTIBYTE +ZEND_MULTIBYTE=no AC_MSG_CHECKING([virtual machine dispatch method]) AC_MSG_RESULT($PHP_ZEND_VM) diff --git a/Zend/flex.skl b/Zend/flex.skl index 9a7c5cf873..060a34bbee 100644 --- a/Zend/flex.skl +++ b/Zend/flex.skl @@ -440,18 +440,6 @@ YY_MALLOC_DECL #define ECHO /* There is no output */ #endif -#ifdef ZEND_MULTIBYTE -# define YY_INPUT(buf, result, max_size) \ - if ( ((result = zend_multibyte_yyinput(yyin, buf, max_size TSRMLS_CC)) == 0) \ - && zend_stream_ferror( yyin TSRMLS_CC) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#else -# define YY_INPUT(buf, result, max_size) \ - if ( ((result = zend_stream_read(yyin, buf, max_size TSRMLS_CC)) == 0) \ - && zend_stream_ferror( yyin TSRMLS_CC) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - #ifndef ECHO %- Standard (non-C++) definition /* This used to be an fputs(), but since the string might contain NUL's, diff --git a/Zend/zend.c b/Zend/zend.c index 52ee10b419..4604ace376 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -28,17 +28,9 @@ #include "zend_exceptions.h" #include "zend_builtin_functions.h" #include "zend_ini.h" - -#ifdef ZTS -# define GLOBAL_FUNCTION_TABLE global_function_table -# define GLOBAL_CLASS_TABLE global_class_table -# define GLOBAL_CONSTANTS_TABLE global_constants_table -# define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table -#else -# define GLOBAL_FUNCTION_TABLE CG(function_table) -# define GLOBAL_CLASS_TABLE CG(class_table) -# define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) -#endif +#include "zend_unicode.h" +#include "zend_interfaces.h" +#include "zend_reflection_api.h" #if defined(ZEND_WIN32) && ZEND_DEBUG BOOL WINAPI IsDebuggerPresent(VOID); @@ -74,9 +66,145 @@ static ZEND_INI_MH(OnUpdateErrorReporting) } +static ZEND_INI_MH(OnUpdateEncoding) +{ + UConverter **converter; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base; + + base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + converter = (UConverter **) (base+(size_t) mh_arg1); + + if (!new_value && converter == &UG(fallback_encoding_conv)) { + new_value = "UTF-8"; + } + + if (new_value) { + if (zend_set_converter_encoding(converter, new_value) == FAILURE) { + zend_error(E_CORE_ERROR, "Unrecognized encoding '%s' used for %s", new_value ? new_value : "null", entry->name); + return FAILURE; + } + } else { + if (*converter) { + ucnv_close(*converter); + } + *converter = NULL; + } + if (*converter) { + zend_set_converter_error_mode(*converter, UG(from_u_error_mode)); + zend_set_converter_subst_char(*converter, UG(subst_char), UG(subst_char_len)); + } + + return SUCCESS; +} + +#if 0 +static ZEND_INI_MH(OnUpdateErrorMode) +{ + uint8_t *error_mode; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base; + + base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + error_mode = (uint8_t *) (base+(size_t) mh_arg1); + + if (new_value) { + if (!strcasecmp(new_value, "stop")) { + *error_mode = ZEND_FROM_U_ERROR_STOP; + } else if (!strcasecmp(new_value, "skip")) { + *error_mode = ZEND_FROM_U_ERROR_SKIP; + } else if (!strcasecmp(new_value, "escape")) { + *error_mode = ZEND_FROM_U_ERROR_ESCAPE; + } else if (!strcasecmp(new_value, "substitute")) { + *error_mode = ZEND_FROM_U_ERROR_SUBST; + } else { + zend_error(E_WARNING, "Illegal value for conversion error mode"); + return FAILURE; + } + } + + return SUCCESS; +} +#endif + +static void zend_update_converters_error_behavior(TSRMLS_D) +{ + if (UG(fallback_encoding_conv)) { + zend_set_converter_error_mode(UG(fallback_encoding_conv), UG(from_u_error_mode)); + zend_set_converter_subst_char(UG(fallback_encoding_conv), UG(subst_char), UG(subst_char_len)); + } + if (UG(runtime_encoding_conv)) { + zend_set_converter_error_mode(UG(runtime_encoding_conv), UG(from_u_error_mode)); + zend_set_converter_subst_char(UG(runtime_encoding_conv), UG(subst_char), UG(subst_char_len)); + } + if (UG(output_encoding_conv)) { + zend_set_converter_error_mode(UG(output_encoding_conv), UG(from_u_error_mode)); + zend_set_converter_subst_char(UG(output_encoding_conv), UG(subst_char), UG(subst_char_len)); + } + if (UG(http_input_encoding_conv)) { + zend_set_converter_error_mode(UG(http_input_encoding_conv), UG(from_u_error_mode)); + } +} + + +static ZEND_INI_MH(OnUpdateConversionErrorMode) +{ + if (!new_value) { + UG(from_u_error_mode) = ZEND_FROM_U_ERROR_SUBST; + } else { + UG(from_u_error_mode) = atoi(new_value); + } + zend_update_converters_error_behavior(TSRMLS_C); + return SUCCESS; +} + + +static ZEND_INI_MH(OnUpdateConversionSubstChar) +{ + uint8_t i = 0; + UChar32 c = 0x3f; /*'?'*/ + char *end_ptr; + + if (new_value) { + c = (int32_t)strtol(new_value, &end_ptr, 16); + if (end_ptr < new_value + strlen(new_value)) { + zend_error(E_WARNING, "Substitution character string should be a hexadecimal Unicode codepoint value"); + return FAILURE; + } + if (c < 0 || c >= 0x10FFFF) { + zend_error(E_WARNING, "Substitution character value U+%06x is out of range 0-10FFFF", c); + return FAILURE; + } + } + U16_APPEND_UNSAFE(UG(subst_char), i, c); + UG(subst_char)[i] = 0; + UG(subst_char_len) = i; + zend_update_converters_error_behavior(TSRMLS_C); + + return SUCCESS; +} + + ZEND_INI_BEGIN() - ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) + + /* Unicode .ini entries */ + STD_ZEND_INI_ENTRY("unicode_semantics", "off", ZEND_INI_SYSTEM|ZEND_INI_PERDIR, OnUpdateBool, unicode, zend_unicode_globals, unicode_globals) + STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals) + STD_ZEND_INI_ENTRY("unicode.runtime_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, runtime_encoding_conv, zend_unicode_globals, unicode_globals) + STD_ZEND_INI_ENTRY("unicode.script_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, script_encoding_conv, zend_unicode_globals, unicode_globals) + STD_ZEND_INI_ENTRY("unicode.http_input_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, http_input_encoding_conv, zend_unicode_globals, unicode_globals) + ZEND_INI_ENTRY("unicode.from_error_mode", "2", ZEND_INI_ALL, OnUpdateConversionErrorMode) + ZEND_INI_ENTRY("unicode.from_error_subst_char", "3f", ZEND_INI_ALL, OnUpdateConversionSubstChar) ZEND_INI_END() @@ -84,11 +212,15 @@ ZEND_INI_END() ZEND_API int compiler_globals_id; ZEND_API int executor_globals_id; ZEND_API int alloc_globals_id; -HashTable *global_function_table; -HashTable *global_class_table; -HashTable *global_constants_table; -HashTable *global_auto_globals_table; #endif +static HashTable *global_function_table = NULL; +static HashTable *global_class_table = NULL; +static HashTable *global_constants_table = NULL; +static HashTable *global_auto_globals_table = NULL; +static HashTable *global_u_function_table = NULL; +static HashTable *global_u_class_table = NULL; +static HashTable *global_u_constants_table = NULL; +static HashTable *global_u_auto_globals_table = NULL; ZEND_API zend_utility_values zend_uv; @@ -118,17 +250,25 @@ static void print_hash(HashTable *ht, int indent, zend_bool is_object TSRMLS_DC) indent += PRINT_ZVAL_INDENT; zend_hash_internal_pointer_reset_ex(ht, &iterator); while (zend_hash_get_current_data_ex(ht, (void **) &tmp, &iterator) == SUCCESS) { + zend_uchar key_type; + for (i=0; i 0) { - ZEND_PUTS(","); - } - ZEND_PUTS("["); - switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator)) { - case HASH_KEY_IS_STRING: - ZEND_PUTS(string_key); - break; - case HASH_KEY_IS_LONG: - zend_printf("%ld", num_key); - break; - } - ZEND_PUTS("] => "); - zend_print_flat_zval_r(*tmp TSRMLS_CC); - zend_hash_move_forward_ex(ht, &iterator); - } + zval **tmp; + char *string_key; + HashPosition iterator; + ulong num_key; + uint str_len; + int i = 0; + + zend_hash_internal_pointer_reset_ex(ht, &iterator); + while (zend_hash_get_current_data_ex(ht, (void **) &tmp, &iterator) == SUCCESS) { + if (i++ > 0) { + ZEND_PUTS(","); + } + ZEND_PUTS("["); + switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator)) { + case HASH_KEY_IS_STRING: + ZEND_PUTS(string_key); + break; + case HASH_KEY_IS_LONG: + zend_printf("%ld", num_key); + break; + } + ZEND_PUTS("] => "); + zend_print_flat_zval_r(*tmp TSRMLS_CC); + zend_hash_move_forward_ex(ht, &iterator); + } } -ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy) +ZEND_API void zend_make_string_zval(zval *expr, zval *expr_copy, int *use_copy) { if (expr->type==IS_STRING) { *use_copy = 0; return; } + switch (expr->type) { + case IS_OBJECT: + { + TSRMLS_FETCH(); +#if 0 + /* Standard PHP objects */ + if (Z_OBJ_HT_P(expr) == &std_object_handlers || !Z_OBJ_HT_P(expr)->cast_object) { + if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + break; + } + zend_error(E_NOTICE, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name); + } +#endif + if (Z_OBJ_HANDLER_P(expr, cast_object)) { + if(Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + break; + } + } else { + if(Z_OBJ_HANDLER_P(expr, get)) { + zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC); + if(Z_TYPE_P(z) != IS_OBJECT) { + zend_make_printable_zval(z, expr_copy, use_copy); + FREE_ZVAL(z); + return; + } + } + } + if (EG(exception)) { + zval_dtor(expr_copy); + expr_copy->value.str.len = 0; + expr_copy->value.str.val = STR_EMPTY_ALLOC(); + break; + } + } + expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); + expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle); + expr_copy->type = IS_STRING; + break; + default: + *expr_copy = *expr; + zval_copy_ctor(expr_copy); + convert_to_string(expr_copy); + break; + } + *use_copy = 1; +} + +ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy) +{ + UErrorCode temp = U_ZERO_ERROR; + TSRMLS_FETCH(); + + if (expr->type == IS_BINARY || + /* UTODO: clean this up */ + (expr->type == IS_STRING && + (!strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &temp), + ucnv_getName(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &temp))))) { + *use_copy = 0; + return; + } switch (expr->type) { case IS_NULL: expr_copy->value.str.len = 0; @@ -215,14 +419,13 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop break; case IS_OBJECT: { - TSRMLS_FETCH(); #if 0 /* Standard PHP objects */ if (Z_OBJ_HT_P(expr) == &std_object_handlers || !Z_OBJ_HT_P(expr)->cast_object) { if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { break; } - zend_error(E_NOTICE, "Object of class %s could not be converted to string", Z_OBJCE_P(expr)->name); + zend_error(E_NOTICE, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name); } #endif if (Z_OBJ_HANDLER_P(expr, cast_object)) { @@ -248,6 +451,7 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop } expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle); + expr_copy->type = IS_STRING; break; case IS_DOUBLE: *expr_copy = *expr; @@ -257,7 +461,11 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop default: *expr_copy = *expr; zval_copy_ctor(expr_copy); - convert_to_string(expr_copy); + if (UG(unicode)) { + convert_to_string_with_converter(expr_copy, ZEND_U_CONVERTER(UG(output_encoding_conv))); + } else { + convert_to_string(expr_copy); + } break; } expr_copy->type = IS_STRING; @@ -265,6 +473,61 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop } +ZEND_API void zend_make_unicode_zval(zval *expr, zval *expr_copy, int *use_copy) +{ + TSRMLS_FETCH(); + + if (expr->type==IS_UNICODE) { + *use_copy = 0; + return; + } + switch (expr->type) { + case IS_OBJECT: + { +#if 0 + /* Standard PHP objects */ + if (Z_OBJ_HT_P(expr) == &std_object_handlers || !Z_OBJ_HT_P(expr)->cast_object) { + if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + break; + } + zend_error(E_NOTICE, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name); + } +#endif + if (Z_OBJ_HANDLER_P(expr, cast_object)) { + if(Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) { + break; + } + } else { + if(Z_OBJ_HANDLER_P(expr, get)) { + zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC); + if(Z_TYPE_P(z) != IS_OBJECT) { + zend_make_unicode_zval(z, expr_copy, use_copy); + FREE_ZVAL(z); + return; + } + } + } + if (EG(exception)) { + zval_dtor(expr_copy); + expr_copy->value.ustr.len = 0; + expr_copy->value.ustr.val = USTR_MAKE(""); + break; + } + } + expr_copy->value.ustr.val = emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG + 1); + expr_copy->value.ustr.len = u_sprintf(expr_copy->value.ustr.val, "Object id #%ld", (long)expr->value.obj.handle); + expr_copy->type = IS_UNICODE; + break; + default: + *expr_copy = *expr; + zval_copy_ctor(expr_copy); + convert_to_unicode(expr_copy); + break; + } + *use_copy = 1; +} + + ZEND_API int zend_print_zval(zval *expr, int indent) { return zend_print_zval_ex(zend_write, expr, indent); @@ -295,28 +558,32 @@ ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int in ZEND_API void zend_print_flat_zval_r(zval *expr TSRMLS_DC) { - switch (expr->type) { - case IS_ARRAY: - ZEND_PUTS("Array ("); - if (++expr->value.ht->nApplyCount>1) { - ZEND_PUTS(" *RECURSION*"); - expr->value.ht->nApplyCount--; - return; - } - print_flat_hash(expr->value.ht TSRMLS_CC); - ZEND_PUTS(")"); - expr->value.ht->nApplyCount--; - break; - case IS_OBJECT: - { + switch (expr->type) { + case IS_ARRAY: + ZEND_PUTS("Array ("); + if (++expr->value.ht->nApplyCount>1) { + ZEND_PUTS(" *RECURSION*"); + expr->value.ht->nApplyCount--; + return; + } + print_flat_hash(expr->value.ht TSRMLS_CC); + ZEND_PUTS(")"); + expr->value.ht->nApplyCount--; + break; + case IS_OBJECT: + { HashTable *properties = NULL; char *class_name = NULL; zend_uint clen; - + if (Z_OBJ_HANDLER_P(expr, get_class_name)) { Z_OBJ_HANDLER_P(expr, get_class_name)(expr, &class_name, &clen, 0 TSRMLS_CC); } - zend_printf("%s Object (", class_name?class_name:"Unknown Class"); + if (class_name) { + zend_printf("%v Object (", class_name); + } else { + zend_printf("%s Object (", "Unknown Class"); + } if (class_name) { efree(class_name); } @@ -334,11 +601,11 @@ ZEND_API void zend_print_flat_zval_r(zval *expr TSRMLS_DC) } ZEND_PUTS(")"); break; - } - default: - zend_print_variable(expr); - break; - } + } + default: + zend_print_variable(expr); + break; + } } ZEND_API void zend_print_zval_r(zval *expr, int indent TSRMLS_DC) @@ -365,11 +632,15 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int HashTable *properties = NULL; char *class_name = NULL; zend_uint clen; - + if (Z_OBJ_HANDLER_P(expr, get_class_name)) { Z_OBJ_HANDLER_P(expr, get_class_name)(expr, &class_name, &clen, 0 TSRMLS_CC); } - zend_printf("%s Object\n", class_name?class_name:"Unknown Class"); + if (class_name) { + zend_printf("%v Object\n", class_name); + } else { + zend_printf("%s Object\n", "Unknown Class"); + } if (class_name) { efree(class_name); } @@ -425,6 +696,186 @@ static void zend_set_default_compile_time_values(TSRMLS_D) } +#define ZEND_U_FUNCTION_DTOR (void (*)(void *)) zend_u_function_dtor +#define ZEND_U_CONSTANT_DTOR (void (*)(void *)) free_u_zend_constant + +static void zval_copy_persistent(zval *zv) +{ + if (Z_TYPE_P(zv) == IS_BINARY) { + Z_BINVAL_P(zv) = zend_strndup(Z_BINVAL_P(zv), Z_BINLEN_P(zv)); + } else if (Z_TYPE_P(zv) == IS_UNICODE) { + Z_USTRVAL_P(zv) = zend_ustrndup(Z_USTRVAL_P(zv), Z_USTRLEN_P(zv)); + } else if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) { + UChar *ustr; + + ustr = malloc(UBYTES(Z_STRLEN_P(zv)+1)); + u_charsToUChars(Z_STRVAL_P(zv), ustr, Z_STRLEN_P(zv)+1); + Z_USTRVAL_P(zv) = ustr; + if (Z_TYPE_P(zv) == IS_STRING) Z_TYPE_P(zv) = IS_UNICODE; + } +} + +static void zend_u_function_dtor(zend_function *function) +{ + TSRMLS_FETCH(); + + destroy_zend_function(function TSRMLS_CC); + if (function->type == ZEND_INTERNAL_FUNCTION && function->common.function_name) { + free(function->common.function_name); + } +} + +static void free_u_zend_constant(zend_constant *c) +{ + if (!(c->flags & CONST_PERSISTENT)) { + zval_dtor(&c->value); + } else { + zval_internal_dtor(&c->value); + } + free(c->name); +} + +static void copy_u_zend_constant(zend_constant *c) +{ + c->name = (char*)zend_ustrndup((UChar*)c->name, c->name_len - 1); + if (!(c->flags & CONST_PERSISTENT)) { + zval_copy_ctor(&c->value); + } else { + zval_copy_persistent(&c->value); + } +} + +static void function_to_unicode(zend_function *func) +{ + if (func->common.function_name) { + UChar *uname; + int len = strlen(func->common.function_name)+1; + + uname = malloc(UBYTES(len)); + u_charsToUChars(func->common.function_name, uname, len); + func->common.function_name = (char*)uname; + } +} + +static void property_info_to_unicode(zend_property_info *info) +{ + if (info->name) { + UChar *uname; + + uname = malloc(UBYTES(info->name_length+1)); + u_charsToUChars(info->name, uname, info->name_length+1); + info->name = (char*)uname; + info->h = zend_u_get_hash_value(IS_UNICODE, info->name, info->name_length+1); + } +} + +static void zval_ptr_to_unicode(zval **zv) +{ + zval *new_zv = malloc(sizeof(zval)); + + memcpy(new_zv, *zv, sizeof(zval)); + new_zv->refcount = 1; + zval_copy_persistent(new_zv); + *zv = new_zv; +} + +static void const_to_unicode(zend_constant *c) +{ + UChar *uname; + + if (c->name) { + uname = malloc(UBYTES(c->name_len)); + u_charsToUChars(c->name, uname, c->name_len); + c->name = (char*)uname; + } + zval_copy_persistent(&c->value); +} + +static void class_to_unicode(zend_class_entry **ce) +{ + zend_class_entry *new_ce = malloc(sizeof(zend_class_entry)); + zend_function tmp_func; + zend_constant tmp_const; + zend_property_info tmp_info; + zval* tmp_zval; + + memcpy(new_ce, *ce, sizeof(zend_class_entry)); + + /* Copy methods */ + zend_u_hash_init_ex(&new_ce->function_table, (*ce)->function_table.nNumOfElements, NULL, ZEND_U_FUNCTION_DTOR, 1, 1, 0); + zend_hash_copy(&new_ce->function_table, &(*ce)->function_table, (copy_ctor_func_t) function_to_unicode, &tmp_func, sizeof(zend_function)); + + /* Copy constants */ + zend_u_hash_init_ex(&new_ce->constants_table, (*ce)->constants_table.nNumOfElements, NULL, (*ce)->constants_table.pDestructor, 1, 1, 0); + zend_hash_copy(&new_ce->constants_table, &(*ce)->constants_table, (copy_ctor_func_t) zval_ptr_to_unicode, &tmp_const, sizeof(zend_constant)); + + /* Copy properties */ + zend_u_hash_init_ex(&new_ce->properties_info, (*ce)->properties_info.nNumOfElements, NULL, (*ce)->properties_info.pDestructor/*(dtor_func_t)zend_destroy_property_info_internal*/, 1, 1, 0); + zend_hash_copy(&new_ce->properties_info, &(*ce)->properties_info, (copy_ctor_func_t) property_info_to_unicode, &tmp_info, sizeof(zend_property_info)); + + zend_u_hash_init_ex(&new_ce->default_properties, (*ce)->default_properties.nNumOfElements, NULL, (*ce)->default_properties.pDestructor, 1, 1, 0); + zend_hash_copy(&new_ce->default_properties, &(*ce)->default_properties, (copy_ctor_func_t) zval_ptr_to_unicode, &tmp_zval, sizeof(zval*)); + + if (new_ce->static_members) { + new_ce->static_members = (HashTable*)malloc(sizeof(HashTable)); + zend_u_hash_init_ex(new_ce->static_members, (*ce)->static_members->nNumOfElements, NULL, (*ce)->static_members->pDestructor, 1, 1, 0); + zend_hash_copy(new_ce->static_members, (*ce)->static_members, (copy_ctor_func_t) zval_ptr_to_unicode, &tmp_zval, sizeof(zval*)); + } + + *ce = new_ce; +} + +static void fix_classes(HashTable *ht) { + Bucket *p = ht->pListHead; + + /* Fix parent classes */ + while (p != NULL) { + zend_class_entry *ce = *(zend_class_entry**)p->pData; + zend_class_entry **parent; + + if (ce->parent) { + char *lcname = do_alloca(ce->parent->name_length+1); + + zend_str_tolower_copy(lcname, ce->parent->name, ce->parent->name_length); + if (zend_hash_find(ht, lcname, ce->parent->name_length+1, (void**)&parent) == SUCCESS) { + ce->parent = *parent; + } + free_alloca(lcname); + } + if (ce->num_interfaces > 0 && ce->interfaces) { + int i = sizeof(zend_class_entry*)*ce->num_interfaces; + zend_class_entry **new_interfaces; + + new_interfaces = (zend_class_entry**)malloc(i); + memcpy(new_interfaces, ce->interfaces, i); + ce->interfaces = new_interfaces; + for (i = 0; i < ce->num_interfaces; i++) { + char *lcname = do_alloca(ce->interfaces[i]->name_length+1); + + zend_str_tolower_copy(lcname, ce->interfaces[i]->name, ce->interfaces[i]->name_length); + if (zend_hash_find(ht, lcname, ce->interfaces[i]->name_length+1, (void**)&parent) == SUCCESS) { + ce->interfaces[i] = *parent; + } + free_alloca(lcname); + + } + } + p = p->pListNext; + } + + /* Convert Class Names to unicode */ + p = ht->pListHead; + while (p != NULL) { + zend_class_entry *ce = *(zend_class_entry**)p->pData; + UChar *uname = malloc(UBYTES(ce->name_length+1)); + + u_charsToUChars(ce->name, uname, ce->name_length+1); + ce->name = (char*)uname; + + p = p->pListNext; + } +} + #ifdef ZTS static void compiler_globals_ctor(zend_compiler_globals *compiler_globals TSRMLS_DC) { @@ -433,45 +884,102 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals TSRMLS compiler_globals->compiled_filename = NULL; - compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init_ex(compiler_globals->function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); - zend_hash_copy(compiler_globals->function_table, global_function_table, NULL, &tmp_func, sizeof(zend_function)); + compiler_globals->global_function_table = compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0, 0); + zend_hash_copy(compiler_globals->function_table, global_function_table, NULL, &tmp_func, sizeof(zend_function)); - compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init_ex(compiler_globals->class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); - zend_hash_copy(compiler_globals->class_table, global_class_table, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *)); + if (global_u_function_table) { + compiler_globals->global_u_function_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->global_u_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 1, 0); + zend_hash_copy(compiler_globals->global_u_function_table, global_u_function_table, NULL, &tmp_func, sizeof(zend_function)); + } else { + compiler_globals->global_u_function_table = 0; + } + + compiler_globals->global_class_table = compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0, 0); + zend_hash_copy(compiler_globals->class_table, global_class_table, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *)); + if (global_u_class_table) { + compiler_globals->global_u_class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->global_u_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 1, 0); + zend_hash_copy(compiler_globals->global_u_class_table, global_u_class_table, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *)); + } else { + compiler_globals->global_u_class_table = NULL; + } zend_set_default_compile_time_values(TSRMLS_C); CG(interactive) = 0; + CG(literal_type) = IS_STRING; - compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, NULL, 1, 0); + compiler_globals->global_auto_globals_table = compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->auto_globals, 8, NULL, NULL, 1, 0, 0); zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, NULL, NULL, sizeof(zend_auto_global) /* empty element */); + + if (global_u_auto_globals_table) { + compiler_globals->global_u_auto_globals_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(compiler_globals->global_u_auto_globals_table, 8, NULL, NULL, 1, 1, 0); + zend_hash_copy(compiler_globals->global_u_auto_globals_table, global_u_auto_globals_table, NULL, NULL, sizeof(zend_auto_global) /* empty element */); + } else { + compiler_globals->global_u_auto_globals_table = NULL; + } } static void compiler_globals_dtor(zend_compiler_globals *compiler_globals TSRMLS_DC) { - if (compiler_globals->function_table != GLOBAL_FUNCTION_TABLE) { - zend_hash_destroy(compiler_globals->function_table); - free(compiler_globals->function_table); + if (compiler_globals->function_table != global_function_table && + compiler_globals->function_table != global_u_function_table) { + if (compiler_globals->global_function_table) { + zend_hash_destroy(compiler_globals->global_function_table); + free(compiler_globals->global_function_table); + } + if (compiler_globals->global_u_function_table) { + zend_hash_destroy(compiler_globals->global_u_function_table); + free(compiler_globals->global_u_function_table); + } } - if (compiler_globals->class_table != GLOBAL_CLASS_TABLE) { - zend_hash_destroy(compiler_globals->class_table); - free(compiler_globals->class_table); + if (compiler_globals->class_table != global_class_table && + compiler_globals->class_table != global_u_class_table) { + if (compiler_globals->global_class_table) { + zend_hash_destroy(compiler_globals->global_class_table); + free(compiler_globals->global_class_table); + } + if (compiler_globals->global_u_class_table) { + zend_hash_destroy(compiler_globals->global_u_class_table); + free(compiler_globals->global_u_class_table); + } } - if (compiler_globals->auto_globals != GLOBAL_AUTO_GLOBALS_TABLE) { - zend_hash_destroy(compiler_globals->auto_globals); - free(compiler_globals->auto_globals); + if (compiler_globals->auto_globals != global_auto_globals_table && + compiler_globals->auto_globals != global_u_auto_globals_table) { + if (compiler_globals->global_auto_globals_table) { + zend_hash_destroy(compiler_globals->global_auto_globals_table); + free(compiler_globals->global_auto_globals_table); + } + if (compiler_globals->global_u_auto_globals_table) { + zend_hash_destroy(compiler_globals->global_u_auto_globals_table); + free(compiler_globals->global_u_auto_globals_table); + } } } static void executor_globals_ctor(zend_executor_globals *executor_globals TSRMLS_DC) { + zend_constant tmp_const; + zend_startup_constants(TSRMLS_C); - zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE); + zend_copy_constants(EG(zend_constants), global_constants_table); + EG(global_constants_table) = EG(zend_constants); + + if (global_u_constants_table) { + EG(global_u_constants_table) = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(EG(global_u_constants_table), global_u_constants_table->nNumOfElements, NULL, ZEND_U_CONSTANT_DTOR, 1, 1, 0); + zend_hash_copy(EG(global_u_constants_table), global_u_constants_table, (copy_ctor_func_t) copy_u_zend_constant, &tmp_const, sizeof(zend_constant)); + } else { + EG(global_u_constants_table) = NULL; + } + zend_init_rsrc_plist(TSRMLS_C); EG(lambda_count)=0; EG(user_error_handler) = NULL; @@ -506,7 +1014,6 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals_p TSRMLS_DC) start_memory_manager(TSRMLS_C); } - #if defined(__FreeBSD__) || defined(__DragonFly__) /* FreeBSD and DragonFly floating point precision fix */ #include @@ -528,6 +1035,44 @@ static void scanner_globals_ctor(zend_scanner_globals *scanner_globals_p TSRMLS_ scanner_globals_p->yy_start_stack = 0; } +static void unicode_globals_ctor(zend_unicode_globals *unicode_globals TSRMLS_DC) +{ + unicode_globals->unicode = 0; + unicode_globals->utf8_conv = NULL; + unicode_globals->fallback_encoding_conv = NULL; + unicode_globals->runtime_encoding_conv = NULL; + unicode_globals->output_encoding_conv = NULL; + unicode_globals->script_encoding_conv = NULL; + unicode_globals->http_input_encoding_conv = NULL; + zend_set_converter_encoding(&unicode_globals->utf8_conv, "UTF-8"); + unicode_globals->from_u_error_mode = ZEND_FROM_U_ERROR_SUBST; + + zend_hash_init_ex(&unicode_globals->flex_compatible, 0, NULL, NULL, 1, 0); +} + +static void unicode_globals_dtor(zend_unicode_globals *unicode_globals TSRMLS_DC) +{ + if (unicode_globals->fallback_encoding_conv) { + ucnv_close(unicode_globals->fallback_encoding_conv); + } + if (unicode_globals->runtime_encoding_conv) { + ucnv_close(unicode_globals->runtime_encoding_conv); + } + if (unicode_globals->output_encoding_conv) { + ucnv_close(unicode_globals->output_encoding_conv); + } + if (unicode_globals->script_encoding_conv) { + ucnv_close(unicode_globals->script_encoding_conv); + } + if (unicode_globals->http_input_encoding_conv) { + ucnv_close(unicode_globals->http_input_encoding_conv); + } + if (unicode_globals->utf8_conv) { + ucnv_close(unicode_globals->utf8_conv); + } + zend_hash_destroy(&unicode_globals->flex_compatible); +} + void zend_init_opcodes_handlers(); int zend_startup(zend_utility_functions *utility_functions, char **extensions, int start_builtin_functions) @@ -538,9 +1083,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i void ***tsrm_ls; extern ZEND_API ts_rsrc_id ini_scanner_globals_id; extern ZEND_API ts_rsrc_id language_scanner_globals_id; + extern ZEND_API ts_rsrc_id unicode_globals_id; #else extern zend_scanner_globals ini_scanner_globals; extern zend_scanner_globals language_scanner_globals; + extern zend_unicode_globals unicode_globals; #endif #ifdef ZTS @@ -585,14 +1132,15 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i zend_version_info = strdup(ZEND_CORE_VERSION_INFO); zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO)-1; - GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); - GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); - GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); -#ifdef ZTS - GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); -#endif - zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); - zend_hash_init_ex(GLOBAL_CLASS_TABLE, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + global_function_table = (HashTable *) malloc(sizeof(HashTable)); + global_class_table = (HashTable *) malloc(sizeof(HashTable)); + global_auto_globals_table = (HashTable *) malloc(sizeof(HashTable)); + global_constants_table = (HashTable *) malloc(sizeof(HashTable)); + + zend_hash_init_ex(global_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); + zend_hash_init_ex(global_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(global_auto_globals_table, 8, NULL, (dtor_func_t) zend_auto_global_dtor, 1, 0); + zend_hash_init_ex(global_constants_table, 20, NULL, ZEND_CONSTANT_DTOR, 1, 0); zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0); zend_init_rsrc_list_dtors(); @@ -604,8 +1152,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i zval_used_for_init.type = IS_NULL; #ifdef ZTS - zend_hash_init_ex(GLOBAL_CONSTANTS_TABLE, 20, NULL, ZEND_CONSTANT_DTOR, 1, 0); - zend_hash_init_ex(GLOBAL_AUTO_GLOBALS_TABLE, 8, NULL, (dtor_func_t) zend_auto_global_dtor, 1, 0); + ts_allocate_id(&unicode_globals_id, sizeof(zend_unicode_globals), (ts_allocate_ctor) unicode_globals_ctor, (ts_allocate_dtor) unicode_globals_dtor); ts_allocate_id(&compiler_globals_id, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor); ts_allocate_id(&executor_globals_id, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor); ts_allocate_id(&language_scanner_globals_id, sizeof(zend_scanner_globals), (ts_allocate_ctor) scanner_globals_ctor, NULL); @@ -619,17 +1166,22 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); - *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; - *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; - compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + *compiler_globals->function_table = *global_function_table; + *compiler_globals->class_table = *global_class_table; + compiler_globals->auto_globals = global_auto_globals_table; zend_hash_destroy(executor_globals->zend_constants); - *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; + *executor_globals->zend_constants = *global_constants_table; #else - zend_hash_init_ex(CG(auto_globals), 8, NULL, (dtor_func_t) zend_auto_global_dtor, 1, 0); + unicode_globals_ctor(&unicode_globals TSRMLS_CC); scanner_globals_ctor(&ini_scanner_globals TSRMLS_CC); scanner_globals_ctor(&language_scanner_globals TSRMLS_CC); - zend_startup_constants(); + + CG(function_table) = global_function_table; + CG(class_table) = global_class_table; + CG(auto_globals) = global_auto_globals_table; + EG(zend_constants) = global_constants_table; + zend_set_default_compile_time_values(TSRMLS_C); EG(user_error_handler) = NULL; EG(user_exception_handler) = NULL; @@ -663,19 +1215,51 @@ void zend_register_standard_ini_entries(TSRMLS_D) REGISTER_INI_ENTRIES(); } - -#ifdef ZTS /* Unlink the global (r/o) copies of the class, function and constant tables, * and use a fresh r/w copy for the startup thread */ void zend_post_startup(TSRMLS_D) { + UConverter *old_runtime_encoding_conv; + UErrorCode status = U_ZERO_ERROR; + zend_function tmp_func; + zend_class_entry *tmp_class; + zend_constant tmp_const; +#ifdef ZTS zend_compiler_globals *compiler_globals = ts_resource(compiler_globals_id); zend_executor_globals *executor_globals = ts_resource(executor_globals_id); - *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; - *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; - *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + *global_function_table = *compiler_globals->function_table; + *global_class_table = *compiler_globals->class_table; + *global_constants_table = *executor_globals->zend_constants; +#endif + + /* Make copies of HashTables with UNICODE */ + + old_runtime_encoding_conv = UG(runtime_encoding_conv); + UG(runtime_encoding_conv) = ucnv_open("ASCII", &status); + + global_u_function_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(global_u_function_table, global_function_table->nNumOfElements, NULL, ZEND_U_FUNCTION_DTOR, 1, 1, 0); + zend_hash_copy(global_u_function_table, global_function_table, (copy_ctor_func_t) function_to_unicode, &tmp_func, sizeof(zend_function)); + + global_u_class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(global_u_class_table, global_class_table->nNumOfElements, NULL, ZEND_CLASS_DTOR, 1, 1, 0); + zend_hash_copy(global_u_class_table, global_class_table, (copy_ctor_func_t) class_to_unicode, &tmp_class, sizeof(zend_class_entry *)); + fix_classes(global_u_class_table); + + global_u_auto_globals_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(global_u_auto_globals_table, global_auto_globals_table->nNumOfElements, NULL, NULL, 1, 1, 0); + zend_hash_copy(global_u_auto_globals_table, global_auto_globals_table, NULL, NULL, sizeof(zend_auto_global)); + + global_u_constants_table = (HashTable *) malloc(sizeof(HashTable)); + zend_u_hash_init_ex(global_u_constants_table, global_constants_table->nNumOfElements, NULL, ZEND_U_CONSTANT_DTOR, 1, 1, 0); + zend_hash_copy(global_u_constants_table, global_constants_table, (copy_ctor_func_t) const_to_unicode, &tmp_const, sizeof(zend_constant)); + + ucnv_close(UG(runtime_encoding_conv)); + UG(runtime_encoding_conv) = old_runtime_encoding_conv; + +#ifdef ZTS zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); free(compiler_globals->function_table); free(compiler_globals->class_table); @@ -683,8 +1267,8 @@ void zend_post_startup(TSRMLS_D) free(EG(zend_constants)); executor_globals_ctor(executor_globals, tsrm_ls); zend_new_thread_end_handler(tsrm_thread_id() TSRMLS_CC); -} #endif +} void zend_shutdown(TSRMLS_D) @@ -697,25 +1281,57 @@ void zend_shutdown(TSRMLS_D) #endif zend_hash_graceful_reverse_destroy(&module_registry); - zend_hash_destroy(GLOBAL_FUNCTION_TABLE); - zend_hash_destroy(GLOBAL_CLASS_TABLE); + zend_hash_destroy(global_function_table); + zend_hash_destroy(global_class_table); + if (global_u_function_table) { + zend_hash_destroy(global_u_function_table); + } + if (global_u_class_table) { + zend_hash_destroy(global_u_class_table); + } - zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); - free(GLOBAL_AUTO_GLOBALS_TABLE); + zend_hash_destroy(global_auto_globals_table); + free(global_auto_globals_table); + if (global_u_auto_globals_table) { + zend_hash_destroy(global_u_auto_globals_table); + free(global_u_auto_globals_table); + } zend_shutdown_extensions(TSRMLS_C); free(zend_version_info); - zend_shutdown_constants(TSRMLS_C); - free(GLOBAL_FUNCTION_TABLE); - free(GLOBAL_CLASS_TABLE); +#ifdef ZTS + if (EG(global_constants_table)) { + zend_hash_destroy(EG(global_constants_table)); + free(EG(global_constants_table)); + } + if (EG(global_u_constants_table)) { + zend_hash_destroy(EG(global_u_constants_table)); + free(EG(global_u_constants_table)); + } +#endif + zend_hash_destroy(global_constants_table); + free(global_constants_table); + if (global_u_constants_table) { + zend_hash_destroy(global_u_constants_table); + free(global_u_constants_table); + } + + free(global_function_table); + free(global_class_table); + if (global_u_function_table) { + free(global_u_function_table); + } + if (global_u_class_table) { + free(global_u_class_table); + } #ifdef ZTS zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); - zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); - free(GLOBAL_CONSTANTS_TABLE); - GLOBAL_FUNCTION_TABLE = NULL; - GLOBAL_CLASS_TABLE = NULL; - GLOBAL_AUTO_GLOBALS_TABLE = NULL; + global_function_table = NULL; + global_class_table = NULL; + global_auto_globals_table = NULL; +#else + unicode_globals_dtor(&unicode_globals TSRMLS_CC); #endif zend_destroy_rsrc_list_dtors(); } @@ -779,9 +1395,54 @@ ZEND_API char *get_zend_version() return zend_version_info; } +ZEND_API void zend_reset_locale_deps(TSRMLS_D) +{ + UErrorCode status = U_ZERO_ERROR; + + if (UG(default_collator)) { + ucol_close(UG(default_collator)); + } + UG(default_collator) = ucol_open(UG(default_locale), &status); + if (U_FAILURE(status)) { + zend_error(E_ERROR, "Could not open collator for locale %s", UG(default_locale)); + } +} + +static void init_unicode_request_globals(TSRMLS_D) +{ + UG(default_locale) = safe_estrdup(uloc_getDefault()); + UG(default_collator) = NULL; + + zend_reset_locale_deps(TSRMLS_C); +} + +static void shutdown_unicode_request_globals(TSRMLS_D) +{ + ucol_close(UG(default_collator)); + efree(UG(default_locale)); +} void zend_activate(TSRMLS_D) { +#ifdef ZTS + CG(function_table) = UG(unicode)?CG(global_u_function_table):CG(global_function_table); + CG(class_table) = UG(unicode)?CG(global_u_class_table):CG(global_class_table); + CG(auto_globals) = UG(unicode)?CG(global_u_auto_globals_table):CG(global_auto_globals_table); + EG(zend_constants) = UG(unicode)?EG(global_u_constants_table):EG(global_constants_table); +#else + CG(function_table) = UG(unicode)?global_u_function_table:global_function_table; + CG(class_table) = UG(unicode)?global_u_class_table:global_class_table; + CG(auto_globals) = UG(unicode)?global_u_auto_globals_table:global_auto_globals_table; + EG(zend_constants) = UG(unicode)?global_u_constants_table:global_constants_table; +#endif + zend_standard_class_def = zend_get_named_class_entry("stdClass", sizeof("stdClass")-1 TSRMLS_CC); + + init_unicode_request_globals(TSRMLS_C); + + init_unicode_strings(); + init_exceptions(TSRMLS_C); + init_interfaces(TSRMLS_C); + init_reflection_api(TSRMLS_C); init_compiler(TSRMLS_C); init_executor(TSRMLS_C); startup_scanner(TSRMLS_C); @@ -802,7 +1463,7 @@ void zend_deactivate_modules(TSRMLS_D) } zend_end_try(); } -void zend_call_destructors(TSRMLS_D) +void zend_call_destructors(TSRMLS_D) { zend_try { shutdown_destructors(TSRMLS_C); @@ -815,6 +1476,8 @@ void zend_deactivate(TSRMLS_D) EG(opline_ptr) = NULL; EG(active_symbol_table) = NULL; + shutdown_unicode_request_globals(TSRMLS_C); + zend_try { shutdown_scanner(TSRMLS_C); } zend_end_try(); @@ -986,7 +1649,7 @@ ZEND_API void zend_error(int type, const char *format, ...) orig_user_error_handler = EG(user_error_handler); EG(user_error_handler) = NULL; - + if (call_user_function_ex(CG(function_table), NULL, orig_user_error_handler, &retval, 5, params, 1, NULL TSRMLS_CC)==SUCCESS) { if (retval) { if (Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval) == 0) { @@ -1052,6 +1715,9 @@ ZEND_API void zend_output_debug_string(zend_bool trigger_break, char *format, .. #endif } +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(DARWIN) +void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((alias("zend_error"),noreturn)); +#endif ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) { diff --git a/Zend/zend.h b/Zend/zend.h index d2aa70b6ed..b517ceff95 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -35,6 +35,7 @@ #endif #include +#include /* * general definitions @@ -225,6 +226,8 @@ char *alloca (); #include "zend_types.h" +#include + #ifdef HAVE_LIMITS_H # include #endif @@ -237,6 +240,8 @@ char *alloca (); #define LONG_MIN (- LONG_MAX - 1) #endif +#define EMPTY_STR "\0\0" + #undef SUCCESS #undef FAILURE #define SUCCESS 0 @@ -258,6 +263,13 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore # define zend_error_noreturn zend_error #endif +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(DARWIN) +# define ZEND_VM_ALWAYS_INLINE __attribute__ ((always_inline)) +void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((noreturn)); +#else +# define ZEND_VM_ALWAYS_INLINE +# define zend_error_noreturn zend_error +#endif /* * zval @@ -287,10 +299,14 @@ struct _zend_object_value { typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ - struct { + struct { /* 8-bit legacy string type */ char *val; int len; } str; + struct { /* Unicode string type */ + UChar *val; + int32_t len; + } ustr; HashTable *ht; /* hash table value */ zend_object_value obj; } zvalue_value; @@ -371,8 +387,8 @@ struct _zend_class_entry { #include "zend_stream.h" typedef struct _zend_utility_functions { - void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); - int (*printf_function)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2); + void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); + int (*printf_function)(const char *format, ...); int (*write_function)(const char *str, uint str_length); FILE *(*fopen_function)(const char *filename, char **opened_path); void (*message_handler)(long message, void *data); @@ -407,6 +423,8 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); ((n) ? (((n)>0) ? 1 : -1) : 0) #define ZEND_TRUTH(x) ((x) ? 1 : 0) #define ZEND_LOG_XOR(a, b) (ZEND_TRUTH(a) ^ ZEND_TRUTH(b)) +#define ZEND_COLL_RESULT(n) \ + ((n) == UCOL_EQUAL ? 0 : ((n) == UCOL_GREATER ? 1 : -1)) @@ -422,6 +440,8 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); #define IS_RESOURCE 7 #define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 +#define IS_UNICODE 10 +#define IS_BINARY 11 /* Ugly hack to support constants as static array indices */ #define IS_CONSTANT_INDEX 0x80 @@ -432,14 +452,13 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); #define OE_IS_OBJECT (1<<1) #define OE_IS_METHOD (1<<2) - int zend_startup(zend_utility_functions *utility_functions, char **extensions, int start_builtin_functions); void zend_shutdown(TSRMLS_D); void zend_register_standard_ini_entries(TSRMLS_D); -#ifdef ZTS +//#ifdef ZTS void zend_post_startup(TSRMLS_D); -#endif +//#endif void zend_set_utility_values(zend_utility_values *utility_values); @@ -468,12 +487,14 @@ END_EXTERN_C() BEGIN_EXTERN_C() ZEND_API char *get_zend_version(void); ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy); +ZEND_API void zend_make_string_zval(zval *expr, zval *expr_copy, int *use_copy); +ZEND_API void zend_make_unicode_zval(zval *expr, zval *expr_copy, int *use_copy); ZEND_API int zend_print_zval(zval *expr, int indent); ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent); ZEND_API void zend_print_zval_r(zval *expr, int indent TSRMLS_DC); ZEND_API void zend_print_flat_zval_r(zval *expr TSRMLS_DC); ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC); -ZEND_API void zend_output_debug_string(zend_bool trigger_break, char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API void zend_output_debug_string(zend_bool trigger_break, char *format, ...); END_EXTERN_C() void zend_activate(TSRMLS_D); @@ -510,20 +531,20 @@ END_EXTERN_C() BEGIN_EXTERN_C() -extern ZEND_API int (*zend_printf)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2); +extern ZEND_API int (*zend_printf)(const char *format, ...); extern ZEND_API zend_write_func_t zend_write; extern ZEND_API FILE *(*zend_fopen)(const char *filename, char **opened_path); extern ZEND_API void (*zend_block_interruptions)(void); extern ZEND_API void (*zend_unblock_interruptions)(void); extern ZEND_API void (*zend_ticks_function)(int ticks); -extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); +extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); extern void (*zend_on_timeout)(int seconds TSRMLS_DC); extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); -ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API void zend_error(int type, const char *format, ...); void zenderror(char *error); @@ -545,6 +566,7 @@ BEGIN_EXTERN_C() ZEND_API void zend_message_dispatcher(long message, void *data); ZEND_API int zend_get_configuration_directive(char *name, uint name_length, zval *contents); +ZEND_API void zend_reset_locale_deps(TSRMLS_D); END_EXTERN_C() @@ -644,8 +666,15 @@ END_EXTERN_C() #define ZEND_MAX_RESERVED_RESOURCES 4 +#define ZEND_INTERNAL_ENCODING "UTF-16" + #include "zend_variables.h" +#define ZEND_U_EQUAL(type, ustr, ulen, str, slen) \ + ((type == IS_STRING)? \ + (!memcmp((ustr),(str),(slen))): \ + (!zend_cmp_unicode_and_literal(((UChar*)(ustr)), ulen, str, slen))) + #endif /* ZEND_H */ /* diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 537cb9086e..852821c817 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -208,7 +208,7 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D) char *space; char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_error(E_WARNING, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "Wrong parameter count for %v%s%v()", class_name, space, get_active_function_name(TSRMLS_C)); } @@ -241,6 +241,12 @@ ZEND_API char *zend_zval_type_name(zval *arg) case IS_RESOURCE: return "resource"; + case IS_UNICODE: + return "Unicode string"; + + case IS_BINARY: + return "binary data"; + default: return "unknown"; } @@ -270,8 +276,22 @@ ZEND_API int zend_get_object_classname(zval *object, char **class_name, zend_uin return 0; } +#define RETURN_AS_STRING(arg, p, pl, type) \ + *(char**)p = Z_STRVAL_PP(arg); \ + *pl = Z_STRLEN_PP(arg); \ + *type = IS_STRING; + +#define RETURN_AS_BINARY(arg, p, pl, type) \ + *(char**)p = Z_BINVAL_PP(arg); \ + *pl = Z_BINLEN_PP(arg); \ + *type = IS_BINARY; -static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) +#define RETURN_AS_UNICODE(arg, p, pl, type) \ + *(UChar**)p = Z_USTRVAL_PP(arg); \ + *pl = Z_USTRLEN_PP(arg); \ + *type = IS_UNICODE; + +static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_arg_type TSRMLS_DC) { char *spec_walk = *spec; char c = *spec_walk++; @@ -304,6 +324,19 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) } break; + case IS_UNICODE: + { + double d; + int type; + + if ((type = is_numeric_unicode(Z_USTRVAL_PP(arg), Z_USTRLEN_PP(arg), p, &d, 0)) == 0) { + return "long"; + } else if (type == IS_DOUBLE) { + *p = (long) d; + } + } + break; + case IS_NULL: case IS_LONG: case IS_DOUBLE: @@ -338,6 +371,19 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) } break; + case IS_UNICODE: + { + long l; + int type; + + if ((type = is_numeric_unicode(Z_USTRVAL_PP(arg), Z_USTRLEN_PP(arg), &l, p, 0)) == 0) { + return "double"; + } else if (type == IS_LONG) { + *p = (double) l; + } + } + break; + case IS_NULL: case IS_LONG: case IS_DOUBLE: @@ -372,10 +418,17 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) case IS_LONG: case IS_DOUBLE: case IS_BOOL: + case IS_UNICODE: convert_to_string_ex(arg); *p = Z_STRVAL_PP(arg); *pl = Z_STRLEN_PP(arg); break; + + case IS_BINARY: + *p = Z_BINVAL_PP(arg); + *pl = Z_BINLEN_PP(arg); + break; + case IS_OBJECT: { if (Z_OBJ_HANDLER_PP(arg, cast_object)) { SEPARATE_ZVAL_IF_NOT_REF(arg); @@ -383,6 +436,8 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) *pl = Z_STRLEN_PP(arg); *p = Z_STRVAL_PP(arg); break; + } else { + return "string"; } } } @@ -395,6 +450,175 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) } break; + case 'u': + { + UChar **p = va_arg(*va, UChar **); + int32_t *pl = va_arg(*va, int32_t *); + switch (Z_TYPE_PP(arg)) { + case IS_NULL: + if (return_null) { + *p = NULL; + *pl = 0; + break; + } + /* break omitted intentionally */ + + case IS_STRING: + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: + case IS_UNICODE: + convert_to_unicode_ex(arg); + *p = Z_USTRVAL_PP(arg); + *pl = Z_USTRLEN_PP(arg); + break; + + case IS_OBJECT: { + if (Z_OBJ_HANDLER_PP(arg, cast_object)) { + SEPARATE_ZVAL_IF_NOT_REF(arg); + if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) { + *pl = Z_USTRLEN_PP(arg); + *p = Z_USTRVAL_PP(arg); + break; + } else { + return "string"; + } + } + } + + case IS_ARRAY: + case IS_RESOURCE: + default: + return "string"; + } + } + break; + + case 'T': + if (T_arg_type != -1) + { + void **p = va_arg(*va, void **); + int32_t *pl = va_arg(*va, int32_t *); + zend_uchar *type = va_arg(*va, zend_uchar *); + switch (Z_TYPE_PP(arg)) { + case IS_NULL: + if (return_null) { + *p = NULL; + *pl = 0; + *type = T_arg_type; + break; + } + /* break omitted intentionally */ + + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: + case IS_STRING: + case IS_UNICODE: + case IS_BINARY: + if (T_arg_type == IS_UNICODE) { + convert_to_unicode_ex(arg); + RETURN_AS_UNICODE(arg, p, pl, type); + } else if (T_arg_type == IS_STRING) { + convert_to_string_ex(arg); + RETURN_AS_STRING(arg, p, pl, type); + } else { + convert_to_binary_ex(arg); + RETURN_AS_BINARY(arg, p, pl, type); + } + break; + + case IS_OBJECT: { + if (Z_OBJ_HANDLER_PP(arg, cast_object)) { + SEPARATE_ZVAL_IF_NOT_REF(arg); + if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, T_arg_type, 0 TSRMLS_CC) == SUCCESS) { + *(char**)p = Z_UNIVAL_PP(arg); + *pl = Z_UNILEN_PP(arg); + *type = Z_TYPE_PP(arg); + RETURN_AS_UNICODE(arg, p, pl, type); + break; + } + } + } + + case IS_ARRAY: + case IS_RESOURCE: + default: + return "string (legacy, Unicode, or binary)"; + } + + break; + } + /* break omitted intentionally */ + + case 't': + { + void **p = va_arg(*va, void **); + int32_t *pl = va_arg(*va, int32_t *); + zend_uchar *type = va_arg(*va, zend_uchar *); + switch (Z_TYPE_PP(arg)) { + case IS_NULL: + if (return_null) { + *p = NULL; + *pl = 0; + if (UG(unicode)) { + *type = IS_UNICODE; + } else { + *type = IS_STRING; + } + break; + } + /* break omitted intentionally */ + + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: + if (UG(unicode)) { + convert_to_unicode_ex(arg); + RETURN_AS_UNICODE(arg, p, pl, type); + } else { + convert_to_string_ex(arg); + RETURN_AS_STRING(arg, p, pl, type); + } + break; + + case IS_STRING: + RETURN_AS_STRING(arg, p, pl, type); + break; + + case IS_BINARY: + RETURN_AS_BINARY(arg, p, pl, type); + break; + + case IS_UNICODE: + RETURN_AS_UNICODE(arg, p, pl, type); + break; + + case IS_OBJECT: { + if (Z_OBJ_HANDLER_PP(arg, cast_object)) { + SEPARATE_ZVAL_IF_NOT_REF(arg); + if (UG(unicode)) { + if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) { + RETURN_AS_UNICODE(arg, p, pl, type); + break; + } + } else { + if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + RETURN_AS_STRING(arg, p, pl, type); + break; + } + } + } + } + + case IS_ARRAY: + case IS_RESOURCE: + default: + return "string (legacy, Unicode, or binary)"; + } + } + break; + case 'b': { zend_bool *p = va_arg(*va, zend_bool *); @@ -506,17 +730,17 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec TSRMLS_DC) return NULL; } -static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet TSRMLS_DC) +static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet, char T_arg_type TSRMLS_DC) { char *expected_type = NULL; - expected_type = zend_parse_arg_impl(arg, va, spec TSRMLS_CC); + expected_type = zend_parse_arg_impl(arg, va, spec, T_arg_type TSRMLS_CC); if (expected_type) { if (!quiet) { char *space; char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", + zend_error(E_WARNING, "%v%s%v() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type, zend_zval_type_name(*arg)); } @@ -536,15 +760,22 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl void **p; int arg_count; int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + zend_bool T_present = 0; + char T_arg_type = -1; for (spec_walk = type_spec; *spec_walk; spec_walk++) { c = *spec_walk; switch (c) { + case 'T': + T_present++; + /* break omitted intentionally */ case 'l': case 'd': case 's': case 'b': case 'r': case 'a': case 'o': case 'O': case 'z': case 'Z': + case 't': + case 'u': max_num_args++; break; @@ -560,8 +791,8 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl default: if (!quiet) { zend_function *active_function = EG(function_state_ptr)->function; - char *class_name = active_function->common.scope ? active_function->common.scope->name : ""; - zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", + char *class_name = active_function->common.scope ? active_function->common.scope->name : EMPTY_STR; + zend_error(E_WARNING, "%v%s%v(): bad type specifier while parsing parameters", class_name, class_name[0] ? "::" : "", get_active_function_name(TSRMLS_C)); @@ -577,8 +808,8 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl if (num_args < min_num_args || num_args > max_num_args) { if (!quiet) { zend_function *active_function = EG(function_state_ptr)->function; - char *class_name = active_function->common.scope ? active_function->common.scope->name : ""; - zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", + char *class_name = active_function->common.scope ? active_function->common.scope->name : EMPTY_STR; + zend_error(E_WARNING, "%v%s%v() expects %s %d parameter%s, %d given", class_name, class_name[0] ? "::" : "", get_active_function_name(TSRMLS_C), @@ -594,18 +825,48 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl arg_count = (ulong) *p; if (num_args > arg_count) { - zend_error(E_WARNING, "%s(): could not obtain parameters for parsing", - get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "%v(): could not obtain parameters for parsing", + get_active_function_name(TSRMLS_C)); return FAILURE; } + if (T_present > 1) { + /* determine 'T' target argument type */ + for (spec_walk = type_spec, i = 0; *spec_walk && i < num_args; spec_walk++) { + switch (*spec_walk) { + case 'T': + arg = (zval **) p - (arg_count-i); + if (Z_TYPE_PP(arg) == IS_BINARY) { + /* we can always convert to binary */ + T_arg_type = IS_BINARY; + } else if (Z_TYPE_PP(arg) == IS_UNICODE && (T_arg_type == -1 || T_arg_type == IS_STRING)) { + /* we can upgrade from strings to Unicode */ + T_arg_type = IS_UNICODE; + } else if (Z_TYPE_PP(arg) == IS_STRING && T_arg_type == -1) { + T_arg_type = IS_STRING; + } + i++; + break; + + case '|': case '!': + case '/': + /* pass */ + break; + + default: + i++; + break; + } + } + } + i = 0; while (num_args-- > 0) { arg = (zval **) p - (arg_count-i); if (*type_spec == '|') { type_spec++; } - if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { + if (zend_parse_arg(i+1, arg, va, &type_spec, quiet, T_arg_type TSRMLS_CC) == FAILURE) { return FAILURE; } i++; @@ -658,7 +919,7 @@ ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr ce = va_arg(va, zend_class_entry *); *object = this_ptr; if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) { - zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s", + zend_error(E_CORE_ERROR, "%v::%v() must be derived from %v::%v", ce->name, get_active_function_name(TSRMLS_C), Z_OBJCE_P(this_ptr)->name, get_active_function_name(TSRMLS_C)); } @@ -691,7 +952,7 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, *object = this_ptr; if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) { if (!quiet) { - zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s", + zend_error(E_CORE_ERROR, "%v::%v() must be derived from %v::%v", ce->name, get_active_function_name(TSRMLS_C), Z_OBJCE_P(this_ptr)->name, get_active_function_name(TSRMLS_C)); } return FAILURE; @@ -709,9 +970,11 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, ZEND_API int _array_init(zval *arg ZEND_FILE_LINE_DC) { + TSRMLS_FETCH(); + ALLOC_HASHTABLE_REL(arg->value.ht); - _zend_hash_init(arg->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC); + zend_u_hash_init(arg->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); arg->type = IS_ARRAY; return SUCCESS; } @@ -726,7 +989,7 @@ static int zend_merge_property(zval **value, int num_args, va_list args, zend_ha zval member; TSRMLS_FETCH(); - ZVAL_STRINGL(&member, hash_key->arKey, hash_key->nKeyLength-1, 0); + ZVAL_STRINGL(&member, hash_key->u.string, hash_key->nKeyLength-1, 0); obj_ht->write_property(obj, &member, *value TSRMLS_CC); } return ZEND_HASH_APPLY_KEEP; @@ -777,7 +1040,7 @@ ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { char *what = class_type->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "abstract class"; - zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name); + zend_error(E_ERROR, "Cannot instantiate %s %v", what, class_type->name); } zend_update_class_constants(class_type TSRMLS_CC); @@ -789,7 +1052,7 @@ ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type object->properties = properties; } else { ALLOC_HASHTABLE_REL(object->properties); - zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); } } else { @@ -889,11 +1152,36 @@ ZEND_API int add_assoc_stringl_ex(zval *arg, char *key, uint key_len, char *str, return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL); } +ZEND_API int add_assoc_unicode_ex(zval *arg, char *key, uint key_len, void *str, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODE(tmp, str, duplicate); + + return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_assoc_unicodel_ex(zval *arg, char *key, uint key_len, void *str, uint length, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODEL(tmp, str, length, duplicate); + + return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL); +} + ZEND_API int add_assoc_zval_ex(zval *arg, char *key, uint key_len, zval *value) { return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &value, sizeof(zval *), NULL); } +ZEND_API int add_u_assoc_zval_ex(zval *arg, zend_uchar type, void *key, uint key_len, zval *value) +{ + return zend_u_symtable_update(Z_ARRVAL_P(arg), type, key, key_len, (void *) &value, sizeof(zval *), NULL); +} ZEND_API int add_index_long(zval *arg, uint index, long n) { @@ -971,6 +1259,50 @@ ZEND_API int add_index_stringl(zval *arg, uint index, char *str, uint length, in } +ZEND_API int add_index_binary(zval *arg, uint index, char *str, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARY(tmp, str, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_index_binaryl(zval *arg, uint index, char *str, uint length, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARYL(tmp, str, length, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_index_unicode(zval *arg, uint index, UChar *str, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODE(tmp, str, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_index_unicodel(zval *arg, uint index, UChar *str, uint length, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODEL(tmp, str, length, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL); +} + + ZEND_API int add_index_zval(zval *arg, uint index, zval *value) { return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &value, sizeof(zval *), NULL); @@ -1054,6 +1386,51 @@ ZEND_API int add_next_index_stringl(zval *arg, char *str, uint length, int dupli } +ZEND_API int add_next_index_binary(zval *arg, char *str, int duplicate) +{ + zval *tmp; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARY(tmp, str, duplicate); + + return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_next_index_binaryl(zval *arg, char *str, uint length, int duplicate) +{ + zval *tmp; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARYL(tmp, str, length, duplicate); + + return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL); +} + +ZEND_API int add_next_index_unicode(zval *arg, UChar *str, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODE(tmp, str, duplicate); + + return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL); +} + + +ZEND_API int add_next_index_unicodel(zval *arg, UChar *str, uint length, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODEL(tmp, str, length, duplicate); + + return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL); +} + + ZEND_API int add_next_index_zval(zval *arg, zval *value) { return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &value, sizeof(zval *), NULL); @@ -1125,6 +1502,50 @@ ZEND_API int add_get_index_stringl(zval *arg, uint index, char *str, uint length return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest); } +ZEND_API int add_get_index_binary(zval *arg, uint index, char *str, void **dest, int duplicate) +{ + zval *tmp; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARY(tmp, str, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest); +} + + +ZEND_API int add_get_index_binaryl(zval *arg, uint index, char *str, uint length, void **dest, int duplicate) +{ + zval *tmp; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(tmp); + ZVAL_BINARYL(tmp, str, length, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest); +} + + +ZEND_API int add_get_index_unicode(zval *arg, uint index, UChar *str, void **dest, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODE(tmp, str, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest); +} + + +ZEND_API int add_get_index_unicodel(zval *arg, uint index, UChar *str, uint length, void **dest, int duplicate) +{ + zval *tmp; + + MAKE_STD_ZVAL(tmp); + ZVAL_UNICODEL(tmp, str, length, duplicate); + + return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest); +} ZEND_API int add_property_long_ex(zval *arg, char *key, uint key_len, long n TSRMLS_DC) { @@ -1391,30 +1812,43 @@ ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *mod ZEND_API void zend_check_magic_method_implementation(zend_class_entry *ce, zend_function *fptr, int error_type TSRMLS_DC) { - char lcname[16]; + unsigned int lcname_len; + char *lcname; int name_len; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; /* we don't care if the function name is longer, in fact lowercasing only * the beginning of the name speeds up the check process */ - name_len = strlen(fptr->common.function_name); - zend_str_tolower_copy(lcname, fptr->common.function_name, MIN(name_len, sizeof(lcname)-1)); - lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */ - - if (name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) && fptr->common.num_args != 0) { - zend_error(error_type, "Destuctor %s::%s() cannot take arguments", ce->name, ZEND_DESTRUCTOR_FUNC_NAME); - } else if (name_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) && fptr->common.num_args != 0) { - zend_error(error_type, "Method %s::%s() cannot accept any arguments", ce->name, ZEND_CLONE_FUNC_NAME); - } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) && fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_GET_FUNC_NAME); - } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) && fptr->common.num_args != 2) { - zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name, ZEND_SET_FUNC_NAME); - } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)) && fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_UNSET_FUNC_NAME); - } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)) && fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_ISSET_FUNC_NAME); - } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) && fptr->common.num_args != 2) { - zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name, ZEND_CALL_FUNC_NAME); + if (UG(unicode)) { + name_len = u_strlen((UChar*)fptr->common.function_name); + } else { + name_len = strlen(fptr->common.function_name); + } + lcname = zend_u_str_case_fold(utype, fptr->common.function_name, name_len, 0, &lcname_len); + + if (lcname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && fptr->common.num_args != 0) { + zend_error(error_type, "Destuctor %v::%s() cannot take arguments", ce->name, ZEND_DESTRUCTOR_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1) && fptr->common.num_args != 0) { + zend_error(error_type, "Method %v::%s() cannot accept any arguments", ce->name, ZEND_CLONE_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1) && fptr->common.num_args != 1) { + zend_error(error_type, "Method %v::%s() must take exactly 1 argument", ce->name, ZEND_GET_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1) && fptr->common.num_args != 2) { + zend_error(error_type, "Method %v::%s() must take exactly 2 arguments", ce->name, ZEND_SET_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1) && fptr->common.num_args != 1) { + zend_error(error_type, "Method %v::%s() must take exactly 1 arguments", ce->name, ZEND_UNSET_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1) && fptr->common.num_args != 1) { + zend_error(error_type, "Method %v::%s() must take exactly 1 arguments", ce->name, ZEND_ISSET_FUNC_NAME); + } else if (lcname_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1) && fptr->common.num_args != 2) { + zend_error(error_type, "Method %v::%s() must take exactly 2 arguments", ce->name, ZEND_CALL_FUNC_NAME); } + efree(lcname); } /* registers all functions in *library_functions in the function hash */ @@ -1444,7 +1878,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, zend_function_entr internal_function->type = ZEND_INTERNAL_FUNCTION; if (scope) { - class_name_len = strlen(scope->name); + class_name_len = scope->name_length; lc_class_name = zend_str_tolower_dup(scope->name, class_name_len); } @@ -1473,7 +1907,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, zend_function_entr } if (ptr->flags) { if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { - zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : "", scope ? "::" : "", ptr->fname); + zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : EMPTY_STR, scope ? "::" : "", ptr->fname); internal_function->fn_flags = ZEND_ACC_PUBLIC; } else { internal_function->fn_flags = ptr->flags; @@ -1498,7 +1932,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, zend_function_entr return FAILURE; } if (!internal_function->handler) { - zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name : "", scope ? "::" : "", ptr->fname); + zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name : EMPTY_STR, scope ? "::" : "", ptr->fname); zend_unregister_functions(functions, count, target_function_table TSRMLS_CC); return FAILURE; } @@ -1550,11 +1984,11 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, zend_function_entr } if (unload) { /* before unloading, display all remaining bad function in the module */ if (scope) { - efree(lc_class_name); + free_alloca(lc_class_name); } while (ptr->fname) { if (zend_hash_exists(target_function_table, ptr->fname, strlen(ptr->fname)+1)) { - zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name : "", scope ? "::" : "", ptr->fname); + zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name : EMPTY_STR, scope ? "::" : "", ptr->fname); } ptr++; } @@ -1694,9 +2128,9 @@ void module_destructor(zend_module_entry *module) #if HAVE_LIBDL || defined(HAVE_MACH_O_DYLD_H) #if !(defined(NETWARE) && defined(APACHE_1_BUILD)) - if (module->handle) { - DL_UNLOAD(module->handle); - } + if (module->handle) { + DL_UNLOAD(module->handle); + } #endif #endif } @@ -1832,21 +2266,21 @@ ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *or ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...) { - HashTable *symbol_table; - va_list symbol_table_list; + HashTable *symbol_table; + va_list symbol_table_list; - if (num_symbol_tables <= 0) return FAILURE; + if (num_symbol_tables <= 0) return FAILURE; - symbol->is_ref = is_ref; + symbol->is_ref = is_ref; - va_start(symbol_table_list, num_symbol_tables); - while (num_symbol_tables-- > 0) { - symbol_table = va_arg(symbol_table_list, HashTable *); - zend_hash_update(symbol_table, name, name_length + 1, &symbol, sizeof(zval *), NULL); - zval_add_ref(&symbol); - } - va_end(symbol_table_list); - return SUCCESS; + va_start(symbol_table_list, num_symbol_tables); + while (num_symbol_tables-- > 0) { + symbol_table = va_arg(symbol_table_list, HashTable *); + zend_hash_update(symbol_table, name, name_length + 1, &symbol, sizeof(zval *), NULL); + zval_add_ref(&symbol); + } + va_end(symbol_table_list); + return SUCCESS; } @@ -1856,7 +2290,7 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length, ZEND_API ZEND_FUNCTION(display_disabled_function) { - zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "%v() has been disabled for security reasons", get_active_function_name(TSRMLS_C)); } @@ -1881,8 +2315,8 @@ static zend_object_value display_disabled_class(zend_class_entry *class_type TSR zend_object *intern; retval = zend_objects_new(&intern, class_type TSRMLS_CC); ALLOC_HASHTABLE(intern->properties); - zend_hash_init(intern->properties, 0, NULL, ZVAL_PTR_DTOR, 0); - zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name); + zend_u_hash_init(intern->properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); + zend_error(E_WARNING, "%v() has been disabled for security reasons", class_type->name); return retval; } @@ -1907,6 +2341,7 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC) { + unsigned int lcname_len; char *lcname; zend_bool retval = 0; int callable_name_len_local; @@ -1927,16 +2362,22 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** switch (Z_TYPE_P(callable)) { case IS_STRING: + case IS_UNICODE: if (callable_name) { - *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); - *callable_name_len = Z_STRLEN_P(callable); + /* UTODO: we need to return callable name type as well */ + if (Z_TYPE_P(callable) == IS_UNICODE) { + *callable_name = (char*)eustrndup(Z_USTRVAL_P(callable), Z_USTRLEN_P(callable)); + } else { + *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); + } + *callable_name_len = Z_UNILEN_P(callable); } if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { return 1; } - lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); - if (zend_hash_find(EG(function_table), lcname, Z_STRLEN_P(callable)+1, (void**)fptr_ptr) == SUCCESS) { + lcname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(callable), lcname, lcname_len+1, (void**)fptr_ptr) == SUCCESS) { retval = 1; } efree(lcname); @@ -1951,10 +2392,13 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2 && zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj) == SUCCESS && zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method) == SUCCESS && - (Z_TYPE_PP(obj) == IS_OBJECT || Z_TYPE_PP(obj) == IS_STRING) && - Z_TYPE_PP(method) == IS_STRING) { + (Z_TYPE_PP(obj) == IS_OBJECT || + Z_TYPE_PP(obj) == IS_STRING || + Z_TYPE_PP(obj) == IS_UNICODE) && + (Z_TYPE_PP(method) == IS_STRING || + Z_TYPE_PP(method) == IS_UNICODE)) { - if (Z_TYPE_PP(obj) == IS_STRING) { + if (Z_TYPE_PP(obj) == IS_STRING || Z_TYPE_PP(obj) == IS_UNICODE) { if (callable_name) { char *ptr; @@ -1970,13 +2414,17 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) return 1; - lcname = zend_str_tolower_dup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj)); + lcname = zend_u_str_case_fold(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), 1, &lcname_len); - if (EG(active_op_array) && strcmp(lcname, "self") == 0) { + if (EG(active_op_array) && + lcname_len == sizeof("self")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "self", sizeof("self")-1)) { ce = EG(active_op_array)->scope; - } else if (strcmp(lcname, "parent") == 0 && EG(active_op_array) && EG(active_op_array)->scope) { + } else if (EG(active_op_array) && EG(active_op_array)->scope && + lcname_len == sizeof("parent")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "parent", sizeof("parent")-1)) { ce = EG(active_op_array)->scope->parent; - } else if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) { + } else if (zend_u_lookup_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) { ce = *pce; } @@ -2005,8 +2453,8 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** if (ce) { zend_function *fbc; - lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), Z_STRLEN_PP(method)); - if (zend_hash_find(&ce->function_table, lcname, Z_STRLEN_PP(method)+1, (void **)&fbc) == SUCCESS) { + lcname = zend_u_str_case_fold(Z_TYPE_PP(method), Z_STRVAL_PP(method), Z_STRLEN_PP(method), 1, &lcname_len); + if (zend_u_hash_find(&ce->function_table, Z_TYPE_PP(method), lcname, lcname_len+1, (void **)&fbc) == SUCCESS) { retval = 1; if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) { if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) { @@ -2105,19 +2553,13 @@ ZEND_API char *zend_get_module_version(char *module_name) zend_module_entry *module; if (zend_hash_find(&module_registry, module_name, strlen(module_name) + 1, - (void**)&module) == FAILURE) { + (void**)&module) == FAILURE) { return NULL; } - return module->version; -} - - -ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC) -{ - return zend_declare_property_ex(ce, name, name_length, property, access_type, NULL, 0 TSRMLS_CC); + return module->version; } -ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) +ZEND_API int zend_u_declare_property_ex(zend_class_entry *ce, zend_uchar type, void *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) { zend_property_info property_info; HashTable *target_symbol_table; @@ -2147,8 +2589,8 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name char *priv_name; int priv_name_length; - zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS); - zend_hash_update(target_symbol_table, priv_name, priv_name_length+1, &property, sizeof(zval *), NULL); + zend_u_mangle_property_name(&priv_name, &priv_name_length, type, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS); + zend_u_hash_update(target_symbol_table, type, priv_name, priv_name_length+1, &property, sizeof(zval *), NULL); property_info.name = priv_name; property_info.name_length = priv_name_length; } @@ -2157,8 +2599,8 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name char *prot_name; int prot_name_length; - zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); - zend_hash_update(target_symbol_table, prot_name, prot_name_length+1, &property, sizeof(zval *), NULL); + zend_u_mangle_property_name(&prot_name, &prot_name_length, type, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); + zend_u_hash_update(target_symbol_table, type, prot_name, prot_name_length+1, &property, sizeof(zval *), NULL); property_info.name = prot_name; property_info.name_length = prot_name_length; } @@ -2168,26 +2610,43 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name char *prot_name; int prot_name_length; - zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); - zend_hash_del(target_symbol_table, prot_name, prot_name_length+1); + zend_u_mangle_property_name(&prot_name, &prot_name_length, type, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); + zend_u_hash_del(target_symbol_table, type, prot_name, prot_name_length+1); pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); } - zend_hash_update(target_symbol_table, name, name_length+1, &property, sizeof(zval *), NULL); - property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length); + zend_u_hash_update(target_symbol_table, type, name, name_length+1, &property, sizeof(zval *), NULL); + property_info.name = ce->type & ZEND_INTERNAL_CLASS ? + (type==IS_UNICODE?(char*)zend_ustrndup(name, name_length):zend_strndup(name, name_length)) : + (type==IS_UNICODE?(char*)eustrndup(name, name_length):estrndup(name, name_length)); property_info.name_length = name_length; break; } property_info.flags = access_type; - property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1); + property_info.h = zend_u_get_hash_value(type, property_info.name, property_info.name_length+1); property_info.doc_comment = doc_comment; property_info.doc_comment_len = doc_comment_len; - zend_hash_update(&ce->properties_info, name, name_length + 1, &property_info, sizeof(zend_property_info), NULL); + zend_u_hash_update(&ce->properties_info, type, name, name_length + 1, &property_info, sizeof(zend_property_info), NULL); return SUCCESS; } +ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) +{ + return zend_u_declare_property_ex(ce, IS_STRING, name, name_length, property, access_type, NULL, 0 TSRMLS_CC); +} + +ZEND_API int zend_u_declare_property(zend_class_entry *ce, zend_uchar type, void *name, int name_length, zval *property, int access_type TSRMLS_DC) +{ + return zend_u_declare_property_ex(ce, type, name, name_length, property, access_type, NULL, 0 TSRMLS_CC); +} + +ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC) +{ + return zend_u_declare_property_ex(ce, IS_STRING, name, name_length, property, access_type, NULL, 0 TSRMLS_CC); +} + ZEND_API int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length, int access_type TSRMLS_DC) { zval *property; @@ -2287,7 +2746,7 @@ ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char * zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); - zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", name, class_name); + zend_error(E_CORE_ERROR, "Property %s of class %v cannot be updated", name, class_name); } ZVAL_STRINGL(&property, name, name_length, 0); Z_OBJ_HT_P(object)->write_property(object, &property, value TSRMLS_CC); @@ -2373,7 +2832,7 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *n zend_uint class_name_len; zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); - zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", name, class_name); + zend_error(E_CORE_ERROR, "Property %s of class %v cannot be read", name, class_name); } ZVAL_STRINGL(&property, name, name_length, 0); value = Z_OBJ_HT_P(object)->read_property(object, &property, silent TSRMLS_CC); @@ -2382,6 +2841,50 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *n return value; } +ZEND_API zend_class_entry* zend_get_named_class_entry(char* name, int name_length TSRMLS_DC) +{ + zend_class_entry **scope; + char *lcname = do_alloca(name_length+1); + + zend_str_tolower_copy(lcname, name, name_length); + if (zend_hash_find(CG(class_table), lcname, name_length+1, (void**)&scope) == FAILURE) { + free_alloca(lcname); + zend_error(E_ERROR, "Class '%s' is not defined", name); + return NULL; + } + free_alloca(lcname); + return *scope; +} + + +/* + * Return the most precise string type out of the list. + * If none of the types are string types, IS_STRING is returned. + * Binary > Unicode > string. + */ +ZEND_API zend_uchar zend_get_best_string_type(int num_args, ...) +{ + va_list ap; + int best_type = IS_STRING; + int type; + + if (num_args <= 0) return -1; + + va_start(ap, num_args); + while (num_args--) { + type = va_arg(ap, int); + if (type == IS_BINARY) { + best_type = IS_BINARY; + break; + } else if (type == IS_UNICODE && best_type == IS_STRING) { + best_type = IS_UNICODE; + } + } + va_end(ap); + + return best_type; +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_API.h b/Zend/zend_API.h index d42c914512..38b4a9f199 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -126,6 +126,8 @@ typedef struct _zend_function_entry { class_container.constructor = NULL; \ class_container.destructor = NULL; \ class_container.clone = NULL; \ + class_container.serialize = NULL; \ + class_container.unserialize = NULL; \ class_container.create_object = NULL; \ class_container.interface_gets_implemented = NULL; \ class_container.__call = handle_fcall; \ @@ -212,6 +214,8 @@ ZEND_API int zend_declare_property_double(zend_class_entry *ce, char *name, int ZEND_API int zend_declare_property_string(zend_class_entry *ce, char *name, int name_length, char *value, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, char *name, int name_length, char *value, int value_len, int access_type TSRMLS_DC); +ZEND_API int zend_u_declare_property(zend_class_entry *ce, zend_uchar type, void *name, int name_length, zval *property, int access_type TSRMLS_DC); + ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC); ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC); ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, char *name, int name_length TSRMLS_DC); @@ -225,6 +229,7 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *n ZEND_API zend_class_entry *zend_get_class_entry(zval *zobject TSRMLS_DC); ZEND_API int zend_get_object_classname(zval *object, char **class_name, zend_uint *class_name_len TSRMLS_DC); +ZEND_API zend_uchar zend_get_best_string_type(int num_args, ...); #define getThis() (this_ptr) @@ -260,6 +265,8 @@ ZEND_API int add_assoc_resource_ex(zval *arg, char *key, uint key_len, int r); ZEND_API int add_assoc_double_ex(zval *arg, char *key, uint key_len, double d); ZEND_API int add_assoc_string_ex(zval *arg, char *key, uint key_len, char *str, int duplicate); ZEND_API int add_assoc_stringl_ex(zval *arg, char *key, uint key_len, char *str, uint length, int duplicate); +ZEND_API int add_assoc_unicode_ex(zval *arg, char *key, uint key_len, void *str, int duplicate); +ZEND_API int add_assoc_unicodel_ex(zval *arg, char *key, uint key_len, void *str, uint length, int duplicate); ZEND_API int add_assoc_zval_ex(zval *arg, char *key, uint key_len, zval *value); #define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key)+1, __n) @@ -269,8 +276,14 @@ ZEND_API int add_assoc_zval_ex(zval *arg, char *key, uint key_len, zval *value); #define add_assoc_double(__arg, __key, __d) add_assoc_double_ex(__arg, __key, strlen(__key)+1, __d) #define add_assoc_string(__arg, __key, __str, __duplicate) add_assoc_string_ex(__arg, __key, strlen(__key)+1, __str, __duplicate) #define add_assoc_stringl(__arg, __key, __str, __length, __duplicate) add_assoc_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate) +#define add_assoc_unicode(__arg, __key, __str, __duplicate) add_assoc_unicode_ex(__arg, __key, strlen(__key)+1, __str, __duplicate) +#define add_assoc_unicodel(__arg, __key, __str, __length, __duplicate) add_assoc_unicodel_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate) #define add_assoc_zval(__arg, __key, __value) add_assoc_zval_ex(__arg, __key, strlen(__key)+1, __value) +ZEND_API int add_u_assoc_zval_ex(zval *arg, zend_uchar type, void *key, uint key_len, zval *value); + +#define add_u_assoc_zval(__arg, __type, __key, __value) add_u_assoc_zval_ex(__arg, __type, __key, (((__type)==IS_UNICODE)?u_strlen((UChar*)__key):strlen(__key))+1, __value) + /* unset() functions are only suported for legacy modules and null() functions should be used */ #define add_assoc_unset(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key) + 1) #define add_index_unset(__arg, __key) add_index_null(__arg, __key) @@ -284,6 +297,10 @@ ZEND_API int add_index_resource(zval *arg, uint idx, int r); ZEND_API int add_index_double(zval *arg, uint idx, double d); ZEND_API int add_index_string(zval *arg, uint idx, char *str, int duplicate); ZEND_API int add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate); +ZEND_API int add_index_binary(zval *arg, uint idx, char *str, int duplicate); +ZEND_API int add_index_binaryl(zval *arg, uint idx, char *str, uint length, int duplicate); +ZEND_API int add_index_unicode(zval *arg, uint idx, UChar *str, int duplicate); +ZEND_API int add_index_unicodel(zval *arg, uint idx, UChar *str, uint length, int duplicate); ZEND_API int add_index_zval(zval *arg, uint index, zval *value); ZEND_API int add_next_index_long(zval *arg, long n); @@ -293,6 +310,10 @@ ZEND_API int add_next_index_resource(zval *arg, int r); ZEND_API int add_next_index_double(zval *arg, double d); ZEND_API int add_next_index_string(zval *arg, char *str, int duplicate); ZEND_API int add_next_index_stringl(zval *arg, char *str, uint length, int duplicate); +ZEND_API int add_next_index_binary(zval *arg, char *str, int duplicate); +ZEND_API int add_next_index_binaryl(zval *arg, char *str, uint length, int duplicate); +ZEND_API int add_next_index_unicode(zval *arg, UChar *str, int duplicate); +ZEND_API int add_next_index_unicodel(zval *arg, UChar *str, uint length, int duplicate); ZEND_API int add_next_index_zval(zval *arg, zval *value); ZEND_API int add_get_assoc_string_ex(zval *arg, char *key, uint key_len, char *str, void **dest, int duplicate); @@ -305,6 +326,10 @@ ZEND_API int add_get_index_long(zval *arg, uint idx, long l, void **dest); ZEND_API int add_get_index_double(zval *arg, uint idx, double d, void **dest); ZEND_API int add_get_index_string(zval *arg, uint idx, char *str, void **dest, int duplicate); ZEND_API int add_get_index_stringl(zval *arg, uint idx, char *str, uint length, void **dest, int duplicate); +ZEND_API int add_get_index_binary(zval *arg, uint idx, char *str, void **dest, int duplicate); +ZEND_API int add_get_index_binaryl(zval *arg, uint idx, char *str, uint length, void **dest, int duplicate); +ZEND_API int add_get_index_unicode(zval *arg, uint idx, UChar *str, void **dest, int duplicate); +ZEND_API int add_get_index_unicodel(zval *arg, uint idx, UChar *str, uint length, void **dest, int duplicate); ZEND_API int add_property_long_ex(zval *arg, char *key, uint key_len, long l TSRMLS_DC); ZEND_API int add_property_null_ex(zval *arg, char *key, uint key_len TSRMLS_DC); @@ -358,6 +383,9 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...); ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC); +ZEND_API int zend_u_delete_global_variable(zend_uchar type, void *name, int name_len TSRMLS_DC); + +ZEND_API zend_class_entry* zend_get_named_class_entry(char* name, int name_length TSRMLS_DC); ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC); @@ -367,14 +395,24 @@ ZEND_API ZEND_FUNCTION(display_disabled_function); ZEND_API ZEND_FUNCTION(display_disabled_class); END_EXTERN_C() + +#define BINARY_TYPE (UG(unicode) ? IS_BINARY : IS_STRING) + + #if ZEND_DEBUG #define CHECK_ZVAL_STRING(z) \ if ((z)->value.str.val[ (z)->value.str.len ] != '\0') { zend_error(E_WARNING, "String is not zero-terminated (%s)", (z)->value.str.val); } #define CHECK_ZVAL_STRING_REL(z) \ if ((z)->value.str.val[ (z)->value.str.len ] != '\0') { zend_error(E_WARNING, "String is not zero-terminated (%s) (source: %s:%d)", (z)->value.str.val ZEND_FILE_LINE_RELAY_CC); } +#define CHECK_ZVAL_UNICODE(z) \ + if ((z)->value.ustr.val[ (z)->value.ustr.len ] != 0 ) { zend_error(E_WARNING, "String is not zero-terminated"); } +#define CHECK_ZVAL_UNICODE_REL(z) \ + if ((z)->value.ustr.val[ (z)->value.ustr.len ] != 0) { zend_error(E_WARNING, "String is not zero-terminated (source: %s:%d)", ZEND_FILE_LINE_RELAY_C); } #else #define CHECK_ZVAL_STRING(z) #define CHECK_ZVAL_STRING_REL(z) +#define CHECK_ZVAL_UNICODE(z) +#define CHECK_ZVAL_UNICODE_REL(z) #endif #define ZVAL_RESOURCE(z, l) { \ @@ -415,12 +453,52 @@ END_EXTERN_C() (z)->type = IS_STRING; \ } +#define ZVAL_UNICODE(z, u, duplicate) { \ + UChar *__u=(u); \ + (z)->value.ustr.len = u_strlen(__u); \ + (z)->value.ustr.val = (duplicate?eustrndup(__u, (z)->value.ustr.len):__u); \ + (z)->type = IS_UNICODE; \ +} + +#define ZVAL_UNICODEL(z, u, l, duplicate) { \ + UChar *__u=(u); int32_t __l=l; \ + (z)->value.ustr.len = __l; \ + (z)->value.ustr.val = (duplicate?eustrndup(__u, __l):__u); \ + (z)->type = IS_UNICODE; \ +} + +#define ZVAL_BINARY(z, s, duplicate) { \ + char *__s=(s); \ + (z)->value.str.len = strlen(__s); \ + (z)->value.str.val = (duplicate?estrndup(__s, (z)->value.str.len):__s); \ + (z)->type = BINARY_TYPE; \ + } + +#define ZVAL_BINARYL(z, s, l, duplicate) { \ + char *__s=(s); int __l=l; \ + (z)->value.str.len = __l; \ + (z)->value.str.val = (duplicate?estrndup(__s, __l):__s); \ + (z)->type = BINARY_TYPE; \ + } + #define ZVAL_EMPTY_STRING(z) { \ (z)->value.str.len = 0; \ (z)->value.str.val = STR_EMPTY_ALLOC(); \ (z)->type = IS_STRING; \ } +#define ZVAL_EMPTY_UNICODE(z) { \ + (z)->value.ustr.len = 0; \ + (z)->value.ustr.val = USTR_MAKE(""); \ + (z)->type = IS_UNICODE; \ + } + +#define ZVAL_EMPTY_BINARY(z) { \ + (z)->value.str.len = 0; \ + (z)->value.str.val = STR_EMPTY_ALLOC(); \ + (z)->type = BINARY_TYPE; \ + } + #define ZVAL_ZVAL(z, zv, copy, dtor) { \ int is_ref, refcount; \ is_ref = (z)->is_ref; \ @@ -450,9 +528,32 @@ END_EXTERN_C() #define RETVAL_STRING(s, duplicate) ZVAL_STRING(return_value, s, duplicate) #define RETVAL_STRINGL(s, l, duplicate) ZVAL_STRINGL(return_value, s, l, duplicate) #define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value) +#define RETVAL_UNICODE(u, duplicate) ZVAL_UNICODE(return_value, u, duplicate) +#define RETVAL_UNICODEL(u, l, duplicate) ZVAL_UNICODEL(return_value, u, l, duplicate) +#define RETVAL_EMPTY_UNICODE() ZVAL_EMPTY_UNICODE(return_value) +#define RETVAL_BINARY(s, duplicate) ZVAL_BINARY(return_value, s, duplicate) +#define RETVAL_BINARYL(s, l, duplicate) ZVAL_BINARYL(return_value, s, l, duplicate) +#define RETVAL_EMPTY_BINARY() ZVAL_EMPTY_BINARY(return_value) #define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor) #define RETVAL_FALSE ZVAL_BOOL(return_value, 0) #define RETVAL_TRUE ZVAL_BOOL(return_value, 1) +#define RETVAL_TEXT(t, duplicate) \ + do { \ + if (UG(unicode)) { \ + RETVAL_UNICODE(t, duplicate); \ + } else { \ + RETVAL_STRING(t, duplicate); \ + } \ + } while (0); + +#define RETVAL_TEXTL(t, l, duplicate) \ + do { \ + if (UG(unicode)) { \ + RETVAL_UNICODEL(t, l, duplicate); \ + } else { \ + RETVAL_STRINGL(t, l, duplicate); \ + } \ + } while (0); #define RETURN_RESOURCE(l) { RETVAL_RESOURCE(l); return; } #define RETURN_BOOL(b) { RETVAL_BOOL(b); return; } @@ -462,9 +563,17 @@ END_EXTERN_C() #define RETURN_STRING(s, duplicate) { RETVAL_STRING(s, duplicate); return; } #define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; } #define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; } +#define RETURN_UNICODE(u, duplicate) { RETVAL_UNICODE(u, duplicate); return; } +#define RETURN_UNICODEL(u, l, duplicate) { RETVAL_UNICODEL(u, l, duplicate); return; } +#define RETURN_EMPTY_UNICODE() { RETVAL_EMPTY_UNICODE(); return; } +#define RETURN_BINARY(s, duplicate) { RETVAL_BINARY(s, duplicate); return; } +#define RETURN_BINARYL(s, l, duplicate) { RETVAL_BINARYL(s, l, duplicate); return; } +#define RETURN_EMPTY_BINARY() { RETVAL_EMPTY_BINARY(); return; } #define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } #define RETURN_FALSE { RETVAL_FALSE; return; } #define RETURN_TRUE { RETVAL_TRUE; return; } +#define RETURN_TEXT(t, duplicate) { RETVAL_TEXT(t, duplicate); return; } +#define RETURN_TEXTL(t, l, duplicate) { RETVAL_TEXTL(t, l, duplicate); return; } #define SET_VAR_STRING(n, v) { \ { \ diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index f77c54ef9c..26b41adf51 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -23,6 +23,7 @@ #include "zend_alloc.h" #include "zend_globals.h" #include "zend_fast_cache.h" +#include "zend_unicode.h" #ifdef HAVE_SIGNAL_H # include #endif @@ -409,6 +410,24 @@ ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) return p; } +ZEND_API UChar *_eustrdup(const UChar *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +{ + int length; + UChar *p; + + length = u_strlen(s)+1; + HANDLE_BLOCK_INTERRUPTIONS(); + p = (UChar *) _emalloc(sizeof(UChar) * length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + if (!p) { + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (UChar *)NULL; + } + HANDLE_UNBLOCK_INTERRUPTIONS(); + u_memcpy(p, s, length); + return p; +} + + ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { char *p; @@ -426,6 +445,23 @@ ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_ } +ZEND_API UChar *_eustrndup(const UChar *s, int32_t length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +{ + UChar *p; + + HANDLE_BLOCK_INTERRUPTIONS(); + p = (UChar *) _emalloc(sizeof(UChar) * (length+1) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + if (!p) { + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (UChar *)NULL; + } + HANDLE_UNBLOCK_INTERRUPTIONS(); + memcpy(p, s, length * sizeof(UChar)); + p[length] = 0; + return p; +} + + ZEND_API char *zend_strndup(const char *s, uint length) { char *p; @@ -441,6 +477,21 @@ ZEND_API char *zend_strndup(const char *s, uint length) return p; } +ZEND_API UChar *zend_ustrndup(const UChar *s, uint length) +{ + UChar *p; + + p = (UChar *) malloc(UBYTES(length+1)); + if (!p) { + return (UChar *)NULL; + } + if (length) { + memcpy(p, s, UBYTES(length)); + } + p[length] = 0; + return p; +} + ZEND_API int zend_set_memory_limit(unsigned int memory_limit) { diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h index 6d4b58192f..fc0edf0a4d 100644 --- a/Zend/zend_alloc.h +++ b/Zend/zend_alloc.h @@ -28,6 +28,7 @@ #include "zend_globals_macros.h" #include "zend_mm.h" +#include #define MEM_BLOCK_START_MAGIC 0x7312F8DCL #define MEM_BLOCK_END_MAGIC 0x2A8FCC84L @@ -75,6 +76,7 @@ typedef union _align_test { BEGIN_EXTERN_C() ZEND_API char *zend_strndup(const char *s, unsigned int length) ZEND_ATTRIBUTE_MALLOC; +ZEND_API UChar *zend_ustrndup(const UChar *s, uint length) ZEND_ATTRIBUTE_MALLOC; ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; @@ -84,6 +86,8 @@ ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LI ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; ZEND_API char *_estrndup(const char *s, unsigned int length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; +ZEND_API UChar *_eustrdup(const UChar *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; +ZEND_API UChar *_eustrndup(const UChar *s, int32_t length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; #if USE_ZEND_ALLOC @@ -96,16 +100,23 @@ ZEND_API char *_estrndup(const char *s, unsigned int length ZEND_FILE_LINE_DC ZE #define erealloc_recoverable(ptr, size) _erealloc((ptr), (size), 1 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) #define estrdup(s) _estrdup((s) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) #define estrndup(s, length) _estrndup((s), (length) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) +#define eumalloc(size) (UChar*)_emalloc(UBYTES(size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) +#define eurealloc(ptr, size) (UChar*)_erealloc((ptr), UBYTES(size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) +#define eustrndup(s, length) _eustrndup((s), (length) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) +#define eustrdup(s) _eustrdup((s) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) /* Relay wrapper macros */ #define emalloc_rel(size) _emalloc((size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define safe_emalloc_rel(nmemb, size, offset) _safe_emalloc((nmemb), (size), (offset) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define efree_rel(ptr) _efree((ptr) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define ecalloc_rel(nmemb, size) _ecalloc((nmemb), (size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) -#define erealloc_rel(ptr, size) _erealloc((ptr), (size), 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) +#define erealloc_rel(ptr, size) _erealloc((ptr), (size), 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define erealloc_recoverable_rel(ptr, size) _erealloc((ptr), (size), 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define estrdup_rel(s) _estrdup((s) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) #define estrndup_rel(s, length) _estrndup((s), (length) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) +#define eumalloc_rel(size) (UChar*)_emalloc(UBYTES(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) +#define eurealloc_rel(ptr, size) (UChar*)_erealloc((ptr), UBYTES(size), 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) +#define eustrndup_rel(s, length) _eustrndup((s), (length) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC) /* Selective persistent/non persistent allocation macros */ #define pemalloc(size, persistent) ((persistent)?malloc(size):emalloc(size)) @@ -115,6 +126,8 @@ ZEND_API char *_estrndup(const char *s, unsigned int length ZEND_FILE_LINE_DC ZE #define perealloc(ptr, size, persistent) ((persistent)?realloc((ptr), (size)):erealloc((ptr), (size))) #define perealloc_recoverable(ptr, size, persistent) ((persistent)?realloc((ptr), (size)):erealloc_recoverable((ptr), (size))) #define pestrdup(s, persistent) ((persistent)?strdup(s):estrdup(s)) +#define peumalloc(size, persistent) ((persistent)?malloc(UBYTES(size)):eumalloc(size)) +#define peurealloc(ptr, size, persistent) ((persistent)?realloc((ptr),UBYTES(size)):eurealloc((ptr),size)) #define pemalloc_rel(size, persistent) ((persistent)?malloc(size):emalloc_rel(size)) #define pefree_rel(ptr, persistent) ((persistent)?free(ptr):efree_rel(ptr)) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 0506d5f263..c1ca31c25e 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -279,8 +279,27 @@ ZEND_NAMED_FUNCTION(zend_if_strlen) if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) { ZEND_WRONG_PARAM_COUNT(); } - convert_to_string_ex(str); - RETVAL_LONG((*str)->value.str.len); + + switch (Z_TYPE_PP(str)) { + case IS_UNICODE: + RETVAL_LONG(u_countChar32(Z_USTRVAL_PP(str), Z_USTRLEN_PP(str))); + break; + + case IS_STRING: + case IS_BINARY: + RETVAL_LONG(Z_STRLEN_PP(str)); + break; + + default: + if (UG(unicode)) { + convert_to_unicode_ex(str); + RETVAL_LONG(Z_USTRLEN_PP(str)); + } else { + convert_to_string_ex(str); + RETVAL_LONG(Z_STRLEN_PP(str)); + } + break; + } } /* }}} */ @@ -396,6 +415,12 @@ ZEND_FUNCTION(each) case HASH_KEY_IS_STRING: add_get_index_stringl(return_value, 0, string_key, string_key_len-1, (void **) &inserted_pointer, 0); break; + case HASH_KEY_IS_BINARY: + add_get_index_binaryl(return_value, 0, string_key, string_key_len-1, (void **) &inserted_pointer, 0); + break; + case HASH_KEY_IS_UNICODE: + add_get_index_unicodel(return_value, 0, (UChar*)string_key, string_key_len-1, (void **) &inserted_pointer, 0); + break; case HASH_KEY_IS_LONG: add_get_index_long(return_value, 0, num_key, (void **) &inserted_pointer); break; @@ -470,6 +495,8 @@ ZEND_FUNCTION(define) case IS_LONG: case IS_DOUBLE: case IS_STRING: + case IS_BINARY: + case IS_UNICODE: case IS_BOOL: case IS_RESOURCE: case IS_NULL: @@ -479,15 +506,22 @@ ZEND_FUNCTION(define) RETURN_FALSE; break; } - convert_to_string_ex(var); + + if (Z_TYPE_PP(var) != IS_STRING && Z_TYPE_PP(var) != IS_UNICODE) { + convert_to_string_ex(var); + } c.value = **val; zval_copy_ctor(&c.value); c.flags = case_sensitive; /* non persistent */ - c.name = zend_strndup((*var)->value.str.val, (*var)->value.str.len); - c.name_len = (*var)->value.str.len+1; + if (Z_TYPE_PP(var) == IS_UNICODE) { + c.name = (char*)zend_ustrndup(Z_USTRVAL_PP(var), Z_USTRLEN_PP(var)); + } else { + c.name = zend_strndup(Z_STRVAL_PP(var), Z_STRLEN_PP(var)); + } + c.name_len = Z_UNILEN_PP(var)+1; c.module_number = PHP_USER_CONSTANT; - if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) { + if (zend_u_register_constant(Z_TYPE_PP(var), &c TSRMLS_CC) == SUCCESS) { RETURN_TRUE; } else { RETURN_FALSE; @@ -507,8 +541,8 @@ ZEND_FUNCTION(defined) ZEND_WRONG_PARAM_COUNT(); } - convert_to_string_ex(var); - if (zend_get_constant((*var)->value.str.val, (*var)->value.str.len, &c TSRMLS_CC)) { + convert_to_text_ex(var); + if (zend_get_constant(Z_UNIVAL_PP(var), Z_UNILEN_PP(var), &c TSRMLS_CC)) { zval_dtor(&c); RETURN_TRUE; } else { @@ -523,13 +557,17 @@ ZEND_FUNCTION(defined) ZEND_FUNCTION(get_class) { zval **arg; - char *name = ""; + char *name = EMPTY_STR; zend_uint name_len = 0; int dup; if (!ZEND_NUM_ARGS()) { if (EG(scope)) { - RETURN_STRINGL(EG(scope)->name, EG(scope)->name_length, 1); + if (UG(unicode)) { + RETURN_UNICODEL((UChar*)EG(scope)->name, EG(scope)->name_length, 1); + } else { + RETURN_STRINGL(EG(scope)->name, EG(scope)->name_length, 1); + } } else { zend_error(E_ERROR, "get_class() called without object from outside a class"); } @@ -543,7 +581,11 @@ ZEND_FUNCTION(get_class) dup = zend_get_object_classname(*arg, &name, &name_len TSRMLS_CC); - RETURN_STRINGL(name, name_len, dup); + if (UG(unicode)) { + RETURN_UNICODEL((UChar*)name, name_len, 0); + } else { + RETURN_STRINGL(name, name_len, 0); + } } /* }}} */ @@ -560,7 +602,11 @@ ZEND_FUNCTION(get_parent_class) if (!ZEND_NUM_ARGS()) { ce = EG(scope); if (ce && ce->parent) { - RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1); + if (UG(unicode)) { + RETURN_UNICODEL((UChar*)ce->parent->name, ce->parent->name_length, 1); + } else { + RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1); + } } else { RETURN_FALSE; } @@ -572,20 +618,28 @@ ZEND_FUNCTION(get_parent_class) if (Z_TYPE_PP(arg) == IS_OBJECT) { if (Z_OBJ_HT_PP(arg)->get_class_name && Z_OBJ_HT_PP(arg)->get_class_name(*arg, &name, &name_length, 1 TSRMLS_CC) == SUCCESS) { - RETURN_STRINGL(name, name_length, 0); + if (UG(unicode)) { + RETURN_UNICODEL((UChar*)name, name_length, 0); + } else{ + RETURN_STRINGL(name, name_length, 0); + } } else { ce = zend_get_class_entry(*arg TSRMLS_CC); } - } else if (Z_TYPE_PP(arg) == IS_STRING) { + } else if (Z_TYPE_PP(arg) == IS_STRING || Z_TYPE_PP(arg) == IS_UNICODE) { zend_class_entry **pce; - if (zend_lookup_class(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &pce TSRMLS_CC) == SUCCESS) { + if (zend_u_lookup_class(Z_TYPE_PP(arg), Z_UNIVAL_PP(arg), Z_UNILEN_PP(arg), &pce TSRMLS_CC) == SUCCESS) { ce = *pce; } } if (ce && ce->parent) { - RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1); + if (UG(unicode)) { + RETURN_UNICODEL((UChar*)ce->parent->name, ce->parent->name_length, 1); + } else { + RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1); + } } else { RETURN_FALSE; } @@ -606,7 +660,7 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass) if (only_subclass && Z_TYPE_PP(obj) == IS_STRING) { zend_class_entry **the_ce; - if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &the_ce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), &the_ce TSRMLS_CC) == FAILURE) { zend_error(E_WARNING, "Unknown class passed as parameter"); RETURN_FALSE; } @@ -624,7 +678,7 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass) convert_to_string_ex(class_name); - if (zend_lookup_class(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name), &ce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(Z_TYPE_PP(class_name), Z_UNIVAL_PP(class_name), Z_UNILEN_PP(class_name), &ce TSRMLS_CC) == FAILURE) { retval = 0; } else { if (only_subclass) { @@ -686,8 +740,9 @@ static void add_class_vars(zend_class_entry *ce, HashTable *properties, zval *re uint key_len; ulong num_index; zval *prop_copy; + zend_uchar key_type; - zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos); + key_type = zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos); zend_hash_move_forward_ex(properties, &pos); zend_unmangle_property_name(key, &class_name, &prop_name); if (class_name) { @@ -712,7 +767,7 @@ static void add_class_vars(zend_class_entry *ce, HashTable *properties, zval *re zval_update_constant(&prop_copy, 0 TSRMLS_CC); } - add_assoc_zval(return_value, prop_name, prop_copy); + add_u_assoc_zval(return_value, key_type==HASH_KEY_IS_UNICODE?IS_UNICODE:IS_STRING, prop_name, prop_copy); } } } @@ -725,13 +780,14 @@ ZEND_FUNCTION(get_class_vars) { char *class_name; int class_name_len; + zend_uchar type; zend_class_entry **pce; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &class_name, &class_name_len, &type) == FAILURE) { return; } - if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(type, class_name, class_name_len, &pce TSRMLS_CC) == FAILURE) { RETURN_FALSE; } else { array_init(return_value); @@ -774,17 +830,19 @@ ZEND_FUNCTION(get_object_vars) zend_hash_internal_pointer_reset_ex(properties, &pos); while (zend_hash_get_current_data_ex(properties, (void **) &value, &pos) == SUCCESS) { - if (zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos) == HASH_KEY_IS_STRING) { - if (key[0]) { + if (zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos) == (UG(unicode)?HASH_KEY_IS_UNICODE:HASH_KEY_IS_STRING)) { + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, key, &class_name, &prop_name); + if (class_name == NULL) { /* Not separating references */ (*value)->refcount++; - add_assoc_zval_ex(return_value, key, key_len, *value); + add_u_assoc_zval_ex(return_value, UG(unicode)?IS_UNICODE:IS_STRING, key, key_len, *value); } else if (instanceof) { - zend_unmangle_property_name(key, &class_name, &prop_name); - if (!memcmp(class_name, "*", 2) || (Z_OBJCE_P(EG(This)) == Z_OBJCE_PP(obj) && !strcmp(Z_OBJCE_P(EG(This))->name, class_name))) { + if (class_name[0] == '*' || + (Z_OBJCE_P(EG(This)) == Z_OBJCE_PP(obj) && + UG(unicode)?!u_strcmp((UChar*)Z_OBJCE_P(EG(This))->name, (UChar*)class_name):!strcmp(Z_OBJCE_P(EG(This))->name, class_name))) { /* Not separating references */ (*value)->refcount++; - add_assoc_zval_ex(return_value, prop_name, strlen(prop_name)+1, *value); + add_u_assoc_zval(return_value, UG(unicode)?IS_UNICODE:IS_STRING, prop_name, *value); } } } @@ -814,8 +872,8 @@ ZEND_FUNCTION(get_class_methods) RETURN_FALSE; } ce = Z_OBJCE_PP(class); - } else if (Z_TYPE_PP(class) == IS_STRING) { - if (zend_lookup_class(Z_STRVAL_PP(class), Z_STRLEN_PP(class), &pce TSRMLS_CC) == SUCCESS) { + } else if (Z_TYPE_PP(class) == IS_STRING || Z_TYPE_PP(class) == IS_UNICODE) { + if (zend_u_lookup_class(Z_TYPE_PP(class), Z_UNIVAL_PP(class), Z_UNILEN_PP(class), &pce TSRMLS_CC) == SUCCESS) { ce = *pce; } } @@ -835,7 +893,11 @@ ZEND_FUNCTION(get_class_methods) || ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && EG(scope) == mptr->common.scope)))) { MAKE_STD_ZVAL(method_name); - ZVAL_STRING(method_name, mptr->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(method_name, (UChar*)mptr->common.function_name, 1); + } else { + ZVAL_STRING(method_name, mptr->common.function_name, 1); + } zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL); } zend_hash_move_forward_ex(&ce->function_table, &pos); @@ -849,6 +911,7 @@ ZEND_FUNCTION(get_class_methods) ZEND_FUNCTION(method_exists) { zval **klass, **method_name; + unsigned int lcname_len; char *lcname; zend_class_entry * ce, **pce; @@ -867,8 +930,8 @@ ZEND_FUNCTION(method_exists) } convert_to_string_ex(method_name); - lcname = zend_str_tolower_dup(Z_STRVAL_PP(method_name), Z_STRLEN_PP(method_name)); - if (zend_hash_exists(&ce->function_table, lcname, Z_STRLEN_PP(method_name)+1)) { + lcname = zend_u_str_case_fold(Z_TYPE_PP(method_name), Z_UNIVAL_PP(method_name), Z_UNILEN_PP(method_name), 1, &lcname_len); + if (zend_u_hash_exists(&ce->function_table, Z_TYPE_PP(method_name), lcname, lcname_len+1)) { efree(lcname); RETURN_TRUE; } else { @@ -962,26 +1025,26 @@ ZEND_FUNCTION(property_exists) Checks if the class exists */ ZEND_FUNCTION(class_exists) { - char *class_name, *lc_name; + unsigned int lc_name_len; + void *class_name, *lc_name; zend_class_entry **ce; int class_name_len; zend_bool autoload = 1; + zend_uchar type; int found; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &class_name, &class_name_len, &autoload) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|b", &class_name, &class_name_len, &type, &autoload) == FAILURE) { return; } if (!autoload) { - lc_name = do_alloca(class_name_len + 1); - zend_str_tolower_copy(lc_name, class_name, class_name_len); - - found = zend_hash_find(EG(class_table), lc_name, class_name_len+1, (void **) &ce); - free_alloca(lc_name); + lc_name = zend_u_str_case_fold(type, class_name, class_name_len, 1, &lc_name_len); + found = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) &ce); + efree(lc_name); RETURN_BOOL(found == SUCCESS && !((*ce)->ce_flags & ZEND_ACC_INTERFACE)); } - if (zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC) == SUCCESS) { + if (zend_u_lookup_class(type, class_name, class_name_len, &ce TSRMLS_CC) == SUCCESS) { RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0); } else { RETURN_FALSE; @@ -993,26 +1056,26 @@ ZEND_FUNCTION(class_exists) Checks if the class exists */ ZEND_FUNCTION(interface_exists) { - char *iface_name, *lc_name; + unsigned int lc_name_len; + void *iface_name, *lc_name; zend_class_entry **ce; int iface_name_len; + zend_uchar type; zend_bool autoload = 1; int found; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &iface_name, &iface_name_len, &autoload) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|b", &iface_name, &iface_name_len, &type, &autoload) == FAILURE) { return; } if (!autoload) { - lc_name = do_alloca(iface_name_len + 1); - zend_str_tolower_copy(lc_name, iface_name, iface_name_len); - - found = zend_hash_find(EG(class_table), lc_name, iface_name_len+1, (void **) &ce); - free_alloca(lc_name); + lc_name = zend_u_str_case_fold(type, iface_name, iface_name_len, 1, &lc_name_len); + found = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) &ce); + efree(lc_name); RETURN_BOOL(found == SUCCESS && (*ce)->ce_flags & ZEND_ACC_INTERFACE); } - if (zend_lookup_class(iface_name, iface_name_len, &ce TSRMLS_CC) == SUCCESS) { + if (zend_u_lookup_class(type, iface_name, iface_name_len, &ce TSRMLS_CC) == SUCCESS) { RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0); } else { RETURN_FALSE; @@ -1027,6 +1090,7 @@ ZEND_FUNCTION(function_exists) { zval **function_name; zend_function *func; + unsigned int lcname_len; char *lcname; zend_bool retval; @@ -1034,9 +1098,9 @@ ZEND_FUNCTION(function_exists) ZEND_WRONG_PARAM_COUNT(); } convert_to_string_ex(function_name); - lcname = zend_str_tolower_dup((*function_name)->value.str.val, (*function_name)->value.str.len); + lcname = zend_u_str_case_fold(Z_TYPE_PP(function_name), Z_UNIVAL_PP(function_name), Z_UNILEN_PP(function_name), 1, &lcname_len); - retval = (zend_hash_find(EG(function_table), lcname, (*function_name)->value.str.len+1, (void **)&func) == SUCCESS); + retval = (zend_u_hash_find(EG(function_table), Z_TYPE_PP(function_name), lcname, lcname_len+1, (void **)&func) == SUCCESS); efree(lcname); @@ -1283,10 +1347,17 @@ static int copy_class_or_interface_name(zend_class_entry **pce, int num_args, va zend_uint comply = va_arg(args, zend_uint); zend_uint comply_mask = (comply)? mask:0; zend_class_entry *ce = *pce; + TSRMLS_FETCH(); - if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0) + if ((hash_key->nKeyLength==0 || + (hash_key->type == IS_UNICODE && hash_key->u.unicode[0] != 0) || + (hash_key->type == IS_STRING && hash_key->u.string[0] != 0)) && (comply_mask == (ce->ce_flags & mask))) { - add_next_index_stringl(array, ce->name, ce->name_length, 1); + if (UG(unicode)) { + add_next_index_unicodel(array, (UChar*)ce->name, ce->name_length, 1); + } else { + add_next_index_stringl(array, ce->name, ce->name_length, 1); + } } return ZEND_HASH_APPLY_KEEP; } @@ -1330,14 +1401,29 @@ static int copy_function_name(zend_function *func, int num_args, va_list args, z zval *internal_ar = va_arg(args, zval *), *user_ar = va_arg(args, zval *); - if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) { + if (hash_key->nKeyLength == 0 || + hash_key->type == IS_BINARY || + (hash_key->type == IS_UNICODE && hash_key->u.unicode[0] == 0) || + (hash_key->type == IS_STRING && hash_key->u.unicode[0] == 0)) { return 0; } if (func->type == ZEND_INTERNAL_FUNCTION) { - add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); + if (hash_key->type == IS_STRING) { + add_next_index_stringl(internal_ar, hash_key->u.string, hash_key->nKeyLength-1, 1); + } else if (hash_key->type == IS_BINARY) { + add_next_index_binaryl(internal_ar, hash_key->u.string, hash_key->nKeyLength-1, 1); + } else { + add_next_index_unicodel(internal_ar, hash_key->u.unicode, hash_key->nKeyLength-1, 1); + } } else if (func->type == ZEND_USER_FUNCTION) { - add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); + if (hash_key->type == IS_STRING) { + add_next_index_stringl(user_ar, hash_key->u.string, hash_key->nKeyLength-1, 1); + } else if (hash_key->type == IS_BINARY) { + add_next_index_binaryl(user_ar, hash_key->u.string, hash_key->nKeyLength-1, 1); + } else { + add_next_index_unicodel(user_ar, hash_key->u.unicode, hash_key->nKeyLength-1, 1); + } } return 0; @@ -1431,7 +1517,7 @@ ZEND_FUNCTION(create_function) RETURN_FALSE; } new_function = *func; - function_add_ref(&new_function); + function_add_ref(&new_function TSRMLS_CC); function_name = (char *) emalloc(sizeof("0lambda_")+MAX_LENGTH_OF_LONG); @@ -1507,7 +1593,7 @@ static int add_constant_info(zend_constant *constant, void *arg TSRMLS_DC) *const_val = constant->value; zval_copy_ctor(const_val); INIT_PZVAL(const_val); - add_assoc_zval_ex(name_array, constant->name, constant->name_len, const_val); + add_u_assoc_zval_ex(name_array, UG(unicode)?IS_UNICODE:IS_STRING, constant->name, constant->name_len, const_val); return 0; } @@ -1695,6 +1781,7 @@ ZEND_FUNCTION(debug_print_backtrace) while (ptr) { char *free_class_name = NULL; + int function_name_string = 1; class_name = call_type = NULL; arg_array = NULL; @@ -1721,6 +1808,7 @@ ZEND_FUNCTION(debug_print_backtrace) function_name = ptr->function_state.function->common.function_name; if (function_name) { + function_name_string = !UG(unicode); if (ptr->object) { if (ptr->function_state.function->common.scope) { class_name = ptr->function_state.function->common.scope->name; @@ -1791,10 +1879,18 @@ ZEND_FUNCTION(debug_print_backtrace) } zend_printf("#%-2d ", indent); if (class_name) { - ZEND_PUTS(class_name); + if (UG(unicode)) { + zend_printf("%r(", class_name); + } else { + ZEND_PUTS(class_name); + } ZEND_PUTS(call_type); } - zend_printf("%s(", function_name?function_name:"main"); + if (function_name_string) { + zend_printf("%s(", function_name?function_name:"main"); + } else { + zend_printf("%r(", function_name); + } if (arg_array) { debug_print_backtrace_args(arg_array TSRMLS_CC); zval_ptr_dtor(&arg_array); @@ -1898,22 +1994,37 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last TSRML function_name = ptr->function_state.function->common.function_name; if (function_name) { - add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1); + if (UG(unicode)) { + add_assoc_unicode_ex(stack_frame, "function", sizeof("function"), function_name, 1); + } else { + add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1); + } if (ptr->object && Z_TYPE_P(ptr->object) == IS_OBJECT) { if (ptr->function_state.function->common.scope) { - add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + if (UG(unicode)) { + add_assoc_unicode_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + } else { + add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + } } else { zend_uint class_name_len; int dup; dup = zend_get_object_classname(ptr->object, &class_name, &class_name_len TSRMLS_CC); - add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, dup); - + if (UG(unicode)) { + add_assoc_unicode_ex(stack_frame, "class", sizeof("class"), class_name, dup); + } else { + add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, dup); + } } add_assoc_string_ex(stack_frame, "type", sizeof("type"), "->", 1); } else if (ptr->function_state.function->common.scope) { - add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + if (UG(unicode)) { + add_assoc_unicode_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + } else { + add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1); + } add_assoc_string_ex(stack_frame, "type", sizeof("type"), "::", 1); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index a7c09b0a14..86c68cad13 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -27,10 +27,6 @@ #include "zend_API.h" #include "zend_fast_cache.h" -#ifdef ZEND_MULTIBYTE -#include "zend_multibyte.h" -#endif /* ZEND_MULTIBYTE */ - ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); @@ -41,7 +37,13 @@ ZEND_API zend_executor_globals executor_globals; static void zend_duplicate_property_info(zend_property_info *property_info) { - property_info->name = estrndup(property_info->name, property_info->name_length); + TSRMLS_FETCH(); + + if (UG(unicode)) { + property_info->name = (char*)eustrndup((UChar*)property_info->name, property_info->name_length); + } else { + property_info->name = estrndup(property_info->name, property_info->name_length); + } if (property_info->doc_comment) { property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len); } @@ -50,7 +52,13 @@ static void zend_duplicate_property_info(zend_property_info *property_info) static void zend_duplicate_property_info_internal(zend_property_info *property_info) { - property_info->name = zend_strndup(property_info->name, property_info->name_length); + TSRMLS_FETCH(); + + if (UG(unicode)) { + property_info->name = (char*)zend_ustrndup((UChar*)property_info->name, property_info->name_length); + } else { + property_info->name = zend_strndup(property_info->name, property_info->name_length); + } } @@ -68,7 +76,7 @@ static void zend_destroy_property_info_internal(zend_property_info *property_inf free(property_info->name); } -static void build_runtime_defined_function_key(zval *result, char *name, int name_length TSRMLS_DC) +static void build_runtime_defined_function_key(zval *result, zend_uchar type, char *name, int name_length TSRMLS_DC) { char char_pos_buf[32]; uint char_pos_len; @@ -82,16 +90,16 @@ static void build_runtime_defined_function_key(zval *result, char *name, int nam } /* NULL, name length, filename length, last accepting char position length */ + if (type == IS_UNICODE) { + name_length *= sizeof(UChar); + } result->value.str.len = 1+name_length+strlen(filename)+char_pos_len; result->value.str.val = (char *) emalloc(result->value.str.len+1); -#ifdef ZEND_MULTIBYTE - /* must be binary safe */ + /* UTODO: function key should probably store UTF-16 value instead of converting to + runtime encoding */ result->value.str.val[0] = '\0'; memcpy(result->value.str.val+1, name, name_length); sprintf(result->value.str.val+1+name_length, "%s%s", filename, char_pos_buf); -#else - sprintf(result->value.str.val, "%c%s%s%s", '\0', name, filename, char_pos_buf); -#endif /* ZEND_MULTIBYTE */ result->type = IS_STRING; result->refcount = 1; } @@ -140,15 +148,6 @@ void zend_init_compiler_data_structures(TSRMLS_D) CG(start_lineno) = 0; init_compiler_declarables(TSRMLS_C); zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); - -#ifdef ZEND_MULTIBYTE - CG(script_encoding_list) = NULL; - CG(script_encoding_list_size) = 0; - CG(internal_encoding) = NULL; - CG(encoding_detector) = NULL; - CG(encoding_converter) = NULL; - CG(encoding_oddlen) = NULL; -#endif /* ZEND_MULTIBYTE */ } @@ -173,12 +172,6 @@ void shutdown_compiler(TSRMLS_D) zend_stack_destroy(&CG(list_stack)); zend_hash_destroy(&CG(filenames_table)); zend_llist_destroy(&CG(open_files)); - -#ifdef ZEND_MULTIBYTE - if (CG(script_encoding_list)) { - efree(CG(script_encoding_list)); - } -#endif /* ZEND_MULTIBYTE */ } @@ -227,15 +220,15 @@ static zend_uint get_temporary_variable(zend_op_array *op_array) return (op_array->T)++ * sizeof(temp_variable); } -static int lookup_cv(zend_op_array *op_array, char* name, int name_len) +static int lookup_cv(zend_op_array *op_array, zend_uchar type, void *name, int name_len) { int i = 0; - ulong hash_value = zend_inline_hash_func(name, name_len+1); + ulong hash_value = zend_u_inline_hash_func(type, name, name_len+1); while (i < op_array->last_var) { if (op_array->vars[i].hash_value == hash_value && op_array->vars[i].name_len == name_len && - strcmp(op_array->vars[i].name, name) == 0) { + !memcmp(op_array->vars[i].name, name, type==IS_UNICODE?UBYTES(name_len):name_len)) { efree(name); return i; } @@ -337,14 +330,16 @@ void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar zend_op *opline_ptr; zend_llist *fetch_list_ptr; - if (varname->op_type == IS_CONST && varname->u.constant.type == IS_STRING && - !zend_is_auto_global(varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC) && - !(varname->u.constant.value.str.len == (sizeof("this")-1) && - !memcmp(varname->u.constant.value.str.val, "this", sizeof("this"))) && + if (varname->op_type == IS_CONST && + (varname->u.constant.type == IS_STRING || + varname->u.constant.type == IS_UNICODE) && + !zend_u_is_auto_global(Z_TYPE(varname->u.constant), Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant) TSRMLS_CC) && + !(Z_UNILEN(varname->u.constant) == (sizeof("this")-1) && + ZEND_U_EQUAL(Z_TYPE(varname->u.constant), Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant), "this", sizeof("this")-1)) && (CG(active_op_array)->last == 0 || CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) { result->op_type = IS_CV; - result->u.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len); + result->u.var = lookup_cv(CG(active_op_array), Z_TYPE(varname->u.constant), Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant)); result->u.EA.type = 0; return; } @@ -365,8 +360,10 @@ void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar SET_UNUSED(opline_ptr->op2); opline_ptr->op2.u.EA.type = ZEND_FETCH_LOCAL; - if (varname->op_type == IS_CONST && varname->u.constant.type == IS_STRING) { - if (zend_is_auto_global(varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC)) { + if (varname->op_type == IS_CONST && + (varname->u.constant.type == IS_STRING || + varname->u.constant.type == IS_UNICODE)) { + if (zend_u_is_auto_global(Z_TYPE(varname->u.constant), Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant) TSRMLS_CC)) { opline_ptr->op2.u.EA.type = ZEND_FETCH_GLOBAL; } } @@ -399,9 +396,15 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) opline.result.u.EA.type = 0; opline.result.u.var = get_temporary_variable(CG(active_op_array)); opline.op1.op_type = IS_CONST; - opline.op1.u.constant.type = IS_STRING; - opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[result->u.var].name); - opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[result->u.var].name_len; + if (UG(unicode)) { + opline.op1.u.constant.type = IS_UNICODE; + Z_USTRVAL(opline.op1.u.constant) = eustrndup((UChar*)CG(active_op_array)->vars[result->u.var].name, CG(active_op_array)->vars[result->u.var].name_len); + Z_USTRLEN(opline.op1.u.constant) = CG(active_op_array)->vars[result->u.var].name_len; + } else { + opline.op1.u.constant.type = IS_STRING; + Z_STRVAL(opline.op1.u.constant) = estrndup(CG(active_op_array)->vars[result->u.var].name, CG(active_op_array)->vars[result->u.var].name_len); + Z_STRLEN(opline.op1.u.constant) = CG(active_op_array)->vars[result->u.var].name_len; + } SET_UNUSED(opline.op2); opline.op2 = *class_znode; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; @@ -419,9 +422,15 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) opline.result.u.EA.type = 0; opline.result.u.var = get_temporary_variable(CG(active_op_array)); opline.op1.op_type = IS_CONST; - opline.op1.u.constant.type = IS_STRING; - opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[opline_ptr->op1.u.var].name); - opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len; + if (UG(unicode)) { + opline.op1.u.constant.type = IS_UNICODE; + Z_USTRVAL(opline.op1.u.constant) = eustrndup((UChar*)CG(active_op_array)->vars[opline_ptr->op1.u.var].name, CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len); + Z_USTRLEN(opline.op1.u.constant) = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len; + } else { + opline.op1.u.constant.type = IS_STRING; + Z_STRVAL(opline.op1.u.constant) = estrndup(CG(active_op_array)->vars[opline_ptr->op1.u.var].name, CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len); + Z_STRLEN(opline.op1.u.constant) = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len; + } SET_UNUSED(opline.op2); opline.op2 = *class_znode; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; @@ -482,12 +491,13 @@ void zend_do_print(znode *result, znode *arg TSRMLS_DC) } -void zend_do_echo(znode *arg TSRMLS_DC) +void zend_do_echo(znode *arg, zend_bool inline_html TSRMLS_DC) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ECHO; opline->op1 = *arg; + opline->extended_value = inline_html; SET_UNUSED(opline->op2); } @@ -514,11 +524,11 @@ void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body SET_UNUSED(opline->op2); } else { /* we had code in the function body */ - zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "%s function %v::%R() cannot contain body", method_type, CG(active_class_entry)->name, Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant)); } } else { if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) { - zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Non-abstract method %v::%R() must contain body", CG(active_class_entry)->name, Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant)); } } } @@ -526,9 +536,10 @@ void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body static zend_bool opline_is_fetch_this(zend_op *opline TSRMLS_DC) { if ((opline->opcode == ZEND_FETCH_W) && (opline->op1.op_type == IS_CONST) - && (opline->op1.u.constant.type == IS_STRING) - && (opline->op1.u.constant.value.str.len == (sizeof("this")-1)) - && !memcmp(opline->op1.u.constant.value.str.val, "this", sizeof("this"))) { + && (opline->op1.u.constant.type == IS_STRING || + opline->op1.u.constant.type == IS_UNICODE) + && (Z_UNILEN(opline->op1.u.constant) == (sizeof("this")-1)) + && ZEND_U_EQUAL(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), "this", sizeof("this")-1)) { return 1; } else { return 0; @@ -909,6 +920,7 @@ void zend_do_init_string(znode *result TSRMLS_DC) opline->opcode = ZEND_INIT_STRING; opline->result.op_type = IS_TMP_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->extended_value = CG(literal_type); *result = opline->result; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); @@ -923,6 +935,8 @@ void zend_do_add_char(znode *result, znode *op1, znode *op2 TSRMLS_DC) opline->op1 = *op1; opline->op2 = *op2; opline->op2.op_type = IS_CONST; + opline->extended_value = CG(literal_type); + opline->extended_value = CG(literal_type); opline->result = opline->op1; *result = opline->result; } @@ -973,6 +987,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC) opline->result = *result; opline->op1 = *result; opline->op2 = *op2; + opline->extended_value = CG(literal_type); *result = opline->result; } @@ -1036,16 +1051,17 @@ int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier) void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) { zend_op_array op_array; - char *name = function_name->u.constant.value.str.val; - int name_len = function_name->u.constant.value.str.len; + char *name = Z_UNIVAL(function_name->u.constant); + int name_len = Z_UNILEN(function_name->u.constant); int function_begin_line = function_token->u.opline_num; zend_uint fn_flags; + unsigned int lcname_len; char *lcname; if (is_method) { if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { if ((fn_flags_znode->u.constant.value.lval & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) { - zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Access type for interface method %v::%R() must be omitted", CG(active_class_entry)->name, Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant)); } fn_flags_znode->u.constant.value.lval |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */ } @@ -1055,7 +1071,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } function_token->u.op_array = CG(active_op_array); - lcname = zend_str_tolower_dup(name, name_len); + lcname = zend_u_str_case_fold(Z_TYPE(function_name->u.constant), name, name_len, 0, &lcname_len); init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); @@ -1071,18 +1087,18 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n if (is_method) { char *short_class_name = CG(active_class_entry)->name; - int short_class_name_length = CG(active_class_entry)->name_length; + unsigned int short_class_name_length = CG(active_class_entry)->name_length; - if (zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { + if (zend_u_hash_add(&CG(active_class_entry)->function_table, Z_TYPE(function_name->u.constant), lcname, lcname_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { zend_op_array *child_op_array, *parent_op_array; if (CG(active_class_entry)->parent - && (zend_hash_find(&CG(active_class_entry)->function_table, name, name_len+1, (void **) &child_op_array) == SUCCESS) - && (zend_hash_find(&CG(active_class_entry)->parent->function_table, name, name_len+1, (void **) &parent_op_array) == SUCCESS) + && (zend_u_hash_find(&CG(active_class_entry)->function_table, Z_TYPE(function_name->u.constant), name, name_len+1, (void **) &child_op_array) == SUCCESS) + && (zend_u_hash_find(&CG(active_class_entry)->parent->function_table, Z_TYPE(function_name->u.constant), name, name_len+1, (void **) &parent_op_array) == SUCCESS) && (child_op_array == parent_op_array)) { - zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); + zend_u_hash_update(&CG(active_class_entry)->function_table, Z_TYPE(function_name->u.constant), name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); } else { efree(lcname); - zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name); + zend_error(E_COMPILE_ERROR, "Cannot redeclare %v::%R()", CG(active_class_entry)->name, Z_TYPE(function_name->u.constant), name); } } @@ -1095,39 +1111,38 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } if (!(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) { - short_class_name = do_alloca(short_class_name_length + 1); - zend_str_tolower_copy(short_class_name, CG(active_class_entry)->name, short_class_name_length); + short_class_name = zend_u_str_case_fold(UG(unicode)?IS_UNICODE:IS_STRING, CG(active_class_entry)->name, short_class_name_length, 0, &short_class_name_length); /* Improve after RC: cache the lowercase class name */ - if ((short_class_name_length == name_len) && (!memcmp(short_class_name, lcname, name_len))) { + if ((short_class_name_length == name_len) && (!memcmp(short_class_name, lcname, UG(unicode)?UBYTES(lcname_len):lcname_len))) { if (CG(active_class_entry)->constructor) { - zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name); + zend_error(E_STRICT, "Redefining already defined constructor for class %v", CG(active_class_entry)->name); } else { CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); } - } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1))) { if (CG(active_class_entry)->constructor) { - zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name); + zend_error(E_STRICT, "Redefining already defined constructor for class %v", CG(active_class_entry)->name); } CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) { CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) { CG(active_class_entry)->clone = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) { CG(active_class_entry)->__call = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) { CG(active_class_entry)->__get = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) { CG(active_class_entry)->__set = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) { CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array); - } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)))) { + } else if ((lcname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (ZEND_U_EQUAL(Z_TYPE(function_name->u.constant), lcname, lcname_len, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) { CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array); } else if (!(fn_flags & ZEND_ACC_STATIC)) { CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; } - free_alloca(short_class_name); + efree(short_class_name); } efree(lcname); @@ -1136,14 +1151,14 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC); + build_runtime_defined_function_key(&opline->op1.u.constant, Z_TYPE(function_name->u.constant), lcname, lcname_len TSRMLS_CC); opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_STRING; + opline->op2.u.constant.type = Z_TYPE(function_name->u.constant); opline->op2.u.constant.value.str.val = lcname; - opline->op2.u.constant.value.str.len = name_len; + opline->op2.u.constant.value.str.len = lcname_len; opline->op2.u.constant.refcount = 1; opline->extended_value = ZEND_DECLARE_FUNCTION; - zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); + zend_u_hash_update(CG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); } if (CG(extended_info)) { @@ -1196,7 +1211,9 @@ void zend_do_handle_exception(TSRMLS_D) void zend_do_end_function_declaration(znode *function_token TSRMLS_DC) { - char lcname[16]; + unsigned int lcname_len; + char *lcname; + char lcname_buf[16]; int name_len; zend_do_extended_info(TSRMLS_C); @@ -1208,14 +1225,29 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC) if (CG(active_class_entry)) { zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC); } else { + zend_uchar utype; + /* we don't care if the function name is longer, in fact lowercasing only * the beginning of the name speeds up the check process */ - name_len = strlen(CG(active_op_array)->function_name); - zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1)); - lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */ - if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) { + if (UG(unicode)) { + utype = IS_UNICODE; + name_len = u_strlen((UChar*)CG(active_op_array)->function_name); + lcname = zend_u_str_case_fold(utype, CG(active_op_array)->function_name, name_len, 0, &lcname_len); + } else { + utype = IS_STRING; + lcname_len = name_len = strlen(CG(active_op_array)->function_name); + zend_str_tolower_copy(lcname_buf, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname_buf)-1)); + lcname_buf[sizeof(lcname_buf)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */ + lcname = lcname_buf; + } + if (lcname_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && + ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1) && + CG(active_op_array)->num_args != 1) { zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME); } + if (lcname != lcname_buf) { + efree(lcname); + } } CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C); @@ -1245,16 +1277,20 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia } CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args)); cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1]; - cur_arg_info->name = estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len); - cur_arg_info->name_len = varname->u.constant.value.str.len; + if (Z_TYPE(varname->u.constant) == IS_UNICODE) { + cur_arg_info->name = (char*)eustrndup(Z_USTRVAL(varname->u.constant), Z_USTRLEN(varname->u.constant)); + } else { + cur_arg_info->name = estrndup(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant)); + } + cur_arg_info->name_len = Z_UNILEN(varname->u.constant); cur_arg_info->array_type_hint = 0; cur_arg_info->allow_null = 1; cur_arg_info->pass_by_reference = pass_by_reference; if (class_type->op_type != IS_UNUSED) { - if (class_type->u.constant.type == IS_STRING) { - cur_arg_info->class_name = class_type->u.constant.value.str.val; - cur_arg_info->class_name_len = class_type->u.constant.value.str.len; + if (class_type->u.constant.type == IS_STRING || class_type->u.constant.type == IS_UNICODE) { + cur_arg_info->class_name = Z_UNIVAL(class_type->u.constant); + cur_arg_info->class_name_len = Z_UNILEN(class_type->u.constant); } else { cur_arg_info->array_type_hint = 1; cur_arg_info->class_name = NULL; @@ -1272,16 +1308,22 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia int zend_do_begin_function_call(znode *function_name TSRMLS_DC) { zend_function *function; + unsigned int lcname_len; char *lcname; - lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); - if (zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant), Z_UNILEN(function_name->u.constant), 0, &lcname_len); + if (zend_u_hash_find(CG(function_table), Z_TYPE(function_name->u.constant), lcname, lcname_len+1, (void **) &function)==FAILURE) { zend_do_begin_dynamic_function_call(function_name TSRMLS_CC); efree(lcname); return 1; /* Dynamic */ } - efree(function_name->u.constant.value.str.val); - function_name->u.constant.value.str.val = lcname; + efree(Z_UNIVAL(function_name->u.constant)); + if (Z_TYPE(function_name->u.constant) == IS_UNICODE) { + Z_USTRVAL(function_name->u.constant) = (UChar *)lcname; + Z_USTRLEN(function_name->u.constant) = lcname_len; + } else { + Z_STRVAL(function_name->u.constant) = lcname; + } switch (function->type) { case ZEND_USER_FUNCTION: { @@ -1381,7 +1423,7 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) if (class_name->op_type == IS_CONST) { int fetch_type; - fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + fetch_type = zend_get_class_fetch_type(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant)); switch (fetch_type) { case ZEND_FETCH_CLASS_SELF: case ZEND_FETCH_CLASS_PARENT: @@ -1413,11 +1455,19 @@ void zend_do_fetch_class_name(znode *result, znode *class_name_entry, znode *cla *result = *class_name_entry; } - length = sizeof("::")-1 + result->u.constant.value.str.len + class_name->u.constant.value.str.len; - result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], class_name->u.constant.value.str.val, class_name->u.constant.value.str.len+1); - STR_FREE(class_name->u.constant.value.str.val); + length = sizeof("::")-1 + Z_USTRLEN(result->u.constant) + Z_USTRLEN(class_name->u.constant); + if (Z_TYPE(result->u.constant) == IS_UNICODE) { + Z_USTRVAL(result->u.constant) = erealloc(Z_USTRVAL(result->u.constant), UBYTES(length+1)); + Z_USTRVAL(result->u.constant)[Z_USTRLEN(result->u.constant)] = ':'; + Z_USTRVAL(result->u.constant)[Z_USTRLEN(result->u.constant)+1] = ':'; + memcpy(&Z_USTRVAL(result->u.constant)[Z_USTRLEN(result->u.constant) + sizeof("::")-1], class_name->u.constant.value.str.val, UBYTES(Z_USTRLEN(class_name->u.constant)+1)); + STR_FREE(Z_USTRVAL(class_name->u.constant)); + } else { + result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], class_name->u.constant.value.str.val, class_name->u.constant.value.str.len+1); + STR_FREE(class_name->u.constant.value.str.val); + } result->u.constant.value.str.len = length; } @@ -1431,12 +1481,22 @@ void zend_do_begin_class_member_function_call(znode *class_name, znode *method_n opline->op2 = *method_name; if (opline->op2.op_type == IS_CONST) { - if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(opline->op2.u.constant) && - memcmp(Z_STRVAL(opline->op2.u.constant), ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) { + if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_UNILEN(opline->op2.u.constant) && + ZEND_U_EQUAL(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) { zval_dtor(&opline->op2.u.constant); SET_UNUSED(opline->op2); } else { - zend_str_tolower(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len); + if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) { + unsigned int lcname_len; + UChar *lcname; + + lcname = zend_u_str_case_fold(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), 0, &lcname_len); + efree(Z_USTRVAL(opline->op2.u.constant)); + Z_USTRVAL(opline->op2.u.constant) = lcname; + Z_USTRLEN(opline->op2.u.constant) = lcname_len; + } else { + zend_str_tolower(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)); + } } } @@ -1731,7 +1791,7 @@ void zend_do_throw(znode *expr TSRMLS_DC) SET_UNUSED(opline->op2); } -ZEND_API void function_add_ref(zend_function *function) +ZEND_API void function_add_ref(zend_function *function TSRMLS_DC) { if (function->type == ZEND_USER_FUNCTION) { zend_op_array *op_array = &function->op_array; @@ -1742,13 +1802,13 @@ ZEND_API void function_add_ref(zend_function *function) zval *tmp_zval; ALLOC_HASHTABLE(op_array->static_variables); - zend_hash_init(op_array->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(op_array->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *)); } } } -static void do_inherit_parent_constructor(zend_class_entry *ce) +static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) { zend_function *function; @@ -1800,20 +1860,22 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) { /* inherit parent's constructor */ zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), NULL); - function_add_ref(function); + function_add_ref(function TSRMLS_CC); } else { /* Don't inherit the old style constructor if we already have the new style constructor */ + unsigned int lc_class_name_len, lc_parent_class_name_len; char *lc_class_name; char *lc_parent_class_name; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; - lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length); - if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) { - lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length); - if (zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) { + lc_class_name = zend_u_str_case_fold(utype, ce->name, ce->name_length, 0, &lc_class_name_len); + if (!zend_u_hash_exists(&ce->function_table, utype, lc_class_name, lc_class_name_len+1)) { + lc_parent_class_name = zend_u_str_case_fold(utype, ce->parent->name, ce->parent->name_length, 0, &lc_parent_class_name_len); + if (zend_u_hash_find(&ce->parent->function_table, utype, lc_parent_class_name, lc_parent_class_name_len+1, (void **)&function)==SUCCESS) { if (function->common.fn_flags & ZEND_ACC_CTOR) { /* inherit parent's constructor */ - zend_hash_update(&ce->function_table, lc_class_name, ce->name_length+1, function, sizeof(zend_function), NULL); - function_add_ref(function); + zend_u_hash_update(&ce->function_table, utype, lc_class_name, lc_class_name_len+1, function, sizeof(zend_function), NULL); + function_add_ref(function TSRMLS_CC); } } efree(lc_parent_class_name); @@ -1845,7 +1907,8 @@ static void do_inherit_method(zend_function *function) * as that of the parent class. That allows us to know in which context * we're running, and handle private method calls properly. */ - function_add_ref(function); + TSRMLS_FETCH(); + function_add_ref(function TSRMLS_CC); } @@ -1914,7 +1977,7 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f zend_function *child; TSRMLS_FETCH(); - if (zend_hash_quick_find(child_function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) { + if (zend_u_hash_quick_find(child_function_table, hash_key->type, hash_key->u.string, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) { if (parent_flags & (ZEND_ACC_ABSTRACT)) { child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; } @@ -1924,14 +1987,14 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f if (parent->common.fn_flags & ZEND_ACC_ABSTRACT && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope) && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) { - zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)", + zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %v::%v() (previously declared abstract in %v)", parent->common.scope->name, child->common.function_name, child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name); } if (parent_flags & ZEND_ACC_FINAL) { - zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name); + zend_error(E_COMPILE_ERROR, "Cannot override final method %v::%v()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name); } child_flags = child->common.fn_flags; @@ -1939,15 +2002,15 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f */ if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) { if (child->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); + zend_error(E_COMPILE_ERROR, "Cannot make non static method %v::%v() static in class %v", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } else { - zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); + zend_error(E_COMPILE_ERROR, "Cannot make static method %v::%v() non static in class %v", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } } /* Disallow making an inherited method abstract. */ if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) { - zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); + zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %v::%v() abstract in class %v", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } if (parent_flags & ZEND_ACC_CHANGED) { @@ -1956,7 +2019,7 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f /* Prevent derived classes from restricting access that was available in parent classes */ if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { - zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + zend_error(E_COMPILE_ERROR, "Access level to %v::%v() must be %s (as in class %v)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK)) && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) { child->common.fn_flags |= ZEND_ACC_CHANGED; @@ -1973,11 +2036,11 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f if (child->common.prototype) { if (!zend_do_perform_implementation_check(child, child->common.prototype)) { - zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with that of %s::%s()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(child->common.prototype), child->common.prototype->common.function_name); + zend_error(E_COMPILE_ERROR, "Declaration of %v::%v() must be compatible with that of %v::%v()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(child->common.prototype), child->common.prototype->common.function_name); } } else if (EG(error_reporting) & E_STRICT) { /* Check E_STRICT before the check so that we save some time */ if (!zend_do_perform_implementation_check(child, parent)) { - zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with that of %s::%s()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(parent), parent->common.function_name); + zend_error(E_STRICT, "Declaration of %v::%v() should be compatible with that of %v::%v()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(parent), parent->common.function_name); } } @@ -1989,12 +2052,15 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro { zend_property_info *child_info; zend_class_entry *parent_ce = ce->parent; - + zend_uchar utype; + TSRMLS_FETCH(); + + utype = UG(unicode)?IS_UNICODE:IS_STRING; if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { - if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { + if (zend_u_hash_quick_find(&ce->properties_info, hash_key->type, hash_key->u.string, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { child_info->flags |= ZEND_ACC_CHANGED; } else { - zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info); + zend_u_hash_quick_update(&ce->properties_info, hash_key->type, hash_key->u.string, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info); if(ce->type & ZEND_INTERNAL_CLASS) { zend_duplicate_property_info_internal(child_info); } else { @@ -2006,12 +2072,11 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro return 0; /* don't copy access information to child */ } - if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { + if (zend_u_hash_quick_find(&ce->properties_info, hash_key->type, hash_key->u.string, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) { - zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s", - (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey, - (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey); - + zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%v::$%R as %s%v::$%R", + (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->type, hash_key->u.string, + (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->type, hash_key->u.string); } if(parent_info->flags & ZEND_ACC_CHANGED) { @@ -2019,16 +2084,16 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro } if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) { - zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + zend_error(E_COMPILE_ERROR, "Access level to %v::$%R must be %s (as in class %v)%s", ce->name, hash_key->type, hash_key->u.string, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); } else if (child_info->flags & ZEND_ACC_IMPLICIT_PUBLIC) { if (!(parent_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) { /* Explicitly copy the default value from the parent (if it has one) */ zval **pvalue; - if (zend_hash_quick_find(&parent_ce->default_properties, parent_info->name, parent_info->name_length+1, parent_info->h, (void **) &pvalue) == SUCCESS) { + if (zend_u_hash_quick_find(&parent_ce->default_properties, utype, parent_info->name, parent_info->name_length+1, parent_info->h, (void **) &pvalue) == SUCCESS) { (*pvalue)->refcount++; - zend_hash_del(&ce->default_properties, child_info->name, child_info->name_length+1); - zend_hash_quick_update(&ce->default_properties, parent_info->name, parent_info->name_length+1, parent_info->h, pvalue, sizeof(zval *), NULL); + zend_u_hash_del(&ce->default_properties, utype, child_info->name, child_info->name_length+1); + zend_u_hash_quick_update(&ce->default_properties, utype, parent_info->name, parent_info->name_length+1, parent_info->h, pvalue, sizeof(zval *), NULL); } } return 1; /* Inherit from the parent */ @@ -2036,26 +2101,26 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro char *prot_name; int prot_name_length; - zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, child_info->name, child_info->name_length, ce->type & ZEND_INTERNAL_CLASS); + zend_u_mangle_property_name(&prot_name, &prot_name_length, utype, "*", 1, child_info->name, child_info->name_length, ce->type & ZEND_INTERNAL_CLASS); if (child_info->flags & ZEND_ACC_STATIC) { zval **prop; - if (zend_hash_find(parent_ce->static_members, prot_name, prot_name_length+1, (void**)&prop) == SUCCESS) { + if (zend_u_hash_find(parent_ce->static_members, utype, prot_name, prot_name_length+1, (void**)&prop) == SUCCESS) { zval **new_prop; - if (zend_hash_find(ce->static_members, child_info->name, child_info->name_length+1, (void**)&new_prop) == SUCCESS) { + if (zend_u_hash_find(ce->static_members, utype, child_info->name, child_info->name_length+1, (void**)&new_prop) == SUCCESS) { if (Z_TYPE_PP(new_prop) != IS_NULL && Z_TYPE_PP(prop) != IS_NULL) { char *prop_name, *tmp; - zend_unmangle_property_name(child_info->name, &tmp, &prop_name); - - zend_error(E_COMPILE_ERROR, "Cannot change initial value of property static protected %s::$%s in class %s", + + zend_u_unmangle_property_name(utype, child_info->name, &tmp, &prop_name); + zend_error(E_COMPILE_ERROR, "Cannot change initial value of property static protected %v::$%v in class %v", parent_ce->name, prop_name, ce->name); } } (*prop)->refcount++; - zend_hash_update(ce->static_members, child_info->name, child_info->name_length+1, (void**)prop, sizeof(zval*), NULL); - zend_hash_del(ce->static_members, prot_name, prot_name_length+1); + zend_u_hash_update(ce->static_members, utype, child_info->name, child_info->name_length+1, (void**)prop, sizeof(zval*), NULL); + zend_u_hash_del(ce->static_members, utype, prot_name, prot_name_length+1); } } else { - zend_hash_del(&ce->default_properties, prot_name, prot_name_length+1); + zend_u_hash_del(&ce->default_properties, utype, prot_name, prot_name_length+1); } pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); } @@ -2070,10 +2135,10 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) { if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) { - zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name); + zend_error(E_CORE_ERROR, "Class %v could not implement interface %v", ce->name, iface->name); } if (ce == iface) { - zend_error(E_ERROR, "Interface %s cannot not implement itself", ce->name); + zend_error(E_ERROR, "Interface %v cannot not implement itself", ce->name); } } @@ -2126,10 +2191,10 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent { if ((ce->ce_flags & ZEND_ACC_INTERFACE) && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) { - zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name); + zend_error(E_COMPILE_ERROR, "Interface %v may not inherit from class (%v)", ce->name, parent_ce->name); } if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) { - zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name); + zend_error(E_COMPILE_ERROR, "Class %v may not inherit from final class (%v)", ce->name, parent_ce->name); } ce->parent = parent_ce; @@ -2155,8 +2220,8 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_hash_key *hash_key, zend_class_entry *iface) { - if (zend_hash_quick_exists(child_constants_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h)) { - zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited constant %s from interface %s", hash_key->arKey, iface->name); + if (zend_u_hash_quick_exists(child_constants_table, hash_key->type, hash_key->u.string, hash_key->nKeyLength, hash_key->h)) { + zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited constant %R from interface %v", hash_key->type, hash_key->u.string, iface->name); return 0; } return 1; @@ -2181,20 +2246,20 @@ ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_b zend_error(E_COMPILE_ERROR, "Internal compiler error. Please report!"); } - zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); - if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) { + zend_u_hash_find(function_table, Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), (void *) &function); + if (zend_u_hash_add(function_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, function, sizeof(zend_function), NULL)==FAILURE) { int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; zend_function *function; - if (zend_hash_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void *) &function)==SUCCESS + if (zend_u_hash_find(function_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void *) &function)==SUCCESS && function->type==ZEND_USER_FUNCTION && ((zend_op_array *) function)->last>0) { - zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", - opline->op2.u.constant.value.str.val, + zend_error(error_level, "Cannot redeclare %R() (previously declared in %s:%d)", + Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), ((zend_op_array *) function)->filename, ((zend_op_array *) function)->opcodes[0].lineno); } else { - zend_error(error_level, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val); + zend_error(error_level, "Cannot redeclare %R()", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } return FAILURE; } else { @@ -2209,14 +2274,14 @@ ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *class_table { zend_class_entry *ce, **pce; - if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { - zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); + if (zend_u_hash_find(class_table, Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), (void **) &pce)==FAILURE) { + zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %R", Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant)); return NULL; } else { ce = *pce; } ce->refcount++; - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { + if (zend_u_hash_add(class_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { ce->refcount--; if (!compile_time) { /* If we're in compile time, in practice, it's quite possible @@ -2224,7 +2289,7 @@ ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *class_table * so we shut up about it. This allows the if (!defined('FOO')) { return; } * approach to work. */ - zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %R", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } return NULL; } else { @@ -2241,7 +2306,7 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *c zend_class_entry *ce, **pce; int found_ce; - found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); + found_ce = zend_u_hash_find(class_table, Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), (void **) &pce); if (found_ce == FAILURE) { if (!compile_time) { @@ -2250,7 +2315,7 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *c * so we shut up about it. This allows the if (!defined('FOO')) { return; } * approach to work. */ - zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %R", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } return NULL; } else { @@ -2258,7 +2323,7 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *c } if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) { - zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name); + zend_error(E_COMPILE_ERROR, "Class %v cannot extend from interface %v", ce->name, parent_ce->name); } zend_do_inheritance(ce, parent_ce TSRMLS_CC); @@ -2266,8 +2331,8 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *c ce->refcount++; /* Register the derived class */ - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { - zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + if (zend_u_hash_add(class_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %R", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); ce->refcount--; zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); @@ -2315,7 +2380,7 @@ void zend_do_early_binding(TSRMLS_D) zval *parent_name = &(opline-1)->op2.u.constant; zend_class_entry **pce; - if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(Z_TYPE_P(parent_name), Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) { return; } if (do_bind_inherited_class(opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) { @@ -2357,7 +2422,7 @@ void zend_do_early_binding(TSRMLS_D) return; } - zend_hash_del(table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); + zend_u_hash_del(table, Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant)); zval_dtor(&opline->op1.u.constant); zval_dtor(&opline->op2.u.constant); opline->opcode = ZEND_NOP; @@ -2624,21 +2689,25 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_op *opline; int doing_inheritance = 0; zend_class_entry *new_class_entry = emalloc(sizeof(zend_class_entry)); - char *lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + unsigned int lcname_len; + char *lcname = zend_u_str_case_fold(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant), 0, &lcname_len); if (CG(active_class_entry)) { zend_error(E_COMPILE_ERROR, "Class declarations may not be nested"); return; } - if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) { + if ((lcname_len == sizeof("self")-1 && + ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "self", sizeof("self")-1)) || + (lcname_len == sizeof("parent")-1 && + ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "parent", sizeof("parent")-1))) { efree(lcname); - zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot use '%R' as class name as it is reserved", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant)); } new_class_entry->type = ZEND_USER_CLASS; - new_class_entry->name = class_name->u.constant.value.str.val; - new_class_entry->name_length = class_name->u.constant.value.str.len; + new_class_entry->name = Z_UNIVAL(class_name->u.constant); + new_class_entry->name_length = Z_UNILEN(class_name->u.constant); zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); new_class_entry->filename = zend_get_compiled_filename(TSRMLS_C); @@ -2661,10 +2730,10 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, lcname, new_class_entry->name_length TSRMLS_CC); + build_runtime_defined_function_key(&opline->op1.u.constant, Z_TYPE(class_name->u.constant), lcname, lcname_len TSRMLS_CC); opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_STRING; + opline->op2.u.constant.type = Z_TYPE(class_name->u.constant); opline->op2.u.constant.refcount = 1; if (doing_inheritance) { @@ -2674,10 +2743,15 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod opline->opcode = ZEND_DECLARE_CLASS; } - opline->op2.u.constant.value.str.val = lcname; - opline->op2.u.constant.value.str.len = new_class_entry->name_length; + if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) { + Z_USTRVAL(opline->op2.u.constant) = (UChar *)lcname; + Z_USTRLEN(opline->op2.u.constant) = lcname_len; + } else { + Z_STRVAL(opline->op2.u.constant) = lcname; + Z_STRLEN(opline->op2.u.constant) = lcname_len; + } - zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL); + zend_u_hash_update(CG(class_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), &new_class_entry, sizeof(zend_class_entry *), NULL); CG(active_class_entry) = new_class_entry; opline->result.u.var = get_temporary_variable(CG(active_op_array)); @@ -2707,24 +2781,24 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML { zend_class_entry *ce = CG(active_class_entry); - do_inherit_parent_constructor(ce); + do_inherit_parent_constructor(ce TSRMLS_CC); if (ce->constructor) { ce->constructor->common.fn_flags |= ZEND_ACC_CTOR; if (ce->constructor->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(E_COMPILE_ERROR, "Constructor %s::%s() cannot be static", ce->name, ce->constructor->common.function_name); + zend_error(E_COMPILE_ERROR, "Constructor %v::%v() cannot be static", ce->name, ce->constructor->common.function_name); } } if (ce->destructor) { ce->destructor->common.fn_flags |= ZEND_ACC_DTOR; if (ce->destructor->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(E_COMPILE_ERROR, "Destructor %s::%s() cannot be static", ce->name, ce->destructor->common.function_name); + zend_error(E_COMPILE_ERROR, "Destructor %v::%v() cannot be static", ce->name, ce->destructor->common.function_name); } } if (ce->clone) { ce->clone->common.fn_flags |= ZEND_ACC_CLONE; if (ce->clone->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(E_COMPILE_ERROR, "Clone method %s::%s() cannot be static", ce->name, ce->clone->common.function_name); + zend_error(E_COMPILE_ERROR, "Clone method %v::%v() cannot be static", ce->name, ce->clone->common.function_name); } } @@ -2790,6 +2864,29 @@ ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, char *src *dest_length = prop_name_length; } +ZEND_API void zend_u_mangle_property_name(char **dest, int *dest_length, zend_uchar type, char *src1, int src1_length, char *src2, int src2_length, int internal) +{ + if (type == IS_UNICODE) { + UChar *prop_name; + int prop_name_length; + + prop_name_length = 1 + src1_length + 1 + src2_length; + prop_name = pemalloc(UBYTES(prop_name_length + 1), internal); + prop_name[0] = 0; + if (src1_length == 1 && src1[0] == '*') { + prop_name[1] = '*'; + prop_name[2] = 0; + } else { + memcpy(prop_name + 1, src1, UBYTES(src1_length+1)); + } + memcpy(prop_name + 1 + src1_length + 1, src2, UBYTES(src2_length+1)); + + *dest = (char*)prop_name; + *dest_length = prop_name_length; + } else { + zend_mangle_property_name(dest, dest_length, src1, src1_length, src2, src2_length, internal); + } +} ZEND_API void zend_unmangle_property_name(char *mangled_property, char **class_name, char **prop_name) { @@ -2804,6 +2901,26 @@ ZEND_API void zend_unmangle_property_name(char *mangled_property, char **class_n *prop_name = (*class_name)+strlen(*class_name)+1; } +ZEND_API void zend_u_unmangle_property_name(zend_uchar type, char *mangled_property, char **class_name, char **prop_name) +{ + if (type == IS_UNICODE) { + *prop_name = *class_name = NULL; + + if (((UChar*)mangled_property)[0]!=0) { + *prop_name = mangled_property; + return; + } + + *class_name = mangled_property+UBYTES(1); + *prop_name = (*class_name)+UBYTES(u_strlen((UChar*)*class_name)+1); + if ((*(UChar**)class_name)[0] == '*') { + *class_name = "*"; + } + } else { + zend_unmangle_property_name(mangled_property, class_name, prop_name); + } +} + void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_type TSRMLS_DC) { zval *property; @@ -2820,13 +2937,13 @@ void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_ty } if (access_type & ZEND_ACC_FINAL) { - zend_error(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, the final modifier is allowed only for methods", - CG(active_class_entry)->name, var_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot declare property %v::$%R final, the final modifier is allowed only for methods", + CG(active_class_entry)->name, Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant)); } - if (zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, (void **) &existing_property_info)==SUCCESS) { + if (zend_u_hash_find(&CG(active_class_entry)->properties_info, Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant), Z_UNILEN(var_name->u.constant)+1, (void **) &existing_property_info)==SUCCESS) { if (!(existing_property_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) { - zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare %v::$%R", CG(active_class_entry)->name, Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant)); } } ALLOC_ZVAL(property); @@ -2845,7 +2962,7 @@ void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_ty CG(doc_comment_len) = 0; } - zend_declare_property_ex(CG(active_class_entry), var_name->u.constant.value.str.val, var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); + zend_u_declare_property(CG(active_class_entry), Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant), Z_UNILEN(var_name->u.constant), property, access_type TSRMLS_CC); efree(var_name->u.constant.value.str.val); } @@ -2867,9 +2984,9 @@ void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC) property->type = IS_NULL; } - if (zend_hash_add(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL)==FAILURE) { + if (zend_u_hash_add(&CG(active_class_entry)->constants_table, Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant), Z_UNILEN(var_name->u.constant)+1, &property, sizeof(zval *), NULL)==FAILURE) { FREE_ZVAL(property); - zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %v::%R", CG(active_class_entry)->name, Z_TYPE(var_name->u.constant), Z_UNIVAL(var_name->u.constant)); } FREE_PNODE(var_name); } @@ -2957,11 +3074,15 @@ void zend_do_declare_implicit_property(TSRMLS_D) if (opline_ptr->op1.op_type == IS_UNUSED && CG(active_class_entry) && opline_ptr->op2.op_type == IS_CONST - && !zend_hash_exists(&CG(active_class_entry)->properties_info, opline_ptr->op2.u.constant.value.str.val, opline_ptr->op2.u.constant.value.str.len+1)) { + && !zend_u_hash_exists(&CG(active_class_entry)->properties_info, Z_TYPE(opline_ptr->op2.u.constant), Z_UNIVAL(opline_ptr->op2.u.constant), Z_UNILEN(opline_ptr->op2.u.constant)+1)) { znode property; property = opline_ptr->op2; - property.u.constant.value.str.val = estrndup(opline_ptr->op2.u.constant.value.str.val, opline_ptr->op2.u.constant.value.str.len); + if (Z_TYPE(opline_ptr->op2.u.constant) == IS_UNICODE) { + Z_USTRVAL(property.u.constant) = eustrndup(Z_USTRVAL(opline_ptr->op2.u.constant), Z_USTRLEN(opline_ptr->op2.u.constant)); + } else { + Z_STRVAL(property.u.constant) = estrndup(Z_STRVAL(opline_ptr->op2.u.constant), Z_STRLEN(opline_ptr->op2.u.constant)); + } zend_do_declare_property(&property, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_IMPLICIT_PUBLIC TSRMLS_CC); } #endif @@ -3123,17 +3244,23 @@ void zend_do_add_array_element(znode *result, znode *expr, znode *offset, zend_b void zend_do_add_static_array_element(znode *result, znode *offset, znode *expr) { zval *element; + TSRMLS_FETCH(); ALLOC_ZVAL(element); *element = expr->u.constant; if (offset) { - switch (offset->u.constant.type) { + zend_uchar utype = Z_TYPE(offset->u.constant); + + switch (Z_TYPE(offset->u.constant)) { case IS_CONSTANT: /* Ugly hack to denote that this value has a constant index */ element->type |= IS_CONSTANT_INDEX; /* break missing intentionally */ + utype = UG(unicode)?IS_UNICODE:IS_STRING; case IS_STRING: - zend_symtable_update(result->u.constant.value.ht, offset->u.constant.value.str.val, offset->u.constant.value.str.len+1, &element, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(result->u.constant.value.ht, utype, Z_UNIVAL(offset->u.constant), Z_UNILEN(offset->u.constant)+1, &element, sizeof(zval *), NULL); zval_dtor(&offset->u.constant); break; case IS_NULL: @@ -3278,9 +3405,9 @@ void zend_do_fetch_static_variable(znode *varname, znode *static_assignment, int } if (!CG(active_op_array)->static_variables) { ALLOC_HASHTABLE(CG(active_op_array)->static_variables); - zend_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); } - zend_hash_update(CG(active_op_array)->static_variables, varname->u.constant.value.str.val, varname->u.constant.value.str.len+1, &tmp, sizeof(zval *), NULL); + zend_u_hash_update(CG(active_op_array)->static_variables, Z_TYPE(varname->u.constant), Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant)+1, &tmp, sizeof(zval *), NULL); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ @@ -3366,9 +3493,10 @@ void zend_do_indirect_references(znode *result, znode *num_references, znode *va int i; zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_normalization(variable, variable TSRMLS_CC); for (i=1; iu.constant.value.lval; i++) { fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R TSRMLS_CC); - *variable = *result; + zend_do_normalization(variable, result TSRMLS_CC); } zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(result, variable, 1 TSRMLS_CC); @@ -3385,9 +3513,15 @@ void zend_do_unset(znode *variable TSRMLS_DC) zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_UNSET_VAR; opline->op1.op_type = IS_CONST; - opline->op1.u.constant.type = IS_STRING; - opline->op1.u.constant.value.str.len = CG(active_op_array)->vars[variable->u.var].name_len; - opline->op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[variable->u.var].name); + if (UG(unicode)) { + opline->op1.u.constant.type = IS_UNICODE; + Z_USTRLEN(opline->op1.u.constant) = CG(active_op_array)->vars[variable->u.var].name_len; + Z_USTRVAL(opline->op1.u.constant) = eustrndup((UChar*)CG(active_op_array)->vars[variable->u.var].name, CG(active_op_array)->vars[variable->u.var].name_len); + } else { + opline->op1.u.constant.type = IS_STRING; + Z_STRLEN(opline->op1.u.constant) = CG(active_op_array)->vars[variable->u.var].name_len; + Z_STRVAL(opline->op1.u.constant) = estrndup(CG(active_op_array)->vars[variable->u.var].name, CG(active_op_array)->vars[variable->u.var].name_len); + } SET_UNUSED(opline->op2); opline->op2.u.EA.type = ZEND_FETCH_LOCAL; SET_UNUSED(opline->result); @@ -3422,9 +3556,15 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC last_op = get_next_op(CG(active_op_array) TSRMLS_CC); last_op->opcode = ZEND_ISSET_ISEMPTY_VAR; last_op->op1.op_type = IS_CONST; - last_op->op1.u.constant.type = IS_STRING; - last_op->op1.u.constant.value.str.len = CG(active_op_array)->vars[variable->u.var].name_len; - last_op->op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[variable->u.var].name); + if (UG(unicode)) { + last_op->op1.u.constant.type = IS_UNICODE; + Z_USTRLEN(last_op->op1.u.constant) = CG(active_op_array)->vars[variable->u.var].name_len; + Z_USTRVAL(last_op->op1.u.constant) = eustrndup((UChar*)CG(active_op_array)->vars[variable->u.var].name, CG(active_op_array)->vars[variable->u.var].name_len); + } else { + last_op->op1.u.constant.type = IS_STRING; + Z_STRLEN(last_op->op1.u.constant) = CG(active_op_array)->vars[variable->u.var].name_len; + Z_STRVAL(last_op->op1.u.constant) = estrndup(CG(active_op_array)->vars[variable->u.var].name, CG(active_op_array)->vars[variable->u.var].name_len); + } SET_UNUSED(last_op->op2); last_op->op2.u.EA.type = ZEND_FETCH_LOCAL; last_op->result.u.var = get_temporary_variable(CG(active_op_array)); @@ -3634,35 +3774,19 @@ void zend_do_declare_begin(TSRMLS_D) void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC) { - if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "ticks", sizeof("ticks")-1)) { + if (ZEND_U_EQUAL(Z_TYPE(var->u.constant), Z_UNIVAL(var->u.constant), Z_UNILEN(var->u.constant), "ticks", sizeof("ticks")-1)) { convert_to_long(&val->u.constant); CG(declarables).ticks = val->u.constant; -#ifdef ZEND_MULTIBYTE - } else if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "encoding", sizeof("encoding")-1)) { - zend_encoding *new_encoding, *old_encoding; - zend_encoding_filter old_input_filter; + } else if (UG(unicode) && ZEND_U_EQUAL(Z_TYPE(var->u.constant), Z_UNIVAL(var->u.constant), Z_UNILEN(var->u.constant), "encoding", sizeof("encoding")-1)) { if (val->u.constant.type == IS_CONSTANT) { zend_error(E_COMPILE_ERROR, "Cannot use constants as encoding"); } convert_to_string(&val->u.constant); - new_encoding = zend_multibyte_fetch_encoding(val->u.constant.value.str.val); - if (!new_encoding) { - zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", val->u.constant.value.str.val); - } else { - old_input_filter = LANG_SCNG(input_filter); - old_encoding = LANG_SCNG(script_encoding); - zend_multibyte_set_filter(new_encoding TSRMLS_CC); - - /* need to re-scan if input filter changed */ - if (old_input_filter != LANG_SCNG(input_filter) || - ((old_input_filter == zend_multibyte_script_encoding_filter) && - (new_encoding != old_encoding))) { - zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC); - } + if (zend_prepare_scanner_converters(Z_STRVAL(val->u.constant), 1 TSRMLS_CC) == FAILURE) { + zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", Z_STRVAL(val->u.constant)); } efree(val->u.constant.value.str.val); -#endif /* ZEND_MULTIBYTE */ } zval_dtor(&var->u.constant); } @@ -3689,12 +3813,21 @@ void zend_do_end_heredoc(TSRMLS_D) return; } - opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0; - if (opline->op2.u.constant.value.str.len>0) { - if (opline->op2.u.constant.value.str.val[opline->op2.u.constant.value.str.len-1]=='\r') { - opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0; - } - } + if (opline->op2.u.constant.type == IS_UNICODE) { + opline->op2.u.constant.value.ustr.val[(opline->op2.u.constant.value.ustr.len--)-1] = 0; + if (opline->op2.u.constant.value.ustr.len>0) { + if (opline->op2.u.constant.value.ustr.val[opline->op2.u.constant.value.ustr.len-1]=='\r') { + opline->op2.u.constant.value.ustr.val[(opline->op2.u.constant.value.ustr.len--)-1] = 0; + } + } + } else { + opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0; + if (opline->op2.u.constant.value.str.len>0) { + if (opline->op2.u.constant.value.str.val[opline->op2.u.constant.value.str.len-1]=='\r') { + opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0; + } + } + } } @@ -3856,11 +3989,11 @@ void zend_auto_global_dtor(zend_auto_global *auto_global) } -zend_bool zend_is_auto_global(char *name, uint name_len TSRMLS_DC) +zend_bool zend_u_is_auto_global(zend_uchar type, void *name, uint name_len TSRMLS_DC) { zend_auto_global *auto_global; - if (zend_hash_find(CG(auto_globals), name, name_len+1, (void **) &auto_global)==SUCCESS) { + if (zend_u_hash_find(CG(auto_globals), type, name, name_len+1, (void **) &auto_global)==SUCCESS) { if (auto_global->armed) { auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC); } @@ -3869,6 +4002,11 @@ zend_bool zend_is_auto_global(char *name, uint name_len TSRMLS_DC) return 0; } +zend_bool zend_is_auto_global(char *name, uint name_len TSRMLS_DC) +{ + return zend_u_is_auto_global(IS_STRING, name, name_len TSRMLS_CC); +} + int zend_register_auto_global(char *name, uint name_len, zend_auto_global_callback auto_global_callback TSRMLS_DC) { @@ -3934,8 +4072,8 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->doc_comment = NULL; ce->doc_comment_len = 0; - zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); - zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); + zend_u_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); + zend_u_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, UG(unicode), 0); if (persistent_hashes) { ce->static_members = (HashTable *) malloc(sizeof(HashTable)); @@ -3943,9 +4081,9 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ALLOC_HASHTABLE(ce->static_members); } - zend_hash_init_ex(ce->static_members, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); - zend_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); - zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); + zend_u_hash_init_ex(ce->static_members, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); + zend_u_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); + zend_u_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, UG(unicode), 0); if (nullify_handlers) { ce->constructor = NULL; @@ -3973,13 +4111,13 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify } -int zend_get_class_fetch_type(char *class_name, uint class_name_len) +int zend_get_class_fetch_type(zend_uchar type, char *class_name, uint class_name_len) { if ((class_name_len == sizeof("self")-1) && - !memcmp(class_name, "self", sizeof("self"))) { + ZEND_U_EQUAL(type, class_name, class_name_len, "self", sizeof("self")-1)) { return ZEND_FETCH_CLASS_SELF; } else if ((class_name_len == sizeof("parent")-1) && - !memcmp(class_name, "parent", sizeof("parent"))) { + ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) { return ZEND_FETCH_CLASS_PARENT; } else { return ZEND_FETCH_CLASS_DEFAULT; @@ -3994,6 +4132,23 @@ ZEND_API char* zend_get_compiled_variable_name(zend_op_array *op_array, zend_uin return op_array->vars[var].name; } +void zend_do_normalization(znode *result, znode *str TSRMLS_DC) +{ + zend_op *opline; + + if (!UG(unicode)) { + *result = *str; + return; + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_U_NORMALIZE; + opline->result.op_type = IS_TMP_VAR; + opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->op1 = *str; + SET_UNUSED(opline->op2); + *result = opline->result; +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b63dd8c90a..869a0a89ea 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -237,7 +237,7 @@ typedef struct _zend_internal_function { void (*handler)(INTERNAL_FUNCTION_PARAMETERS); } zend_internal_function; -#define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : "") +#define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : EMPTY_STR) typedef union _zend_function { zend_uchar type; /* MUST be the first element of this struct! */ @@ -329,6 +329,10 @@ ZEND_API int zend_get_scanned_file_offset(TSRMLS_D); ZEND_API char* zend_get_compiled_variable_name(zend_op_array *op_array, zend_uint var, int* name_len); +ZEND_API int zend_prepare_scanner_converters(const char *onetime_encoding, int run_time TSRMLS_DC); +ZEND_API int32_t zend_convert_scanner_output(UChar **target, int32_t *target_len, const char *source, int32_t source_len, UErrorCode *status TSRMLS_DC); +int zend_unicode_yyinput(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC); + #ifdef ZTS const char *zend_get_zendtext(TSRMLS_D); int zend_get_zendleng(TSRMLS_D); @@ -352,7 +356,7 @@ void fetch_array_dim(znode *result, znode *parent, znode *dim TSRMLS_DC); void fetch_string_offset(znode *result, znode *parent, znode *offset TSRMLS_DC); void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC); void zend_do_print(znode *result, znode *arg TSRMLS_DC); -void zend_do_echo(znode *arg TSRMLS_DC); +void zend_do_echo(znode *arg, zend_bool inline_html TSRMLS_DC); typedef int (*unary_op_type)(zval *, zval *); ZEND_API unary_op_type get_unary_op(int opcode); ZEND_API void *get_binary_op(int opcode); @@ -497,7 +501,9 @@ void zend_do_ticks(TSRMLS_D); void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC); -ZEND_API void function_add_ref(zend_function *function); +ZEND_API void function_add_ref(zend_function *function TSRMLS_DC); + +void zend_do_normalization(znode *result, znode *str TSRMLS_DC); #define INITIAL_OP_ARRAY_SIZE 64 @@ -523,6 +529,10 @@ void zend_class_add_ref(zend_class_entry **ce); ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length, int internal); ZEND_API void zend_unmangle_property_name(char *mangled_property, char **prop_name, char **class_name); +ZEND_API void zend_u_mangle_property_name(char **dest, int *dest_length, zend_uchar type, char *src1, int src1_length, char *src2, int src2_length, int internal); +ZEND_API void zend_u_unmangle_property_name(zend_uchar type, char *mangled_property, char **prop_name, char **class_name); + + #define ZEND_FUNCTION_DTOR (void (*)(void *)) zend_function_dtor #define ZEND_CLASS_DTOR (void (*)(void *)) destroy_zend_class @@ -539,7 +549,7 @@ void zend_do_mark_last_catch(znode *first_catch, znode *last_additional_catch TS ZEND_API zend_bool zend_is_compiling(TSRMLS_D); ZEND_API char *zend_make_compiled_string_description(char *name TSRMLS_DC); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC); -int zend_get_class_fetch_type(char *class_name, uint class_name_len); +int zend_get_class_fetch_type(zend_uchar type, char *class_name, uint class_name_len); typedef zend_bool (*zend_auto_global_callback)(char *name, uint name_len TSRMLS_DC); typedef struct _zend_auto_global { @@ -552,6 +562,7 @@ typedef struct _zend_auto_global { void zend_auto_global_dtor(zend_auto_global *auto_global); ZEND_API int zend_register_auto_global(char *name, uint name_len, zend_auto_global_callback auto_global_callback TSRMLS_DC); ZEND_API zend_bool zend_is_auto_global(char *name, uint name_len TSRMLS_DC); +ZEND_API zend_bool zend_u_is_auto_global(zend_uchar type, void *name, uint name_len TSRMLS_DC); ZEND_API int zend_auto_global_disable_jit(char *varname, zend_uint varname_length TSRMLS_DC); int zendlex(znode *zendlval TSRMLS_DC); diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index ae06f837e7..613bc0a962 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -83,7 +83,7 @@ int zend_startup_constants(TSRMLS_D) { EG(zend_constants) = (HashTable *) malloc(sizeof(HashTable)); - if (zend_hash_init(EG(zend_constants), 20, NULL, ZEND_CONSTANT_DTOR, 1)==FAILURE) { + if (zend_u_hash_init(EG(zend_constants), 20, NULL, ZEND_CONSTANT_DTOR, 1, UG(unicode))==FAILURE) { return FAILURE; } return SUCCESS; @@ -108,6 +108,11 @@ void zend_register_standard_constants(TSRMLS_D) REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("U_INVALID_STOP", ZEND_FROM_U_ERROR_STOP, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("U_INVALID_SKIP", ZEND_FROM_U_ERROR_SKIP, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("U_INVALID_SUBSTITUTE", ZEND_FROM_U_ERROR_SUBST, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("U_INVALID_ESCAPE", ZEND_FROM_U_ERROR_ESCAPE, CONST_PERSISTENT | CONST_CS); + /* true/false constants */ { zend_constant c; @@ -215,13 +220,15 @@ ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC int retval = 1; char *lookup_name; char *colon; + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - if ((colon = memchr(name, ':', name_len)) && colon[1] == ':') { + if ((UG(unicode) && (colon = (char*)u_memchr((UChar*)name, ':', name_len)) && ((UChar*)colon)[1] == ':') || + (!UG(unicode) && (colon = memchr(name, ':', name_len)) && colon[1] == ':')) { /* class constant */ zend_class_entry **ce = NULL, *scope; - int class_name_len = colon-name; + int class_name_len = UG(unicode)?((colon-name)/sizeof(UChar)):colon-name; int const_name_len = name_len - class_name_len - 2; - char *constant_name = colon+2; + char *constant_name = colon + (UG(unicode)?UBYTES(2):2); zval **ret_constant; char *class_name; @@ -231,16 +238,22 @@ ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC scope = CG(active_class_entry); } - class_name = estrndup(name, class_name_len); + if (UG(unicode)) { + class_name = (char*)eustrndup((UChar*)name, class_name_len); + } else { + class_name = estrndup(name, class_name_len); + } - if (class_name_len == sizeof("self")-1 && strcmp(class_name, "self") == 0) { + if (class_name_len == sizeof("self")-1 && + ZEND_U_EQUAL(type, class_name, class_name_len, "self", sizeof("self")-1)) { if (scope) { ce = &scope; } else { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); retval = 0; } - } else if (class_name_len == sizeof("parent")-1 && strcmp(class_name, "parent") == 0) { + } else if (class_name_len == sizeof("parent")-1 && + ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) { if (!scope) { zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); } else if (!scope->parent) { @@ -249,14 +262,14 @@ ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC ce = &scope->parent; } } else { - if (zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC) != SUCCESS) { + if (zend_u_lookup_class(type, class_name, class_name_len, &ce TSRMLS_CC) != SUCCESS) { retval = 0; } } efree(class_name); if (retval && ce) { - if (zend_hash_find(&((*ce)->constants_table), constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) { + if (zend_u_hash_find(&((*ce)->constants_table), type, constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) { retval = 0; } } else { @@ -272,12 +285,13 @@ ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC return retval; } - if (zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c) == FAILURE) { - lookup_name = estrndup(name, name_len); - zend_str_tolower(lookup_name, name_len); + if (zend_u_hash_find(EG(zend_constants), type, name, name_len+1, (void **) &c) == FAILURE) { + int lookup_name_len; + + lookup_name = zend_u_str_case_fold(type, name, name_len, 1, &lookup_name_len); - if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) { - if ((c->flags & CONST_CS) && memcmp(c->name, name, name_len)!=0) { + if (zend_u_hash_find(EG(zend_constants), type, lookup_name, lookup_name_len+1, (void **) &c)==SUCCESS) { + if ((c->flags & CONST_CS) && memcmp(c->name, name, UG(unicode)?UBYTES(name_len):name_len)!=0) { retval=0; } } else { @@ -297,9 +311,10 @@ ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC } -ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) +ZEND_API int zend_u_register_constant(zend_uchar type, zend_constant *c TSRMLS_DC) { - char *lowercase_name = NULL; + int lookup_name_len; + char *lookup_name = NULL; char *name; int ret = SUCCESS; @@ -309,14 +324,14 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) if (!(c->flags & CONST_CS)) { /* keep in mind that c->name_len already contains the '\0' */ - lowercase_name = estrndup(c->name, c->name_len); - zend_str_tolower(lowercase_name, c->name_len); - name = lowercase_name; + name = lookup_name = zend_u_str_case_fold(type, c->name, c->name_len-1, 1, &lookup_name_len); + lookup_name_len++; } else { + lookup_name_len = c->name_len; name = c->name; } - if (zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE) { + if (zend_u_hash_add(EG(zend_constants), type, name, lookup_name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE) { zend_error(E_NOTICE,"Constant %s already defined", name); free(c->name); if (!(c->flags & CONST_PERSISTENT)) { @@ -324,13 +339,16 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) } ret = FAILURE; } - if (lowercase_name) { - efree(lowercase_name); + if (lookup_name) { + efree(lookup_name); } return ret; } - +ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) +{ + return zend_u_register_constant(IS_STRING, c TSRMLS_CC); +} /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 241050da5b..a3ca212d3b 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -60,6 +60,7 @@ ZEND_API void zend_register_double_constant(char *name, uint name_len, double dv ZEND_API void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC); ZEND_API void zend_register_stringl_constant(char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC); ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC); +ZEND_API int zend_u_register_constant(zend_uchar type, zend_constant *c TSRMLS_DC); void zend_copy_constants(HashTable *target, HashTable *sourc); void copy_zend_constant(zend_constant *c); END_EXTERN_C() diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index ca410c56f0..b19a460f3a 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -86,7 +86,7 @@ static zend_object_value zend_default_exception_new_ex(zend_class_entry *class_t obj.value.obj.handlers = &default_exception_handlers; ALLOC_HASHTABLE(object->properties); - zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); ALLOC_ZVAL(trace); @@ -474,8 +474,8 @@ ZEND_METHOD(exception, __toString) _default_exception_get_entry(getThis(), "file", sizeof("file")-1, &file TSRMLS_CC); _default_exception_get_entry(getThis(), "line", sizeof("line")-1, &line TSRMLS_CC); - convert_to_string(&message); - convert_to_string(&file); + convert_to_text(&message); + convert_to_text(&file); convert_to_long(&line); ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 0); @@ -492,16 +492,16 @@ ZEND_METHOD(exception, __toString) zend_call_function(&fci, NULL TSRMLS_CC); - if (Z_TYPE_P(trace) != IS_STRING) { + if (Z_TYPE_P(trace) != IS_STRING && Z_TYPE_P(trace) != IS_UNICODE) { trace = NULL; } - if (Z_STRLEN(message) > 0) { - len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s", - Z_OBJCE_P(getThis())->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line), + if (Z_UNILEN(message) > 0) { + len = zend_spprintf(&str, 0, "exception '%v' with message '%R' in %s:%ld\nStack trace:\n%s", + Z_OBJCE_P(getThis())->name, Z_TYPE(message), Z_UNIVAL(message), Z_STRVAL(file), Z_LVAL(line), (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n"); } else { - len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s", + len = zend_spprintf(&str, 0, "exception '%v' in %s:%ld\nStack trace:\n%s", Z_OBJCE_P(getThis())->name, Z_STRVAL(file), Z_LVAL(line), (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n"); } @@ -670,7 +670,7 @@ ZEND_API void zend_exception_error(zval *exception TSRMLS_DC) zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &str); if (!EG(exception)) { if (Z_TYPE_P(str) != IS_STRING) { - zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name); + zend_error(E_WARNING, "%v::__toString() must return a string", ce_exception->name); } else { zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC); } @@ -686,7 +686,7 @@ ZEND_API void zend_exception_error(zval *exception TSRMLS_DC) file = NULL; line = NULL; } - zend_error_va(E_WARNING, file ? Z_STRVAL_P(file) : NULL, line ? Z_LVAL_P(line) : 0, "Uncaught %s in exception handling during call to %s::__tostring()", Z_OBJCE_P(EG(exception))->name, ce_exception->name); + zend_error_va(E_WARNING, file ? Z_STRVAL_P(file) : NULL, line ? Z_LVAL_P(line) : 0, "Uncaught %v in exception handling during call to %v::__tostring()", Z_OBJCE_P(EG(exception))->name, ce_exception->name); } str = zend_read_property(default_exception_ce, exception, "string", sizeof("string")-1, 1 TSRMLS_CC); @@ -695,7 +695,7 @@ ZEND_API void zend_exception_error(zval *exception TSRMLS_DC) zend_error_va(E_ERROR, Z_STRVAL_P(file), Z_LVAL_P(line), "Uncaught %s\n thrown", Z_STRVAL_P(str)); } else { - zend_error(E_ERROR, "Uncaught exception '%s'", ce_exception->name); + zend_error(E_ERROR, "Uncaught exception '%v'", ce_exception->name); } } @@ -716,6 +716,12 @@ ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC) zend_throw_exception_internal(exception TSRMLS_CC); } +void init_exceptions(TSRMLS_D) +{ + default_exception_ce = zend_get_named_class_entry("Exception", sizeof("Exception")-1 TSRMLS_CC); + error_exception_ce = zend_get_named_class_entry("ErrorException", sizeof("ErrorException")-1 TSRMLS_CC); +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 0a47062265..b546b08c24 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -48,6 +48,8 @@ extern ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC); /* show an exception using zend_error(E_ERROR,...) */ ZEND_API void zend_exception_error(zval *exception TSRMLS_DC); +void init_exceptions(TSRMLS_D); + END_EXTERN_C() #endif diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 888b60e9d2..8aa30d3c86 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -35,6 +35,7 @@ #include "zend_ini.h" #include "zend_exceptions.h" #include "zend_vm.h" +#include "zend_unicode.h" #define _CONST_CODE 0 #define _TMP_CODE 1 @@ -148,12 +149,12 @@ ZEND_API zval** zend_get_compiled_variable_value(zend_execute_data *execute_data return execute_data_ptr->CVs[var]; } -static inline void zend_get_cv_address(zend_compiled_variable *cv, zval ***ptr, temp_variable *Ts TSRMLS_DC) +static inline void zend_get_cv_address(zend_uchar utype, zend_compiled_variable *cv, zval ***ptr, temp_variable *Ts TSRMLS_DC) { - zval *new_zval = &EG(uninitialized_zval); + zval *new_zval = &EG(uninitialized_zval); - new_zval->refcount++; - zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &new_zval, sizeof(zval *), (void **)ptr); + new_zval->refcount++; + zend_u_hash_quick_update(EG(active_symbol_table), utype, cv->name, cv->name_len+1, cv->hash_value, &new_zval, sizeof(zval *), (void **)ptr); } static inline zval *_get_zval_ptr_tmp(znode *node, temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) @@ -163,35 +164,53 @@ static inline zval *_get_zval_ptr_tmp(znode *node, temp_variable *Ts, zend_free_ static inline zval *_get_zval_ptr_var(znode *node, temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) { - zval *ptr = T(node->u.var).var.ptr; - if (ptr) { - PZVAL_UNLOCK(ptr, should_free); - return ptr; + if (T(node->u.var).var.ptr) { + PZVAL_UNLOCK(T(node->u.var).var.ptr, should_free); + return T(node->u.var).var.ptr; } else { temp_variable *T = &T(node->u.var); zval *str = T->str_offset.str; + zval *ptr; /* string offset */ ALLOC_ZVAL(ptr); T->str_offset.ptr = ptr; should_free->var = ptr; - if (T->str_offset.str->type != IS_STRING - || ((int)T->str_offset.offset<0) - || (T->str_offset.str->value.str.len <= T->str_offset.offset)) { - zend_error(E_NOTICE, "Uninitialized string offset: %d", T->str_offset.offset); - ptr->value.str.val = STR_EMPTY_ALLOC(); - ptr->value.str.len = 0; + /* T->str_offset.str here is always IS_STRING or IS_UNICODE */ + if (T->str_offset.str->type == IS_STRING || T->str_offset.str->type == IS_BINARY) { + if (((int)T->str_offset.offset<0) + || (T->str_offset.str->value.str.len <= T->str_offset.offset)) { + zend_error(E_NOTICE, "Uninitialized string offset: %d", T->str_offset.offset); + ptr->value.str.val = STR_EMPTY_ALLOC(); + ptr->value.str.len = 0; + } else { + char c = str->value.str.val[T->str_offset.offset]; + + ptr->value.str.val = estrndup(&c, 1); + ptr->value.str.len = 1; + } + ptr->type = T->str_offset.str->type; } else { - char c = str->value.str.val[T->str_offset.offset]; + if (((int)T->str_offset.offset<0) + || (Z_USTRCPLEN_P(T->str_offset.str) <= T->str_offset.offset)) { + zend_error(E_NOTICE, "Uninitialized string offset: %d", T->str_offset.offset); + ptr->value.ustr.val = USTR_MAKE(""); + ptr->value.ustr.len = 0; + } else { + UChar32 c = zend_get_codepoint_at(str->value.ustr.val, str->value.ustr.len, T->str_offset.offset); + int32_t i = 0; - ptr->value.str.val = estrndup(&c, 1); - ptr->value.str.len = 1; + ptr->value.ustr.val = eumalloc(3); /* potentially 2 code units + null */ + U16_APPEND_UNSAFE(ptr->value.ustr.val, i, c); + ptr->value.ustr.val[i] = 0; + ptr->value.ustr.len = i; + } + ptr->type = IS_UNICODE; } PZVAL_UNLOCK_FREE(str); ptr->refcount=1; ptr->is_ref=1; - ptr->type = IS_STRING; return ptr; } } @@ -202,20 +221,22 @@ static inline zval *_get_zval_ptr_cv(znode *node, temp_variable *Ts, int type TS if (!*ptr) { zend_compiled_variable *cv = &CV_DEF_OF(node->u.var); - if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; + + if (zend_u_hash_quick_find(EG(active_symbol_table), utype, cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + zend_error(E_NOTICE, "Undefined variable: %v", cv->name); /* break missing intentionally */ case BP_VAR_IS: return &EG(uninitialized_zval); break; case BP_VAR_RW: - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + zend_error(E_NOTICE, "Undefined variable: %v", cv->name); /* break missing intentionally */ case BP_VAR_W: - zend_get_cv_address(cv, ptr, Ts TSRMLS_CC); + zend_get_cv_address(utype, cv, ptr, Ts TSRMLS_CC); break; } } @@ -270,20 +291,22 @@ static inline zval **_get_zval_ptr_ptr_cv(znode *node, temp_variable *Ts, int ty if (!*ptr) { zend_compiled_variable *cv = &CV_DEF_OF(node->u.var); - if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; + + if (zend_u_hash_quick_find(EG(active_symbol_table), utype, cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + zend_error(E_NOTICE, "Undefined variable: %v", cv->name); /* break missing intentionally */ case BP_VAR_IS: return &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + zend_error(E_NOTICE, "Undefined variable: %v", cv->name); /* break missing intentionally */ case BP_VAR_W: - zend_get_cv_address(cv, ptr, Ts TSRMLS_CC); + zend_get_cv_address(utype, cv, ptr, Ts TSRMLS_CC); break; } } @@ -435,7 +458,8 @@ static inline void make_real_object(zval **object_ptr TSRMLS_DC) /* this should modify object only if it's empty */ if ((*object_ptr)->type == IS_NULL || ((*object_ptr)->type == IS_BOOL && (*object_ptr)->value.lval==0) - || ((*object_ptr)->type == IS_STRING && (*object_ptr)->value.str.len == 0)) { + || (((*object_ptr)->type == IS_STRING && (*object_ptr)->type == IS_BINARY) && (*object_ptr)->value.str.len == 0) + || ((*object_ptr)->type == IS_UNICODE && (*object_ptr)->value.ustr.len == 0)) { if (!PZVAL_IS_REF(*object_ptr)) { SEPARATE_ZVAL(object_ptr); } @@ -459,9 +483,9 @@ static inline void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zv if (cur_arg_info->class_name) { if (!arg) { if(ptr && ptr->op_array) { - zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %s, called in %s on line %d and defined", arg_num, cur_arg_info->class_name, ptr->op_array->filename, ptr->opline->lineno); + zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %v, called in %s on line %d and defined", arg_num, cur_arg_info->class_name, ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %s", arg_num, cur_arg_info->class_name); + zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %v", arg_num, cur_arg_info->class_name); } } switch (Z_TYPE_P(arg)) { @@ -475,7 +499,7 @@ static inline void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zv } break; case IS_OBJECT: { - zend_class_entry *ce = zend_fetch_class(cur_arg_info->class_name, cur_arg_info->class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); + zend_class_entry *ce = zend_u_fetch_class(UG(unicode)?IS_UNICODE:IS_STRING, cur_arg_info->class_name, cur_arg_info->class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); if (!instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { char *error_msg; @@ -485,18 +509,18 @@ static inline void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zv error_msg = "be an instance of"; } if(ptr && ptr->op_array) { - zend_error_noreturn(E_ERROR, "Argument %d must %s %s, called in %s on line %d and defined", arg_num, error_msg, ce->name, ptr->op_array->filename, ptr->opline->lineno); + zend_error_noreturn(E_ERROR, "Argument %d must %s %v, called in %s on line %d and defined", arg_num, error_msg, ce->name, ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error_noreturn(E_ERROR, "Argument %d must %s %s", arg_num, error_msg, ce->name); + zend_error_noreturn(E_ERROR, "Argument %d must %s %v", arg_num, error_msg, ce->name); } } } break; default: if(ptr && ptr->op_array) { - zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %s, called in %s on line %d and defined", arg_num, cur_arg_info->class_name, ptr->op_array->filename, ptr->opline->lineno); + zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %v, called in %s on line %d and defined", arg_num, cur_arg_info->class_name, ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %s", arg_num, cur_arg_info->class_name); + zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %v", arg_num, cur_arg_info->class_name); } break; } @@ -569,9 +593,9 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode value->refcount = 0; dup = zend_get_object_classname(orig_value, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HANDLER_P(value, clone_obj) == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", class_name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", class_name); value->value.obj = Z_OBJ_HANDLER_P(orig_value, clone_obj)(orig_value TSRMLS_CC); if(!dup) { efree(class_name); @@ -635,7 +659,12 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 if (!variable_ptr_ptr) { temp_variable *T = &T(op1->u.var); - if (T->str_offset.str->type == IS_STRING) do { + if (UG(unicode) && Z_TYPE_P(T->str_offset.str) == IS_STRING && value->type != IS_STRING) { + convert_to_unicode(T->str_offset.str); + } + + if (Z_TYPE_P(T->str_offset.str) == IS_STRING || + Z_TYPE_P(T->str_offset.str) == IS_BINARY) do { zval tmp; zval *final_value = value; @@ -659,9 +688,9 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 T->str_offset.str->value.str.len = T->str_offset.offset+1; } - if (value->type!=IS_STRING) { + if (value->type!=IS_STRING && value->type!=IS_BINARY) { tmp = *value; - if (op2->op_type & (IS_VAR|IS_CV)) { + if (op2->op_type & (IS_VAR|IS_CV|IS_CONST)) { zval_copy_ctor(&tmp); } convert_to_string(&tmp); @@ -686,6 +715,53 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 T(result->u.var).var = &T->str_offset.str; */ } while (0); + else if (T->str_offset.str->type == IS_UNICODE) do { + zval tmp; + zval *final_value = value; + + if (((int)T->str_offset.offset < 0)) { + zend_error(E_WARNING, "Illegal string offset: %d", T->str_offset.offset); + break; + } + if (T->str_offset.offset >= T->str_offset.str->value.ustr.len) { + zend_uint i; + + if (T->str_offset.str->value.ustr.len==0) { + USTR_FREE(T->str_offset.str->value.ustr.val); + T->str_offset.str->value.ustr.val = eumalloc(T->str_offset.offset+1+1); + } else { + T->str_offset.str->value.ustr.val = eurealloc(T->str_offset.str->value.ustr.val, T->str_offset.offset+1+1); + } + for (i=T->str_offset.str->value.ustr.len; istr_offset.offset; i++) { + T->str_offset.str->value.ustr.val[i] = 0x20; /* ' ' */ + } + T->str_offset.str->value.ustr.val[T->str_offset.offset+1] = 0; + T->str_offset.str->value.ustr.len = T->str_offset.offset+1; + } + + if (value->type!=IS_UNICODE) { + tmp = *value; + if (op2->op_type & (IS_VAR|IS_CV|IS_CONST)) { + zval_copy_ctor(&tmp); + } + convert_to_unicode(&tmp); + final_value = &tmp; + } + + T->str_offset.str->value.ustr.val[T->str_offset.offset] = final_value->value.ustr.val[0]; + + if (op2->op_type == IS_TMP_VAR) { + if (final_value == &T(op2->u.var).tmp_var) { + /* we can safely free final_value here + * because separation is done only + * in case op2->op_type == IS_VAR */ + USTR_FREE(final_value->value.ustr.val); + } + } + if (final_value == &tmp) { + zval_dtor(final_value); + } + } while (0); /* zval_ptr_dtor(&T->str_offset.str); Nuke this line if it doesn't cause a leak */ /* T(result->u.var).var.ptr_ptr = &EG(uninitialized_zval_ptr); */ @@ -727,7 +803,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 dup = zend_get_object_classname(value, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HANDLER_P(value, clone_obj) == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", class_name); } else if (PZVAL_IS_REF(variable_ptr)) { if (variable_ptr != value) { zend_uint refcount = variable_ptr->refcount; @@ -740,7 +816,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 *variable_ptr = *value; variable_ptr->refcount = refcount; variable_ptr->is_ref = 1; - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", class_name); variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); if (type != IS_TMP_VAR) { value->refcount--; @@ -759,7 +835,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 } *variable_ptr = *value; INIT_PZVAL(variable_ptr); - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", class_name); variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); zval_ptr_dtor(&value); } @@ -867,14 +943,14 @@ static inline void zend_receive(zval **variable_ptr_ptr, zval *value TSRMLS_DC) dup = zend_get_object_classname(value, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HANDLER_P(value, clone_obj) == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", class_name); } else { variable_ptr->refcount--; ALLOC_ZVAL(variable_ptr); *variable_ptr_ptr = variable_ptr; *variable_ptr = *value; INIT_PZVAL(variable_ptr); - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", class_name); variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); } if (!dup) { @@ -925,7 +1001,7 @@ static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_vari case ZEND_FETCH_STATIC: if (!EG(active_op_array)->static_variables) { ALLOC_HASHTABLE(EG(active_op_array)->static_variables); - zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); } return EG(active_op_array)->static_variables; break; @@ -939,39 +1015,61 @@ static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, zval *dim zval **retval; char *offset_key; int offset_key_length; + zend_uchar ztype = dim->type; + int free_offset = 0; - switch (dim->type) { + switch (ztype) { case IS_NULL: + ztype = IS_STRING; offset_key = ""; - offset_key_length = 0; + offset_key_length = 1; goto fetch_string_dim; case IS_STRING: + case IS_BINARY: + case IS_UNICODE: - offset_key = dim->value.str.val; - offset_key_length = dim->value.str.len; + offset_key = Z_UNIVAL_P(dim); + offset_key_length = Z_UNILEN_P(dim)+1; fetch_string_dim: - if (zend_symtable_find(ht, offset_key, offset_key_length+1, (void **) &retval) == FAILURE) { + if (UG(unicode) && ht == &EG(symbol_table) && ztype == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_key_length, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_key_length = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, ztype, offset_key, offset_key_length, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: - zend_error(E_NOTICE, "Undefined index: %s", offset_key); + zend_error(E_NOTICE, "Undefined index: %R", ztype, offset_key); /* break missing intentionally */ case BP_VAR_UNSET: case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined index: %s", offset_key); + zend_error(E_NOTICE,"Undefined index: %R", ztype, offset_key); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_symtable_update(ht, offset_key, offset_key_length+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_symtable_update(ht, ztype, offset_key, offset_key_length, &new_zval, sizeof(zval *), (void **) &retval); } break; } } + if (free_offset) { + efree(offset_key); + } break; case IS_RESOURCE: zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", dim->value.lval, dim->value.lval); @@ -1049,7 +1147,8 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container if (container->type==IS_NULL || (container->type==IS_BOOL && container->value.lval==0) - || (container->type==IS_STRING && container->value.str.len==0)) { + || ((container->type==IS_STRING || container->type==IS_BINARY) && container->value.str.len==0) + || (container->type==IS_UNICODE && container->value.ustr.len==0)) { switch (type) { case BP_VAR_RW: case BP_VAR_W: @@ -1098,6 +1197,8 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container } break; } + case IS_UNICODE: + case IS_BINARY: case IS_STRING: { zval tmp; @@ -1220,7 +1321,8 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_ /* this should modify object only if it's empty */ if (container->type == IS_NULL || (container->type == IS_BOOL && container->value.lval==0) - || (container->type == IS_STRING && container->value.str.len == 0)) { + || ((container->type==IS_STRING || container->type==IS_BINARY) && container->value.str.len==0) + || (container->type==IS_UNICODE && container->value.ustr.len==0)) { switch (type) { case BP_VAR_RW: case BP_VAR_W: diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index bf7657ed0f..ad05ea7719 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -65,8 +65,11 @@ static inline void safe_free_zval_ptr_rel(zval *p ZEND_FILE_LINE_DC ZEND_FILE_LI } } ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); +ZEND_API int zend_u_lookup_class(zend_uchar type, void *name, int name_length, zend_class_entry ***ce TSRMLS_DC); ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); +ZEND_API int zend_u_eval_string(zend_uchar type, void *str, zval *retval_ptr, char *string_name TSRMLS_DC); +ZEND_API int zend_u_eval_string_ex(zend_uchar type, void *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); static inline int i_zend_is_true(zval *op) { @@ -85,6 +88,7 @@ static inline int i_zend_is_true(zval *op) result = (op->value.dval ? 1 : 0); break; case IS_STRING: + case IS_BINARY: if (op->value.str.len == 0 || (op->value.str.len==1 && op->value.str.val[0]=='0')) { result = 0; @@ -92,6 +96,14 @@ static inline int i_zend_is_true(zval *op) result = 1; } break; + case IS_UNICODE: + if (op->value.ustr.len == 0 + || (op->value.ustr.len==1 && op->value.ustr.val[0]=='0')) { + result = 0; + } else { + result = 1; + } + break; case IS_ARRAY: result = (zend_hash_num_elements(op->value.ht)?1:0); break; @@ -155,6 +167,7 @@ ZEND_API void zend_set_timeout(long seconds); ZEND_API void zend_unset_timeout(TSRMLS_D); ZEND_API void zend_timeout(int dummy); ZEND_API zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC); +ZEND_API zend_class_entry *zend_u_fetch_class(zend_uchar type, void *class_name, uint class_name_len, int fetch_type TSRMLS_DC); void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC); #ifdef ZEND_WIN32 @@ -172,10 +185,12 @@ void zend_shutdown_timeout_thread(); /* The following tries to resolve the classname of a zval of type object. * Since it is slow it should be only used in error messages. */ -#define Z_OBJ_CLASS_NAME_P(zval) ((zval) && (zval)->type == IS_OBJECT && Z_OBJ_HT_P(zval)->get_class_entry != NULL && Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC) ? Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC)->name : "") +#define Z_OBJ_CLASS_NAME_P(zval) ((zval) && (zval)->type == IS_OBJECT && Z_OBJ_HT_P(zval)->get_class_entry != NULL && Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC) ? Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC)->name : EMPTY_STR) ZEND_API zval** zend_get_compiled_variable_value(zend_execute_data *execute_data_ptr, zend_uint var); +void init_unicode_strings(); + #define ZEND_USER_OPCODE_CONTINUE 0 /* execute next opcode */ #define ZEND_USER_OPCODE_RETURN 1 /* exit from executor (return from function) */ #define ZEND_USER_OPCODE_DISPATCH 2 /* call original opcode handler */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 4a131ccf29..94e462a33e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -50,6 +50,16 @@ static DWORD timeout_thread_id; static int timeout_thread_initialized=0; #endif +static UChar u_main[sizeof("main")]; +static UChar u_return[sizeof("return ")]; +static UChar u_semicolon[sizeof(" ;")]; + +void init_unicode_strings() { + u_charsToUChars("main", u_main, sizeof("main")); + u_charsToUChars("return ", u_return, sizeof("return ")); + u_charsToUChars(" ;", u_semicolon, sizeof(" ;")); +} + #if ZEND_DEBUG static void (*original_sigsegv_handler)(int); static void zend_handle_sigsegv(int dummy) @@ -143,7 +153,7 @@ void init_executor(TSRMLS_D) zend_ptr_stack_init(&EG(argument_stack)); zend_ptr_stack_push(&EG(argument_stack), (void *) NULL); - zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); { zval *globals; @@ -303,7 +313,7 @@ ZEND_API char *get_active_class_name(char **space TSRMLS_DC) if (space) { *space = ""; } - return ""; + return EMPTY_STR; } switch (EG(function_state_ptr)->function->type) { case ZEND_USER_FUNCTION: @@ -314,13 +324,13 @@ ZEND_API char *get_active_class_name(char **space TSRMLS_DC) if (space) { *space = ce ? "::" : ""; } - return ce ? ce->name : ""; + return ce ? ce->name : EMPTY_STR; } default: if (space) { *space = ""; } - return ""; + return EMPTY_STR; } } @@ -336,6 +346,8 @@ ZEND_API char *get_active_function_name(TSRMLS_D) if (function_name) { return function_name; + } else if (UG(unicode)) { + return (char*) u_main; } else { return "main"; } @@ -429,11 +441,11 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) refcount = p->refcount; is_ref = p->is_ref; - if (!zend_get_constant(p->value.str.val, p->value.str.len, &const_value TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - p->value.str.val, - p->value.str.val); - p->type = IS_STRING; + if (!zend_get_constant(Z_UNIVAL_P(p), Z_UNILEN_P(p), &const_value TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %v - assumed '%v'", + Z_UNIVAL_P(p), + Z_UNIVAL_P(p)); + p->type = UG(unicode)?IS_UNICODE:IS_STRING; if (!inline_change) { zval_copy_ctor(p); } @@ -464,7 +476,7 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) continue; } Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; - if (zend_hash_get_current_key_ex(p->value.ht, &str_index, &str_index_len, &num_index, 0, NULL)!=HASH_KEY_IS_STRING) { + if (zend_hash_get_current_key_ex(p->value.ht, &str_index, &str_index_len, &num_index, 0, NULL) != (UG(unicode)?HASH_KEY_IS_UNICODE:HASH_KEY_IS_STRING)) { zend_hash_move_forward(p->value.ht); continue; } @@ -474,13 +486,25 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) continue; } - if (const_value.type == IS_STRING && const_value.value.str.len == str_index_len-1 && + if (UG(unicode)) { + if (const_value.type == IS_UNICODE && + const_value.value.ustr.len == str_index_len-1 && + !u_strncmp(Z_USTRVAL(const_value), (UChar*)str_index, str_index_len)) { + /* constant value is the same as its name */ + zval_dtor(&const_value); + zend_hash_move_forward(p->value.ht); + continue; + } + } else { + if (const_value.type == IS_STRING && + const_value.value.str.len == str_index_len-1 && !strncmp(const_value.value.str.val, str_index, str_index_len)) { /* constant value is the same as its name */ zval_dtor(&const_value); zend_hash_move_forward(p->value.ht); continue; } + } ALLOC_ZVAL(new_val); *new_val = **element; @@ -498,13 +522,27 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) long lval; double dval; - if (is_numeric_string(const_value.value.str.val, const_value.value.str.len, &lval, &dval, 0) == IS_LONG) { + if (is_numeric_string(Z_STRVAL(const_value), Z_STRLEN(const_value), &lval, &dval, 0) == IS_LONG) { + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, lval); + } else { + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, Z_STRVAL(const_value), Z_STRLEN(const_value)+1, 0); + } + break; + } + case IS_UNICODE: { + long lval; + double dval; + + if (is_numeric_unicode(Z_USTRVAL(const_value), Z_USTRLEN(const_value), &lval, &dval, 0) == IS_LONG) { zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, lval); } else { - zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, const_value.value.str.val, const_value.value.str.len+1, 0); + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_UNICODE, Z_USTRVAL(const_value), Z_USTRLEN(const_value)+1, 0); } break; } + case IS_BINARY: + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_BINARY, Z_STRVAL(const_value), Z_STRLEN(const_value)+1, 0); + break; case IS_BOOL: case IS_LONG: zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, const_value.value.lval); @@ -587,6 +625,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zval *method_name; zval *params_array; int call_via_handler = 0; + char *old_func_name = NULL; if (EG(exception)) { return FAILURE; /* we would result in an instable executor otherwise */ @@ -649,18 +688,23 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS calling_scope = Z_OBJCE_PP(fci->object_pp); fci->function_table = &calling_scope->function_table; EX(object) = *fci->object_pp; - } else if (Z_TYPE_PP(fci->object_pp) == IS_STRING) { + } else if (Z_TYPE_PP(fci->object_pp) == IS_STRING || + Z_TYPE_PP(fci->object_pp) == IS_UNICODE) { zend_class_entry **ce; int found = FAILURE; - if (EG(active_op_array) && strcmp(Z_STRVAL_PP(fci->object_pp), "self") == 0) { + if (EG(active_op_array) && + Z_UNILEN_PP(fci->object_pp) == sizeof("self")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "self", sizeof("self")-1)) { if (!EG(active_op_array)->scope) { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); } ce = &(EG(active_op_array)->scope); found = (*ce != NULL?SUCCESS:FAILURE); fci->object_pp = EG(This)?&EG(This):NULL; - } else if (strcmp(Z_STRVAL_PP(fci->object_pp), "parent") == 0 && EG(active_op_array)) { + } else if (EG(active_op_array) && + Z_UNILEN_PP(fci->object_pp) == sizeof("parent")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "parent", sizeof("parent")-1)) { if (!EG(active_op_array)->scope) { zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); @@ -675,9 +719,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_class_entry *scope; scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; - found = zend_lookup_class(Z_STRVAL_PP(fci->object_pp), Z_STRLEN_PP(fci->object_pp), &ce TSRMLS_CC); + found = zend_u_lookup_class(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), &ce TSRMLS_CC); if (found == FAILURE) { - zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(fci->object_pp)); + zend_error(E_ERROR, "Class '%R' not found", Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp)); } if (scope && EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) && @@ -702,16 +746,24 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } } - if (fci->function_name->type!=IS_STRING) { + if (fci->function_name->type != IS_STRING && + fci->function_name->type != IS_UNICODE) { return FAILURE; } + if (UG(unicode) && fci->function_name->type == IS_STRING) { + old_func_name = Z_STRVAL_P(fci->function_name); + + Z_STRVAL_P(fci->function_name) = estrndup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name)); + convert_to_unicode(fci->function_name); + } + if (fci->object_pp) { if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) { zend_error(E_ERROR, "Object does not support method calls"); } EX(function_state).function = - Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name) TSRMLS_CC); + Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, Z_UNIVAL_P(fci->function_name), Z_UNILEN_P(fci->function_name) TSRMLS_CC); if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) { char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name)); if (zend_hash_find(&calling_scope->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { @@ -721,18 +773,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS efree(function_name_lc); } } else if (calling_scope) { - char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name)); + unsigned int lcname_len; + char *lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name), Z_UNILEN_P(fci->function_name), 1, &lcname_len); EX(function_state).function = - zend_std_get_static_method(calling_scope, function_name_lc, Z_STRLEN_P(fci->function_name) TSRMLS_CC); - efree(function_name_lc); + zend_std_get_static_method(calling_scope, lcname, lcname_len TSRMLS_CC); + efree(lcname); } else { - char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name)); + unsigned int lcname_len; + char *lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name), Z_UNILEN_P(fci->function_name), 1, &lcname_len); - if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + if (zend_u_hash_find(fci->function_table, Z_TYPE_P(fci->function_name), lcname, lcname_len+1, (void **) &EX(function_state).function)==FAILURE) { EX(function_state).function = NULL; } - efree(function_name_lc); + efree(lcname); } if (EX(function_state).function == NULL) { @@ -846,7 +900,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else { severity = E_ERROR; } - zend_error(severity, "Non-static method %s::%s() cannot be called statically", calling_scope->name, EX(function_state).function->common.function_name); + zend_error(severity, "Non-static method %v::%v() cannot be called statically", calling_scope->name, EX(function_state).function->common.function_name); } } @@ -860,7 +914,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EG(active_symbol_table) = fci->symbol_table; } else { ALLOC_HASHTABLE(EG(active_symbol_table)); - zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); } original_return_value = EG(return_value_ptr_ptr); @@ -902,17 +956,23 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (EG(exception)) { zend_throw_exception_internal(NULL TSRMLS_CC); } + if (old_func_name) { + efree(Z_STRVAL_P(fci->function_name)); + Z_TYPE_P(fci->function_name) = IS_STRING; + Z_STRVAL_P(fci->function_name) = old_func_name; + } return SUCCESS; } -ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) +ZEND_API int zend_u_lookup_class(zend_uchar type, void *name, int name_length, zend_class_entry ***ce TSRMLS_DC) { zval **args[1]; zval autoload_function; zval *class_name_ptr; zval *retval_ptr; int retval; + unsigned int lc_name_len; char *lc_name; zval *exception; char dummy = 1; @@ -923,11 +983,10 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** return FAILURE; } - lc_name = do_alloca(name_length + 1); - zend_str_tolower_copy(lc_name, name, name_length); + lc_name = zend_u_str_case_fold(type, name, name_length, 1, &lc_name_len); - if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) { - free_alloca(lc_name); + if (zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) ce) == SUCCESS) { + efree(lc_name); return SUCCESS; } @@ -935,17 +994,17 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** * (doesn't impact fuctionality of __autoload() */ if (zend_is_compiling(TSRMLS_C)) { - free_alloca(lc_name); + efree(lc_name); return FAILURE; } if (EG(in_autoload) == NULL) { ALLOC_HASHTABLE(EG(in_autoload)); - zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); + zend_u_hash_init(EG(in_autoload), 0, NULL, NULL, 0, UG(unicode)); } - if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - free_alloca(lc_name); + if (zend_u_hash_add(EG(in_autoload), type, lc_name, lc_name_len+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + efree(lc_name); return FAILURE; } @@ -953,7 +1012,11 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** ALLOC_ZVAL(class_name_ptr); INIT_PZVAL(class_name_ptr); - ZVAL_STRINGL(class_name_ptr, name, name_length, 1); + if (type == IS_UNICODE) { + ZVAL_UNICODEL(class_name_ptr, name, name_length, 1); + } else { + ZVAL_STRINGL(class_name_ptr, name, name_length, 1); + } args[0] = &class_name_ptr; @@ -979,17 +1042,17 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** zval_ptr_dtor(&class_name_ptr); - zend_hash_del(EG(in_autoload), lc_name, name_length+1); + zend_u_hash_del(EG(in_autoload), type, lc_name, lc_name_len+1); if (retval == FAILURE) { EG(exception) = exception; - free_alloca(lc_name); + efree(lc_name); return FAILURE; } if (EG(exception) && exception) { - free_alloca(lc_name); - zend_error(E_ERROR, "Function %s(%s) threw an exception of type '%s'", ZEND_AUTOLOAD_FUNC_NAME, name, Z_OBJCE_P(EG(exception))->name); + efree(lc_name); + zend_error(E_ERROR, "Function %s(%R) threw an exception of type '%v'", ZEND_AUTOLOAD_FUNC_NAME, type, name, Z_OBJCE_P(EG(exception))->name); return FAILURE; } if (!EG(exception)) { @@ -997,12 +1060,17 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** zval_ptr_dtor(&retval_ptr); } - retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce); - free_alloca(lc_name); + retval = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len + 1, (void **) ce); + efree(lc_name); return retval; } -ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) +ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) +{ + return zend_u_lookup_class(IS_STRING, name, name_length, ce TSRMLS_CC); +} + +ZEND_API int zend_u_eval_string(zend_uchar type, void *string, zval *retval_ptr, char *string_name TSRMLS_DC) { zval pv; zend_op_array *new_op_array; @@ -1011,17 +1079,34 @@ ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSR zend_uchar original_handle_op_arrays; int retval; - if (retval_ptr) { - pv.value.str.len = strlen(str)+sizeof("return ;")-1; - pv.value.str.val = emalloc(pv.value.str.len+1); - strcpy(pv.value.str.val, "return "); - strcat(pv.value.str.val, str); - strcat(pv.value.str.val, " ;"); + if (type == IS_UNICODE) { + UChar *str = (UChar*)string; + + if (retval_ptr) { + pv.value.ustr.len = u_strlen(str)+sizeof("return ;")-1; + pv.value.ustr.val = eumalloc(pv.value.ustr.len+1); + u_strcpy(pv.value.ustr.val, u_return); + u_strcat(pv.value.ustr.val, str); + u_strcat(pv.value.ustr.val, u_semicolon); + } else { + pv.value.ustr.len = u_strlen(str); + pv.value.ustr.val = eustrndup(str, pv.value.str.len); + } } else { - pv.value.str.len = strlen(str); - pv.value.str.val = estrndup(str, pv.value.str.len); + char *str = (char*)string; + + if (retval_ptr) { + pv.value.str.len = strlen(str)+sizeof("return ;")-1; + pv.value.str.val = emalloc(pv.value.str.len+1); + strcpy(pv.value.str.val, "return "); + strcat(pv.value.str.val, str); + strcat(pv.value.str.val, " ;"); + } else { + pv.value.str.len = strlen(str); + pv.value.str.val = estrndup(str, pv.value.str.len); + } } - pv.type = IS_STRING; + pv.type = type; /*printf("Evaluating '%s'\n", pv.value.str.val);*/ @@ -1068,8 +1153,12 @@ ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSR return retval; } +ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) +{ + return zend_u_eval_string(IS_STRING, str, retval_ptr, string_name TSRMLS_CC); +} -ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) +ZEND_API int zend_u_eval_string_ex(zend_uchar type, void *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) { int result; @@ -1081,6 +1170,11 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, return result; } +ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) +{ + return zend_u_eval_string_ex(IS_STRING, str, retval_ptr, string_name, handle_exceptions TSRMLS_CC); +} + void execute_new_code(TSRMLS_D) { @@ -1324,7 +1418,7 @@ void zend_unset_timeout(TSRMLS_D) } -zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC) +ZEND_API zend_class_entry *zend_u_fetch_class(zend_uchar type, void *class_name, uint class_name_len, int fetch_type TSRMLS_DC) { zend_class_entry **pce; @@ -1344,7 +1438,7 @@ check_fetch_type: } return EG(scope)->parent; case ZEND_FETCH_CLASS_AUTO: { - fetch_type = zend_get_class_fetch_type(class_name, class_name_len); + fetch_type = zend_get_class_fetch_type(type, class_name, class_name_len); if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) { goto check_fetch_type; } @@ -1352,24 +1446,28 @@ check_fetch_type: break; } - if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) { + if (zend_u_lookup_class(type, class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) { if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { - zend_error(E_ERROR, "Interface '%s' not found", class_name); + zend_error(E_ERROR, "Interface '%R' not found", type, class_name); } else { - zend_error(E_ERROR, "Class '%s' not found", class_name); + zend_error(E_ERROR, "Class '%R' not found", type, class_name); } } return *pce; } +zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC) +{ + return zend_u_fetch_class(IS_STRING, class_name, class_name_len, fetch_type TSRMLS_CC); +} #define MAX_ABSTRACT_INFO_CNT 3 -#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" +#define MAX_ABSTRACT_INFO_FMT "%v%s%v%s" #define DISPLAY_ABSTRACT_FN(idx) \ - ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \ + ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : EMPTY_STR, \ ai.afn[idx] ? "::" : "", \ - ai.afn[idx] ? ai.afn[idx]->common.function_name : "", \ + ai.afn[idx] ? ai.afn[idx]->common.function_name : EMPTY_STR, \ ai.afn[idx] && ai.afn[idx+1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "") typedef struct _zend_abstract_info { @@ -1400,7 +1498,7 @@ void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC) zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC); if (ai.cnt) { - zend_error(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", + zend_error(E_ERROR, "Class %v contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", ce->name, ai.cnt, ai.cnt > 1 ? "s" : "", DISPLAY_ABSTRACT_FN(0), @@ -1425,30 +1523,35 @@ ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC) } } -ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC) +ZEND_API int zend_u_delete_global_variable(zend_uchar type, void *name, int name_len TSRMLS_DC) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(name, name_len+1); + ulong hash_value = zend_u_inline_hash_func(type, name, name_len+1); - if (zend_hash_quick_exists(&EG(symbol_table), name, name_len+1, hash_value)) { + if (zend_u_hash_quick_exists(&EG(symbol_table), type, name, name_len+1, hash_value)) { for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { if (ex->symbol_table == &EG(symbol_table)) { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && ex->op_array->vars[i].name_len == name_len && - !memcmp(ex->op_array->vars[i].name, name, name_len)) { + !memcmp(ex->op_array->vars[i].name, name, type==IS_UNICODE?UBYTES(name_len):name_len)) { ex->CVs[i] = NULL; break; } } } } - return zend_hash_del(&EG(symbol_table), name, name_len+1); + return zend_u_hash_del(&EG(symbol_table), type, name, name_len+1); } return FAILURE; } +ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC) +{ + return zend_u_delete_global_variable(IS_STRING, name, name_len TSRMLS_CC); +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index bdbf72e659..1182b4a833 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -5,7 +5,7 @@ | Copyright (c) 1998-2005 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | + | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | @@ -36,9 +36,8 @@ #include "zend_objects_API.h" #include "zend_modules.h" -#ifdef ZEND_MULTIBYTE -#include "zend_multibyte.h" -#endif /* ZEND_MULTIBYTE */ +#include +#include /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -132,17 +131,16 @@ struct _zend_compiler_globals { char *doc_comment; zend_uint doc_comment_len; -#ifdef ZEND_MULTIBYTE - zend_encoding **script_encoding_list; - int script_encoding_list_size; + zend_uchar literal_type; - zend_encoding *internal_encoding; - - /* multibyte utility functions */ - zend_encoding_detector encoding_detector; - zend_encoding_converter encoding_converter; - zend_encoding_oddlen encoding_oddlen; -#endif /* ZEND_MULTIBYTE */ +#ifdef ZTS + HashTable *global_function_table; + HashTable *global_class_table; + HashTable *global_auto_globals_table; + HashTable *global_u_function_table; + HashTable *global_u_class_table; + HashTable *global_u_auto_globals_table; +#endif }; @@ -232,6 +230,11 @@ struct _zend_executor_globals { zend_property_info std_property_info; +#ifdef ZTS + HashTable *global_constants_table; + HashTable *global_u_constants_table; +#endif + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; @@ -286,21 +289,31 @@ struct _zend_scanner_globals { int yy_start_stack_depth; int *yy_start_stack; -#ifdef ZEND_MULTIBYTE - /* original (unfiltered) script */ - char *script_org; - int script_org_size; - - /* filtered script */ - char *script_filtered; - int script_filtered_size; - - /* input/ouput filters */ - zend_encoding_filter input_filter; - zend_encoding_filter output_filter; - zend_encoding *script_encoding; - zend_encoding *internal_encoding; -#endif /* ZEND_MULTIBYTE */ + UConverter *input_conv; /* converter for flex input */ + UConverter *output_conv; /* converter for data from flex output */ + zend_bool encoding_checked; + char* rest_str; + int rest_len; +}; + +struct _zend_unicode_globals { + zend_bool unicode; /* indicates whether full Unicode mode is enabled */ + + UConverter *fallback_encoding_conv; /* converter for default encoding for IS_STRING type */ + UConverter *runtime_encoding_conv; /* runtime encoding converter */ + UConverter *output_encoding_conv; /* output layer converter */ + UConverter *script_encoding_conv; /* default script encoding converter */ + UConverter *http_input_encoding_conv;/* http input encoding converter */ + UConverter *utf8_conv; /* all-purpose UTF-8 converter */ + + uint8_t from_u_error_mode; + UChar subst_char[3]; + uint8_t subst_char_len; + + char *default_locale; + UCollator *default_collator; + + HashTable flex_compatible; }; #endif /* ZEND_GLOBALS_H */ diff --git a/Zend/zend_globals_macros.h b/Zend/zend_globals_macros.h index ce98d15d5b..58d43080fe 100644 --- a/Zend/zend_globals_macros.h +++ b/Zend/zend_globals_macros.h @@ -26,6 +26,7 @@ typedef struct _zend_compiler_globals zend_compiler_globals; typedef struct _zend_executor_globals zend_executor_globals; typedef struct _zend_alloc_globals zend_alloc_globals; typedef struct _zend_scanner_globals zend_scanner_globals; +typedef struct _zend_unicode_globals zend_unicode_globals; /* Compiler */ #ifdef ZTS @@ -78,6 +79,16 @@ extern ZEND_API zend_scanner_globals ini_scanner_globals; #endif +/* Unicode */ +#ifdef ZTS +# define UG(v) TSRMG(unicode_globals_id, zend_unicode_globals *, v) +extern ZEND_API ts_rsrc_id unicode_globals_id; +#else +# define UG(v) (unicode_globals.v) +extern ZEND_API zend_unicode_globals unicode_globals; +#endif + + /* For limited downwards source compatibility */ #define CLS_FETCH() #define ELS_FETCH() diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 407b7627b9..41178883fb 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -5,7 +5,7 @@ | Copyright (c) 1998-2005 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | + | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | @@ -20,6 +20,11 @@ /* $Id$ */ #include "zend.h" +#include "zend_operators.h" +#include "zend_globals.h" + +#include +#include #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ (element)->pNext = (list_head); \ @@ -42,6 +47,21 @@ (ht)->pInternalPointer = (element); \ } +#define UNICODE_KEY(ht, type, arKey, nKeyLength, tmp) \ + if (ht->unicode && type == IS_STRING) { \ + UErrorCode status = U_ZERO_ERROR; \ + UChar *u = NULL; \ + int32_t u_len; \ + TSRMLS_FETCH(); \ + zend_convert_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &u, &u_len, (char*)arKey, nKeyLength-1, &status); \ + if (U_FAILURE(status)) { \ + /* UTODO: */ \ + } \ + type = IS_UNICODE; \ + tmp = arKey = u; \ + } + + #if ZEND_DEBUG #define HT_OK 0 #define HT_IS_DESTROYING 1 @@ -94,16 +114,20 @@ static void _zend_is_inconsistent(HashTable *ht, char *file, int line) static int zend_hash_do_resize(HashTable *ht); -ZEND_API ulong zend_hash_func(char *arKey, uint nKeyLength) +ZEND_API ulong zend_u_hash_func(zend_uchar type, char *arKey, uint nKeyLength) { - return zend_inline_hash_func(arKey, nKeyLength); + return zend_u_inline_hash_func(type, arKey, nKeyLength); } +ZEND_API ulong zend_hash_func(char *arKey, uint nKeyLength) +{ + return zend_u_hash_func(IS_STRING, arKey, nKeyLength); +} #define UPDATE_DATA(ht, p, pData, nDataSize) \ if (nDataSize == sizeof(void*)) { \ - if (!(p)->pDataPtr) { \ - pefree_rel((p)->pData, (ht)->persistent); \ + if ((p)->pData && (p)->pData != &(p)->pDataPtr) { \ + pefree_rel(p->pData, ht->persistent); \ } \ memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \ (p)->pData = &(p)->pDataPtr; \ @@ -134,7 +158,7 @@ ZEND_API ulong zend_hash_func(char *arKey, uint nKeyLength) -ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) +ZEND_API int _zend_u_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode ZEND_FILE_LINE_DC) { uint i = 3; Bucket **tmp; @@ -155,9 +179,10 @@ ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunctio ht->nNextFreeElement = 0; ht->pInternalPointer = NULL; ht->persistent = persistent; + ht->unicode = unicode; ht->nApplyCount = 0; ht->bApplyProtection = 1; - + /* Uses ecalloc() so that Bucket* == NULL */ if (persistent) { tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *)); @@ -171,10 +196,14 @@ ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunctio ht->arBuckets = tmp; } } - + return SUCCESS; } +ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) +{ + return _zend_u_hash_init(ht, nSize, pHashFunction, pDestructor, persistent, 0 ZEND_FILE_LINE_CC); +} ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC) { @@ -184,6 +213,13 @@ ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunc return retval; } +ZEND_API int _zend_u_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode, zend_bool bApplyProtection ZEND_FILE_LINE_DC) +{ + int retval = _zend_u_hash_init(ht, nSize, pHashFunction, pDestructor, persistent, unicode ZEND_FILE_LINE_CC); + + ht->bApplyProtection = bApplyProtection; + return retval; +} ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection) { @@ -192,11 +228,13 @@ ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProt -ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) +ZEND_API int _zend_u_hash_add_or_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) { ulong h; uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; IS_CONSISTENT(ht); @@ -207,43 +245,52 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLengt return FAILURE; } - h = zend_inline_hash_func(arKey, nKeyLength); + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + + h = zend_u_inline_hash_func(type, arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - if (flag & HASH_ADD) { - return FAILURE; - } - HANDLE_BLOCK_INTERRUPTIONS(); + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + if (flag & HASH_ADD) { + if (tmp) efree(tmp); + return FAILURE; + } + HANDLE_BLOCK_INTERRUPTIONS(); #if ZEND_DEBUG - if (p->pData == pData) { - ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n"); - HANDLE_UNBLOCK_INTERRUPTIONS(); - return FAILURE; - } -#endif - if (ht->pDestructor) { - ht->pDestructor(p->pData); - } - UPDATE_DATA(ht, p, pData, nDataSize); - if (pDest) { - *pDest = p->pData; - } + if (p->pData == pData) { + ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n"); HANDLE_UNBLOCK_INTERRUPTIONS(); - return SUCCESS; + if (tmp) efree(tmp); + return FAILURE; } +#endif + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); + if (pDest) { + *pDest = p->pData; + } + HANDLE_UNBLOCK_INTERRUPTIONS(); + if (tmp) efree(tmp); + return SUCCESS; } p = p->pNext; } - - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); + + p = (Bucket *) pemalloc(sizeof(Bucket)-sizeof(p->key.u)+realKeyLength, ht->persistent); if (!p) { + if (tmp) efree(tmp); return FAILURE; } - memcpy(p->arKey, arKey, nKeyLength); + p->key.type = type; + memcpy(&p->key.u, arKey, realKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; @@ -259,13 +306,21 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLengt ht->nNumOfElements++; ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */ + if (tmp) efree(tmp); return SUCCESS; } -ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) +ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) +{ + return _zend_u_hash_add_or_update(ht, IS_STRING, arKey, nKeyLength, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC); +} + +ZEND_API int _zend_u_hash_quick_add_or_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) { uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; IS_CONSISTENT(ht); @@ -273,47 +328,59 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKe return zend_hash_index_update(ht, h, pData, nDataSize, pDest); } + if (ht->unicode && type == IS_STRING) { + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + h = zend_u_inline_hash_func(IS_UNICODE, arKey, nKeyLength); + } + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + nIndex = h & ht->nTableMask; - + p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - if (flag & HASH_ADD) { - return FAILURE; - } - HANDLE_BLOCK_INTERRUPTIONS(); + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + if (flag & HASH_ADD) { + if (tmp) efree(tmp); + return FAILURE; + } + HANDLE_BLOCK_INTERRUPTIONS(); #if ZEND_DEBUG - if (p->pData == pData) { - ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n"); - HANDLE_UNBLOCK_INTERRUPTIONS(); - return FAILURE; - } -#endif - if (ht->pDestructor) { - ht->pDestructor(p->pData); - } - UPDATE_DATA(ht, p, pData, nDataSize); - if (pDest) { - *pDest = p->pData; - } + if (p->pData == pData) { + ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n"); HANDLE_UNBLOCK_INTERRUPTIONS(); - return SUCCESS; + if (tmp) efree(tmp); + return FAILURE; } +#endif + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); + if (pDest) { + *pDest = p->pData; + } + HANDLE_UNBLOCK_INTERRUPTIONS(); + if (tmp) efree(tmp); + return SUCCESS; } p = p->pNext; } - - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); + + p = (Bucket *) pemalloc(sizeof(Bucket)-sizeof(p->key.u)+realKeyLength, ht->persistent); if (!p) { + if (tmp) efree(tmp); return FAILURE; } - memcpy(p->arKey, arKey, nKeyLength); + p->key.type = type; + memcpy(&p->key.u, arKey, realKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; - + CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]); if (pDest) { @@ -327,15 +394,27 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKe ht->nNumOfElements++; ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */ + if (tmp) efree(tmp); return SUCCESS; } +ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) +{ + return _zend_u_hash_quick_add_or_update(ht, IS_STRING, arKey, nKeyLength, h, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC); +} + +ZEND_API int zend_u_hash_add_empty_element(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength) +{ + void *dummy = (void *) 1; + + return zend_u_hash_add(ht, type, arKey, nKeyLength, &dummy, sizeof(void *), NULL); +} ZEND_API int zend_hash_add_empty_element(HashTable *ht, char *arKey, uint nKeyLength) { void *dummy = (void *) 1; - return zend_hash_add(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL); + return zend_u_hash_add(ht, IS_STRING, arKey, nKeyLength, &dummy, sizeof(void *), NULL); } @@ -380,7 +459,7 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void } p = p->pNext; } - p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent); + p = (Bucket *) pemalloc_rel(sizeof(Bucket) - sizeof(p->key.u), ht->persistent); if (!p) { return FAILURE; } @@ -447,22 +526,29 @@ ZEND_API int zend_hash_rehash(HashTable *ht) return SUCCESS; } -ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLength, ulong h, int flag) +ZEND_API int zend_u_hash_del_key_or_index(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, int flag) { uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; IS_CONSISTENT(ht); if (flag == HASH_DEL_KEY) { - h = zend_inline_hash_func(arKey, nKeyLength); + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + h = zend_u_inline_hash_func(type, arKey, nKeyLength); } nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && ((p->nKeyLength == 0) || /* Numeric index */ - ((p->nKeyLength == nKeyLength) && (!memcmp(p->arKey, arKey, nKeyLength))))) { + if ((p->h == h) && + ((p->nKeyLength == 0) || /* Numeric index */ + ((p->nKeyLength == nKeyLength) && + (p->key.type == type) && + (!memcmp(&p->key.u, arKey, realKeyLength))))) { HANDLE_BLOCK_INTERRUPTIONS(); if (p == ht->arBuckets[nIndex]) { ht->arBuckets[nIndex] = p->pNext; @@ -474,7 +560,7 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLen } if (p->pListLast != NULL) { p->pListLast->pListNext = p->pListNext; - } else { + } else { /* Deleting the head of the list */ ht->pListHead = p->pListNext; } @@ -489,19 +575,25 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLen if (ht->pDestructor) { ht->pDestructor(p->pData); } - if (!p->pDataPtr) { + if (p->pData && p->pData != &p->pDataPtr) { pefree(p->pData, ht->persistent); } pefree(p, ht->persistent); HANDLE_UNBLOCK_INTERRUPTIONS(); ht->nNumOfElements--; + if (tmp) efree(tmp); return SUCCESS; } p = p->pNext; } + if (tmp) efree(tmp); return FAILURE; } +ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLength, ulong h, int flag) +{ + return zend_u_hash_del_key_or_index(ht, IS_STRING, arKey, nKeyLength, h, flag); +} ZEND_API void zend_hash_destroy(HashTable *ht) { @@ -518,7 +610,7 @@ ZEND_API void zend_hash_destroy(HashTable *ht) if (ht->pDestructor) { ht->pDestructor(q->pData); } - if (!q->pDataPtr && q->pData) { + if (q->pData && q->pData != &q->pDataPtr) { pefree(q->pData, ht->persistent); } pefree(q, ht->persistent); @@ -544,7 +636,7 @@ ZEND_API void zend_hash_clean(HashTable *ht) if (ht->pDestructor) { ht->pDestructor(q->pData); } - if (!q->pDataPtr && q->pData) { + if (q->pData && q->pData != &q->pDataPtr) { pefree(q->pData, ht->persistent); } pefree(q, ht->persistent); @@ -573,7 +665,7 @@ static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) if (ht->pDestructor) { ht->pDestructor(p->pData); } - if (!p->pDataPtr) { + if (p->pData && p->pData != &p->pDataPtr) { pefree(p->pData, ht->persistent); } retval = p->pListNext; @@ -594,7 +686,7 @@ static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) if (p->pListLast != NULL) { p->pListLast->pListNext = p->pListNext; - } else { + } else { /* Deleting the head of the list */ ht->pListHead = p->pListNext; } @@ -647,7 +739,7 @@ ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht) } /* This is used to selectively delete certain entries from a hashtable. - * destruct() receives the data and decides if the entry should be deleted + * destruct() receives the data and decides if the entry should be deleted * or not */ @@ -703,9 +795,14 @@ ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t de p = ht->pListHead; while (p != NULL) { va_start(args, num_args); - hash_key.arKey = p->arKey; hash_key.nKeyLength = p->nKeyLength; hash_key.h = p->h; + hash_key.type = p->key.type; + if (hash_key.type == IS_UNICODE) { + hash_key.u.unicode = p->key.u.unicode; + } else { + hash_key.u.string = p->key.u.string; + } if (destruct(p->pData, num_args, args, &hash_key)) { p = zend_hash_apply_deleter(ht, p); } else { @@ -732,10 +829,10 @@ ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSR q = p; p = p->pListLast; if (result & ZEND_HASH_APPLY_REMOVE) { - if (q->nKeyLength>0) { - zend_hash_del(ht, q->arKey, q->nKeyLength); - } else { + if (q->nKeyLength==0) { zend_hash_index_del(ht, q->h); + } else { + zend_u_hash_del(ht, q->key.type, &q->key.u.unicode, q->nKeyLength); } } if (result & ZEND_HASH_APPLY_STOP) { @@ -756,10 +853,10 @@ ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_fun p = source->pListHead; while (p) { - if (p->nKeyLength) { - zend_hash_update(target, p->arKey, p->nKeyLength, p->pData, size, &new_entry); + if (p->nKeyLength == 0) { + zend_hash_index_update(target, p->h, p->pData, size, &new_entry); } else { - zend_hash_index_update(target, p->h, p->pData, size, &new_entry); + zend_u_hash_update(target, p->key.type, &p->key.u, p->nKeyLength, p->pData, size, &new_entry); } if (pCopyConstructor) { pCopyConstructor(new_entry); @@ -781,12 +878,12 @@ ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_f p = source->pListHead; while (p) { - if (p->nKeyLength>0) { - if (_zend_hash_add_or_update(target, p->arKey, p->nKeyLength, p->pData, size, &t, mode ZEND_FILE_LINE_RELAY_CC)==SUCCESS && pCopyConstructor) { + if (p->nKeyLength==0) { + if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) { pCopyConstructor(t); } } else { - if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) { + if (_zend_u_hash_add_or_update(target, p->key.type, &p->key.u, p->nKeyLength, p->pData, size, &t, mode ZEND_FILE_LINE_RELAY_CC)==SUCCESS && pCopyConstructor) { pCopyConstructor(t); } } @@ -800,9 +897,14 @@ static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, void *sour { zend_hash_key hash_key; - hash_key.arKey = p->arKey; hash_key.nKeyLength = p->nKeyLength; hash_key.h = p->h; + hash_key.type = p->key.type; + if (hash_key.type == IS_UNICODE) { + hash_key.u.unicode = p->key.u.unicode; + } else { + hash_key.u.string = p->key.u.string; + } return merge_checker_func(target, source_data, &hash_key, pParam); } @@ -818,7 +920,7 @@ ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor p = source->pListHead; while (p) { if (zend_hash_replace_checker_wrapper(target, p->pData, p, pParam, pMergeSource)) { - if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) { + if (zend_u_hash_quick_update(target, p->key.type, &p->key.u, p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) { pCopyConstructor(t); } } @@ -828,9 +930,14 @@ ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor } +ZEND_API ulong zend_u_get_hash_value(zend_uchar type, char *arKey, uint nKeyLength) +{ + return zend_u_inline_hash_func(type, arKey, nKeyLength); +} + ZEND_API ulong zend_get_hash_value(char *arKey, uint nKeyLength) { - return zend_inline_hash_func(arKey, nKeyLength); + return zend_u_get_hash_value(IS_STRING, arKey, nKeyLength); } @@ -838,35 +945,50 @@ ZEND_API ulong zend_get_hash_value(char *arKey, uint nKeyLength) * data is returned in pData. The reason is that there's no reason * someone using the hash table might not want to have NULL data */ -ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData) +ZEND_API int zend_u_hash_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void **pData) { ulong h; uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; IS_CONSISTENT(ht); - h = zend_inline_hash_func(arKey, nKeyLength); + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + + h = zend_u_inline_hash_func(type, arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - *pData = p->pData; - return SUCCESS; - } + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + *pData = p->pData; + if (tmp) efree(tmp); + return SUCCESS; } p = p->pNext; } + if (tmp) efree(tmp); return FAILURE; } +ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData) +{ + return zend_u_hash_find(ht, IS_STRING, arKey, nKeyLength, pData); +} -ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData) + +ZEND_API int zend_u_hash_quick_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, void **pData) { uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; if (nKeyLength==0) { return zend_hash_index_find(ht, h, pData); @@ -874,50 +996,77 @@ ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, u IS_CONSISTENT(ht); + if (ht->unicode && type == IS_STRING) { + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + h = zend_u_inline_hash_func(IS_UNICODE, arKey, nKeyLength); + } + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - *pData = p->pData; - return SUCCESS; - } + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + *pData = p->pData; + if (tmp) efree(tmp); + return SUCCESS; } p = p->pNext; } + if (tmp) efree(tmp); return FAILURE; } +ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData) +{ + return zend_u_hash_quick_find(ht, IS_STRING, arKey, nKeyLength, h, pData); +} -ZEND_API int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength) +ZEND_API int zend_u_hash_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength) { ulong h; uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; IS_CONSISTENT(ht); - h = zend_inline_hash_func(arKey, nKeyLength); + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + + h = zend_u_inline_hash_func(type, arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - return 1; - } + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + if (tmp) efree(tmp); + return 1; } p = p->pNext; } + if (tmp) efree(tmp); return 0; } +ZEND_API int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength) +{ + return zend_u_hash_exists(ht, IS_STRING, arKey, nKeyLength); +} -ZEND_API int zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLength, ulong h) +ZEND_API int zend_u_hash_quick_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h) { uint nIndex; Bucket *p; + void *tmp = NULL; + uint realKeyLength; if (nKeyLength==0) { return zend_hash_index_exists(ht, h); @@ -925,21 +1074,33 @@ ZEND_API int zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLength, IS_CONSISTENT(ht); + if (ht->unicode && type == IS_STRING) { + UNICODE_KEY(ht, type, arKey, nKeyLength, tmp); + h = zend_u_inline_hash_func(type, arKey, nKeyLength); + } + realKeyLength = REAL_KEY_SIZE(type, nKeyLength); + nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { - return 1; - } + if ((p->h == h) && + (p->key.type == type) && + (p->nKeyLength == nKeyLength) && + !memcmp(&p->key.u, arKey, realKeyLength)) { + if (tmp) efree(tmp); + return 1; } p = p->pNext; } + if (tmp) efree(tmp); return 0; - } +ZEND_API int zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLength, ulong h) +{ + return zend_u_hash_quick_exists(ht, IS_STRING, arKey, nKeyLength, h); +} ZEND_API int zend_hash_index_find(HashTable *ht, ulong h, void **pData) { @@ -1001,7 +1162,7 @@ ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *p } -/* This function will be extremely optimized by remembering +/* This function will be extremely optimized by remembering * the end of the list */ ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos) @@ -1053,15 +1214,31 @@ ZEND_API int zend_hash_get_current_key_ex(HashTable *ht, char **str_index, uint if (p) { if (p->nKeyLength) { - if (duplicate) { - *str_index = estrndup(p->arKey, p->nKeyLength - 1); - } else { - *str_index = p->arKey; - } - if (str_length) { - *str_length = p->nKeyLength; + if (p->key.type == IS_STRING || p->key.type == IS_BINARY) { + if (duplicate) { + *str_index = estrndup(p->key.u.string, p->nKeyLength-1); + } else { + *str_index = p->key.u.string; + } + if (str_length) { + *str_length = p->nKeyLength; + } + if (p->key.type == IS_BINARY) { + return HASH_KEY_IS_BINARY; + } else { + return HASH_KEY_IS_STRING; + } + } else if (p->key.type == IS_UNICODE) { + if (duplicate) { + *str_index = (char*)eustrndup(p->key.u.unicode, p->nKeyLength-1); + } else { + *str_index = p->key.u.string; + } + if (str_length) { + *str_length = p->nKeyLength; + } + return HASH_KEY_IS_UNICODE; } - return HASH_KEY_IS_STRING; } else { *num_index = p->h; return HASH_KEY_IS_LONG; @@ -1081,7 +1258,13 @@ ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) if (p) { if (p->nKeyLength) { - return HASH_KEY_IS_STRING; + if (p->key.type == IS_UNICODE) { + return HASH_KEY_IS_UNICODE; + } else if (p->key.type == IS_BINARY) { + return HASH_KEY_IS_BINARY; + } else { + return HASH_KEY_IS_STRING; + } } else { return HASH_KEY_IS_LONG; } @@ -1124,12 +1307,20 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char * return SUCCESS; } zend_hash_index_del(ht, num_index); - } else if (key_type == HASH_KEY_IS_STRING) { + } else if (key_type == HASH_KEY_IS_STRING || key_type == HASH_KEY_IS_BINARY) { + if (p->nKeyLength == str_length && + p->key.type == ((key_type == HASH_KEY_IS_STRING)?IS_STRING:IS_BINARY) && + memcmp(p->key.u.string, str_index, str_length) == 0) { + return SUCCESS; + } + zend_u_hash_del(ht, (key_type == HASH_KEY_IS_STRING)?IS_STRING:IS_BINARY, str_index, str_length); + } else if (key_type == HASH_KEY_IS_UNICODE) { if (p->nKeyLength == str_length && - memcmp(p->arKey, str_index, str_length) == 0) { + p->key.type == IS_UNICODE && + memcmp(p->key.u.string, str_index, str_length * sizeof(UChar*)) == 0) { return SUCCESS; } - zend_hash_del(ht, str_index, str_length); + zend_u_hash_del(ht, IS_UNICODE, str_index, str_length); } else { return FAILURE; } @@ -1179,9 +1370,14 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char * if (key_type == HASH_KEY_IS_LONG) { p->h = num_index; + } else if (key_type == HASH_KEY_IS_UNICODE) { + memcpy(p->key.u.unicode, str_index, str_length * sizeof(UChar)); + p->key.type = IS_UNICODE; + p->h = zend_u_inline_hash_func(IS_UNICODE, str_index, str_length); } else { - memcpy(p->arKey, str_index, str_length); - p->h = zend_inline_hash_func(str_index, str_length); + memcpy(p->key.u.string, str_index, str_length); + p->key.type = (key_type == HASH_KEY_IS_STRING)?IS_STRING:IS_BINARY; + p->h = zend_u_inline_hash_func(p->key.type, str_index, str_length); } CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]); @@ -1266,13 +1462,13 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co IS_CONSISTENT(ht1); IS_CONSISTENT(ht2); - HASH_PROTECT_RECURSION(ht1); - HASH_PROTECT_RECURSION(ht2); + HASH_PROTECT_RECURSION(ht1); + HASH_PROTECT_RECURSION(ht2); result = ht1->nNumOfElements - ht2->nNumOfElements; if (result!=0) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return result; } @@ -1283,29 +1479,29 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co while (p1) { if (ordered && !p2) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return 1; /* That's not supposed to happen */ } if (ordered) { if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */ result = p1->h - p2->h; if (result!=0) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return result; } } else { /* string indices */ - result = p1->nKeyLength - p2->nKeyLength; - if (result!=0) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); - return result; + result = p1->key.type - p2->key.type; + if (result==0) { + result = p1->nKeyLength - p2->nKeyLength; + } + if (result==0) { + result = memcmp(&p1->key.u, &p2->key.u, REAL_KEY_SIZE(p1->key.type, p1->nKeyLength)); } - result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength); if (result!=0) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return result; } } @@ -1313,22 +1509,22 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co } else { if (p1->nKeyLength==0) { /* numeric index */ if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return 1; } - } else { /* string index */ - if (zend_hash_find(ht2, p1->arKey, p1->nKeyLength, &pData2)==FAILURE) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + } else { /* string, binary or unicode index */ + if (zend_u_hash_find(ht2, p1->key.type, &p1->key.u, p1->nKeyLength, &pData2)==FAILURE) { + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return 1; } } } result = compar(p1->pData, pData2 TSRMLS_CC); if (result!=0) { - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return result; } p1 = p1->pListNext; @@ -1336,9 +1532,9 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co p2 = p2->pListNext; } } - - HASH_UNPROTECT_RECURSION(ht1); - HASH_UNPROTECT_RECURSION(ht2); + + HASH_UNPROTECT_RECURSION(ht1); + HASH_UNPROTECT_RECURSION(ht2); return 0; } @@ -1378,6 +1574,147 @@ ZEND_API ulong zend_hash_next_free_element(HashTable *ht) } +#define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ + if (*tmp=='-') { \ + tmp++; \ + } \ + if ((*tmp>='0' && *tmp<='9')) do { /* possibly a numeric index */ \ + char *end=key+length-1; \ + long idx; \ + \ + if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */ \ + break; \ + } \ + while (tmp='0' && *tmp<='9')) { \ + break; \ + } \ + tmp++; \ + } \ + if (tmp==end && *tmp=='\0') { /* a numeric index */ \ + if (*key=='-') { \ + idx = strtol(key, NULL, 10); \ + if (idx!=LONG_MIN) { \ + return func; \ + } \ + } else { \ + idx = strtol(key, NULL, 10); \ + if (idx!=LONG_MAX) { \ + return func; \ + } \ + } \ + } \ + } while (0); \ +} + +#define HANDLE_U_NUMERIC(key, length, func) { \ + register UChar *tmp=key; \ + register int32_t val; \ + \ + if (*tmp=='-') { \ + tmp++; \ + } \ + if ((val = u_digit(*tmp, 10)) >= 0) do { /* possibly a numeric index */ \ + UChar *end=key+length-1; \ + long idx; \ + \ + if (val==0 && length>2) { /* don't accept numbers with leading zeros */ \ + break; \ + } \ + tmp++; \ + while (tmppListTail; while (p != NULL) { - zend_output_debug_string(0, "pListTail has key %s\n", p->arKey); + if (p->key.type == IS_UNICODE) { + /* TODO: ??? */ + } else { + zend_output_debug_string(0, "pListTail has key %s\n", p->key.u.string); + } p = p->pListLast; } } @@ -1399,14 +1740,22 @@ void zend_hash_display(HashTable *ht) for (i = 0; i < ht->nTableSize; i++) { p = ht->arBuckets[i]; while (p != NULL) { - zend_output_debug_string(0, "%s <==> 0x%lX\n", p->arKey, p->h); + if (p->key.type == IS_UNICODE) { + /* TODO: ??? */ + } else { + zend_output_debug_string(0, "%s <==> 0x%lX\n", p->key.u.string, p->h); + } p = p->pNext; } } p = ht->pListTail; while (p != NULL) { - zend_output_debug_string(0, "%s <==> 0x%lX\n", p->arKey, p->h); + if (p->key.type == IS_UNICODE) { + /* TODO: ??? */ + } else { + zend_output_debug_string(0, "%s <==> 0x%lX\n", p->key.u.string, p->h); + } p = p->pListLast; } } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 774c607418..f0aa3e6034 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -28,6 +28,8 @@ #define HASH_KEY_IS_STRING 1 #define HASH_KEY_IS_LONG 2 #define HASH_KEY_NON_EXISTANT 3 +#define HASH_KEY_IS_BINARY 4 +#define HASH_KEY_IS_UNICODE 5 #define HASH_UPDATE (1<<0) #define HASH_ADD (1<<1) @@ -36,6 +38,10 @@ #define HASH_DEL_KEY 0 #define HASH_DEL_INDEX 1 +#define REAL_KEY_SIZE(type, nKeyLength) \ + ((type == IS_UNICODE)?UBYTES(nKeyLength):nKeyLength) + + typedef ulong (*hash_func_t)(char *arKey, uint nKeyLength); typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC); typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC); @@ -45,6 +51,14 @@ typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam); struct _hashtable; +typedef struct _key { + zend_uchar type; + union { + char string[1]; /* Must be last element */ + UChar unicode[1]; /* Must be last element */ + } u; +} HashKey; + typedef struct bucket { ulong h; /* Used for numeric indexing */ uint nKeyLength; @@ -54,7 +68,7 @@ typedef struct bucket { struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; - char arKey[1]; /* Must be last element */ + HashKey key; /* Must be last element */ } Bucket; typedef struct _hashtable { @@ -68,6 +82,7 @@ typedef struct _hashtable { Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; + zend_bool unicode; unsigned char nApplyCount; zend_bool bApplyProtection; #if ZEND_DEBUG @@ -77,9 +92,13 @@ typedef struct _hashtable { typedef struct _zend_hash_key { - char *arKey; - uint nKeyLength; ulong h; + uint nKeyLength; + zend_uchar type; + union { + char *string; + UChar *unicode; + } u; } zend_hash_key; @@ -91,24 +110,38 @@ BEGIN_EXTERN_C() /* startup/shutdown */ ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC); +ZEND_API int _zend_u_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode ZEND_FILE_LINE_DC); ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC); +ZEND_API int _zend_u_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode, zend_bool bApplyProtection ZEND_FILE_LINE_DC); ZEND_API void zend_hash_destroy(HashTable *ht); ZEND_API void zend_hash_clean(HashTable *ht); #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) _zend_hash_init((ht), (nSize), (pHashFunction), (pDestructor), (persistent) ZEND_FILE_LINE_CC) +#define zend_u_hash_init(ht, nSize, pHashFunction, pDestructor, persistent, unicode) _zend_u_hash_init((ht), (nSize), (pHashFunction), (pDestructor), (persistent), (unicode) ZEND_FILE_LINE_CC) #define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) _zend_hash_init_ex((ht), (nSize), (pHashFunction), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC) +#define zend_u_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, unicode, bApplyProtection) _zend_u_hash_init_ex((ht), (nSize), (pHashFunction), (pDestructor), (persistent), (unicode), (bApplyProtection) ZEND_FILE_LINE_CC) /* additions/updates/changes */ ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC); +ZEND_API int _zend_u_hash_add_or_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC); #define zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest) \ _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC) +#define zend_u_hash_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest) \ + _zend_u_hash_add_or_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC) #define zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest) \ _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC) +#define zend_u_hash_add(ht, type, arKey, nKeyLength, pData, nDataSize, pDest) \ + _zend_u_hash_add_or_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC) ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC); +ZEND_API int _zend_u_hash_quick_add_or_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC); #define zend_hash_quick_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) \ _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC) +#define zend_u_hash_quick_update(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest) \ + _zend_u_hash_quick_add_or_update(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC) #define zend_hash_quick_add(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) \ _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC) +#define zend_u_hash_quick_add(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest) \ + _zend_u_hash_quick_add_or_update(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC) ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC); #define zend_hash_index_update(ht, h, pData, nDataSize, pDest) \ @@ -117,6 +150,7 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void _zend_hash_index_update_or_next_insert(ht, 0, pData, nDataSize, pDest, HASH_NEXT_INSERT ZEND_FILE_LINE_CC) ZEND_API int zend_hash_add_empty_element(HashTable *ht, char *arKey, uint nKeyLength); +ZEND_API int zend_u_hash_add_empty_element(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength); #define ZEND_HASH_APPLY_KEEP 0 @@ -145,21 +179,29 @@ ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSR /* Deletes */ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLength, ulong h, int flag); +ZEND_API int zend_u_hash_del_key_or_index(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, int flag); #define zend_hash_del(ht, arKey, nKeyLength) \ zend_hash_del_key_or_index(ht, arKey, nKeyLength, 0, HASH_DEL_KEY) +#define zend_u_hash_del(ht, type, arKey, nKeyLength) \ + zend_u_hash_del_key_or_index(ht, type, arKey, nKeyLength, 0, HASH_DEL_KEY) #define zend_hash_index_del(ht, h) \ zend_hash_del_key_or_index(ht, NULL, 0, h, HASH_DEL_INDEX) ZEND_API ulong zend_get_hash_value(char *arKey, uint nKeyLength); +ZEND_API ulong zend_u_get_hash_value(zend_uchar type, char *arKey, uint nKeyLength); /* Data retreival */ ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData); +ZEND_API int zend_u_hash_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void **pData); ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData); +ZEND_API int zend_u_hash_quick_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h, void **pData); ZEND_API int zend_hash_index_find(HashTable *ht, ulong h, void **pData); /* Misc */ ZEND_API int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength); +ZEND_API int zend_u_hash_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength); ZEND_API int zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLength, ulong h); +ZEND_API int zend_u_hash_quick_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, ulong h); ZEND_API int zend_hash_index_exists(HashTable *ht, ulong h); ZEND_API ulong zend_hash_next_free_element(HashTable *ht); @@ -272,8 +314,11 @@ EMPTY_SWITCH_DEFAULT_CASE() return hash; } +#define zend_u_inline_hash_func(type, arKey, nKeyLength) \ + zend_inline_hash_func(arKey, REAL_KEY_SIZE(type, nKeyLength)) ZEND_API ulong zend_hash_func(char *arKey, uint nKeyLength); +ZEND_API ulong zend_u_hash_func(zend_uchar type, char *arKey, uint nKeyLength); #if ZEND_DEBUG /* debug */ @@ -290,68 +335,15 @@ END_EXTERN_C() zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent) -#define HANDLE_NUMERIC(key, length, func) { \ - register char *tmp=key; \ - \ - if (*tmp=='-') { \ - tmp++; \ - } \ - if ((*tmp>='0' && *tmp<='9')) do { /* possibly a numeric index */ \ - char *end=key+length-1; \ - long idx; \ - \ - if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */ \ - break; \ - } \ - while (tmp='0' && *tmp<='9')) { \ - break; \ - } \ - tmp++; \ - } \ - if (tmp==end && *tmp=='\0') { /* a numeric index */ \ - if (*key=='-') { \ - idx = strtol(key, NULL, 10); \ - if (idx!=LONG_MIN) { \ - return func; \ - } \ - } else { \ - idx = strtol(key, NULL, 10); \ - if (idx!=LONG_MAX) { \ - return func; \ - } \ - } \ - } \ - } while (0); \ -} - - -static inline int zend_symtable_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) \ -{ - HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest)); - return zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest); -} - +ZEND_API int zend_symtable_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest); +ZEND_API int zend_symtable_del(HashTable *ht, char *arKey, uint nKeyLength); +ZEND_API int zend_symtable_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData); +ZEND_API int zend_symtable_exists(HashTable *ht, char *arKey, uint nKeyLength); -static inline int zend_symtable_del(HashTable *ht, char *arKey, uint nKeyLength) -{ - HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx)) - return zend_hash_del(ht, arKey, nKeyLength); -} - - -static inline int zend_symtable_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData) -{ - HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData)); - return zend_hash_find(ht, arKey, nKeyLength, pData); -} - - -static inline int zend_symtable_exists(HashTable *ht, char *arKey, uint nKeyLength) -{ - HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx)); - return zend_hash_exists(ht, arKey, nKeyLength); -} +ZEND_API int zend_u_symtable_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest); +ZEND_API int zend_u_symtable_del(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength); +ZEND_API int zend_u_symtable_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void **pData); +ZEND_API int zend_u_symtable_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength); #endif /* ZEND_HASH_H */ diff --git a/Zend/zend_highlight.c b/Zend/zend_highlight.c index cbd269ed29..980616ebf0 100644 --- a/Zend/zend_highlight.c +++ b/Zend/zend_highlight.c @@ -25,6 +25,7 @@ #include "zend_highlight.h" #include "zend_ptr_stack.h" #include "zend_globals.h" +#include "zend_operators.h" ZEND_API void zend_html_putc(char c) { @@ -96,6 +97,7 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini char *next_color; int in_string=0, post_heredoc = 0; + CG(literal_type) = IS_STRING; zend_printf(""); zend_printf("\n", last_color); /* highlight stuff coming back from zendlex() */ @@ -119,7 +121,7 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini case T_CONSTANT_ENCAPSED_STRING: next_color = syntax_highlighter_ini->highlight_string; break; - case '"': + case '"': next_color = syntax_highlighter_ini->highlight_string; in_string = !in_string; break; @@ -162,7 +164,9 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini break; } - if (token.type == IS_STRING) { + if (token.type == IS_STRING || + token.type == IS_BINARY || + token.type == IS_UNICODE) { switch (token_type) { case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: @@ -172,11 +176,11 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini case T_DOC_COMMENT: break; default: - efree(token.value.str.val); + efree(Z_UNIVAL(token)); break; } } else if (token_type == T_END_HEREDOC) { - efree(token.value.str.val); + efree(Z_UNIVAL(token)); } token.type = 0; } @@ -195,6 +199,7 @@ ZEND_API void zend_strip(TSRMLS_D) int token_type; int prev_space = 0; + CG(literal_type) = IS_STRING; token.type = 0; while ((token_type=lex_scan(&token TSRMLS_CC))) { switch (token_type) { @@ -218,7 +223,7 @@ ZEND_API void zend_strip(TSRMLS_D) if (ptr[LANG_SCNG(yy_leng) - 1] == ';') { lex_scan(&token TSRMLS_CC); } - efree(token.value.str.val); + efree(Z_UNIVAL(token)); } break; @@ -227,7 +232,9 @@ ZEND_API void zend_strip(TSRMLS_D) break; } - if (token.type == IS_STRING) { + if (token.type == IS_STRING || + token.type == IS_BINARY || + token.type == IS_UNICODE) { switch (token_type) { case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: @@ -238,7 +245,7 @@ ZEND_API void zend_strip(TSRMLS_D) break; default: - efree(token.value.str.val); + efree(Z_UNIVAL(token)); break; } } diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 91e320b621..61976052e4 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -134,7 +134,8 @@ static int ini_key_compare(const void *a, const void *b TSRMLS_DC) } else if (s->nKeyLength==0) { /* s is numeric, f is not */ return 1; } else { /* both strings */ - return zend_binary_strcasecmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength); + /*FIXME: unicode hash*/ + return zend_binary_strcasecmp(f->key.u.string, f->nKeyLength, s->key.u.string, s->nKeyLength); } } diff --git a/Zend/zend_ini_scanner.l b/Zend/zend_ini_scanner.l index c18a0695a4..9fb3461c95 100644 --- a/Zend/zend_ini_scanner.l +++ b/Zend/zend_ini_scanner.l @@ -48,6 +48,10 @@ ZEND_API ts_rsrc_id ini_scanner_globals_id; ZEND_API zend_scanner_globals ini_scanner_globals; #endif +# define YY_INPUT(buf, result, max_size) \ + if ( ((result = zend_stream_read(yyin, buf, max_size TSRMLS_CC)) == 0) \ + && zend_stream_ferror( yyin TSRMLS_CC) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); static char *ini_filename; diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 7454311d61..c53a657c66 100755 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -74,7 +74,7 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend if (!fn_proxy || !*fn_proxy) { if (zend_hash_find(function_table, function_name, function_name_len+1, (void **) &fcic.function_handler) == FAILURE) { /* error at c-level */ - zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name : "", obj_ce ? "::" : "", function_name); + zend_error(E_CORE_ERROR, "Couldn't find implementation for method %v%s%s", obj_ce ? obj_ce->name : EMPTY_STR, obj_ce ? "::" : "", function_name); } if (fn_proxy) { *fn_proxy = fcic.function_handler; @@ -91,7 +91,7 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend if (!obj_ce) { obj_ce = object_pp ? Z_OBJCE_PP(object_pp) : NULL; } - zend_error(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? obj_ce->name : "", obj_ce ? "::" : "", function_name); + zend_error(E_CORE_ERROR, "Couldn't execute method %v%s%s", obj_ce ? obj_ce->name : EMPTY_STR, obj_ce ? "::" : "", function_name); } if (!retval_ptr_ptr) { if (retval) { @@ -195,24 +195,36 @@ static int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_ *int_key = 0; if (!EG(exception)) { - zend_error(E_WARNING, "Nothing returned from %s::key()", iter->ce->name); + zend_error(E_WARNING, "Nothing returned from %v::key()", iter->ce->name); } return HASH_KEY_IS_LONG; } switch (retval->type) { default: - zend_error(E_WARNING, "Illegal type returned from %s::key()", iter->ce->name); + zend_error(E_WARNING, "Illegal type returned from %v::key()", iter->ce->name); case IS_NULL: *int_key = 0; zval_ptr_dtor(&retval); return HASH_KEY_IS_LONG; case IS_STRING: - *str_key = estrndup(retval->value.str.val, retval->value.str.len); + *str_key = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); *str_key_len = retval->value.str.len+1; zval_ptr_dtor(&retval); return HASH_KEY_IS_STRING; + case IS_BINARY: + *str_key = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); + *str_key_len = retval->value.str.len+1; + zval_ptr_dtor(&retval); + return HASH_KEY_IS_BINARY; + + case IS_UNICODE: + *str_key = (char*)eustrndup(Z_USTRVAL_P(retval), Z_USTRLEN_P(retval)); + *str_key_len = retval->value.str.len+1; + zval_ptr_dtor(&retval); + return HASH_KEY_IS_UNICODE; + case IS_DOUBLE: case IS_RESOURCE: case IS_BOOL: @@ -286,7 +298,7 @@ static zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, if (!ce || !ce_it || !ce_it->get_iterator || (ce_it->get_iterator == zend_user_it_get_new_iterator && iterator == object)) { if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Objects returned by %s::getIterator() must be traversable or implement interface Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Objects returned by %v::getIterator() must be traversable or implement interface Iterator", ce->name); } if (iterator) { @@ -314,7 +326,7 @@ static int zend_implement_traversable(zend_class_entry *interface, zend_class_en return SUCCESS; } } - zend_error(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s", + zend_error(E_CORE_ERROR, "Class %v must implement interface %v as part of either %v or %v", class_type->name, zend_ce_traversable->name, zend_ce_iterator->name, @@ -550,6 +562,14 @@ ZEND_API void zend_register_interfaces(TSRMLS_D) } /* }}} */ +void init_interfaces(TSRMLS_D) +{ + zend_ce_traversable = zend_get_named_class_entry("Traversable", sizeof("Traversable")-1 TSRMLS_CC); + zend_ce_aggregate = zend_get_named_class_entry("IteratorAggregate", sizeof("IteratorAggregate")-1 TSRMLS_CC); + zend_ce_iterator = zend_get_named_class_entry("Iterator", sizeof("Iterator")-1 TSRMLS_CC); + zend_ce_arrayaccess = zend_get_named_class_entry("ArrayAccess", sizeof("ArrayAccess")-1 TSRMLS_CC); +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_interfaces.h b/Zend/zend_interfaces.h index f2ebdbac37..0894e8ae17 100755 --- a/Zend/zend_interfaces.h +++ b/Zend/zend_interfaces.h @@ -51,6 +51,8 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend ZEND_API void zend_register_interfaces(TSRMLS_D); +void init_interfaces(TSRMLS_D); + END_EXTERN_C() #endif /* ZEND_INTERFACES_H */ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 5861031321..8286e266e0 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -71,7 +71,7 @@ %left '*' '/' '%' %right '!' %nonassoc T_INSTANCEOF -%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@' +%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_UNICODE_CAST T_BINARY_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@' %right '[' %nonassoc T_NEW T_CLONE %token T_EXIT @@ -145,6 +145,8 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM +%token T_BINARY_DOUBLE +%token T_BINARY_HEREDOC %% /* Rules */ @@ -210,7 +212,7 @@ unticked_statement: | T_GLOBAL global_var_list ';' | T_STATIC static_var_list ';' | T_ECHO echo_expr_list ';' - | T_INLINE_HTML { zend_do_echo(&$1 TSRMLS_CC); } + | T_INLINE_HTML { zend_do_echo(&$1, 1 TSRMLS_CC); } | expr ';' { zend_do_free(&$1 TSRMLS_CC); } | T_USE use_filename ';' { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()"); zval_dtor(&$2.u.constant); } | T_UNSET '(' unset_variables ')' ';' @@ -466,8 +468,8 @@ global_var_list: global_var: T_VARIABLE { $$ = $1; } - | '$' r_variable { $$ = $2; } - | '$' '{' expr '}' { $$ = $3; } + | '$' r_variable { zend_do_normalization(&$$, &$2 TSRMLS_CC); } + | '$' '{' expr '}' { zend_do_normalization(&$$, &$3 TSRMLS_CC); } ; @@ -536,8 +538,8 @@ class_constant_declaration: ; echo_expr_list: - echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); } - | expr { zend_do_echo(&$1 TSRMLS_CC); } + echo_expr_list ',' expr { zend_do_echo(&$3, 0 TSRMLS_CC); } + | expr { zend_do_echo(&$1, 0 TSRMLS_CC); } ; @@ -610,6 +612,8 @@ expr_without_variable: | T_INT_CAST expr { zend_do_cast(&$$, &$2, IS_LONG TSRMLS_CC); } | T_DOUBLE_CAST expr { zend_do_cast(&$$, &$2, IS_DOUBLE TSRMLS_CC); } | T_STRING_CAST expr { zend_do_cast(&$$, &$2, IS_STRING TSRMLS_CC); } + | T_UNICODE_CAST expr { zend_do_cast(&$$, &$2, IS_UNICODE TSRMLS_CC); } + | T_BINARY_CAST expr { zend_do_cast(&$$, &$2, UG(unicode)?IS_BINARY:IS_STRING TSRMLS_CC); } | T_ARRAY_CAST expr { zend_do_cast(&$$, &$2, IS_ARRAY TSRMLS_CC); } | T_OBJECT_CAST expr { zend_do_cast(&$$, &$2, IS_OBJECT TSRMLS_CC); } | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); } @@ -618,7 +622,7 @@ expr_without_variable: | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } | scalar { $$ = $1; } | T_ARRAY '(' array_pair_list ')' { $$ = $3; } - | '`' encaps_list '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } + | '`' encaps_list '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } ; @@ -708,9 +712,10 @@ scalar: | T_STRING_VARNAME { $$ = $1; } | class_constant { $$ = $1; } | common_scalar { $$ = $1; } - | '"' encaps_list '"' { $$ = $2; } - | '\'' encaps_list '\'' { $$ = $2; } - | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; zend_do_end_heredoc(TSRMLS_C); } + | '"' { CG(literal_type) = UG(unicode)?IS_UNICODE:IS_STRING; } encaps_list '"' { $$ = $3; } + | T_START_HEREDOC { CG(literal_type) = UG(unicode)?IS_UNICODE:IS_STRING; } encaps_list T_END_HEREDOC { $$ = $3; zend_do_end_heredoc(TSRMLS_C); } + | T_BINARY_DOUBLE { CG(literal_type) = UG(unicode)?IS_BINARY:IS_STRING; } encaps_list '"' { $$ = $3; } + | T_BINARY_HEREDOC { CG(literal_type) = UG(unicode)?IS_BINARY:IS_STRING; } encaps_list T_END_HEREDOC { $$ = $3; zend_do_end_heredoc(TSRMLS_C); } ; @@ -808,7 +813,7 @@ reference_variable: compound_variable: T_VARIABLE { $$ = $1; } - | '$' '{' expr '}' { $$ = $3; } + | '$' '{' expr '}' { zend_do_normalization(&$$, &$3 TSRMLS_CC); } ; dim_offset: @@ -830,7 +835,7 @@ object_dim_list: variable_name: T_STRING { $$ = $1; } - | '{' expr '}' { $$ = $2; } + | '{' expr '}' { zend_do_normalization(&$$, &$2 TSRMLS_CC); } ; simple_indirect_reference: diff --git a/Zend/zend_language_scanner.h b/Zend/zend_language_scanner.h index 7928198f3f..a7778d8d02 100644 --- a/Zend/zend_language_scanner.h +++ b/Zend/zend_language_scanner.h @@ -29,21 +29,11 @@ typedef struct _zend_lex_state { uint lineno; char *filename; -#ifdef ZEND_MULTIBYTE - /* original (unfiltered) script */ - char *script_org; - int script_org_size; - - /* filtered script */ - char *script_filtered; - int script_filtered_size; - - /* input/ouput filters */ - zend_encoding_filter input_filter; - zend_encoding_filter output_filter; - zend_encoding *script_encoding; - zend_encoding *internal_encoding; -#endif /* ZEND_MULTIBYTE */ + UConverter *input_conv; /* converter for flex input */ + UConverter *output_conv; /* converter for data from flex output */ + zend_bool encoding_checked; + char* rest_str; + int rest_len; } zend_lex_state; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index cd6c17f06e..a7ab4ea4e8 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -35,7 +35,6 @@ %x ST_IN_SCRIPTING %x ST_DOUBLE_QUOTES -%x ST_SINGLE_QUOTE %x ST_BACKQUOTE %x ST_HEREDOC %x ST_LOOKING_FOR_PROPERTY @@ -59,6 +58,7 @@ #include "zend_operators.h" #include "zend_API.h" #include "zend_strtod.h" +#include "zend_unicode.h" #ifdef HAVE_STDARG_H # include @@ -87,6 +87,10 @@ ZEND_API ts_rsrc_id language_scanner_globals_id; ZEND_API zend_scanner_globals language_scanner_globals; #endif +#define YY_INPUT(buf, result, max_size) \ + if ( ((result = zend_unicode_yyinput(yyin, buf, max_size TSRMLS_CC)) == 0) \ + && zend_stream_ferror( yyin TSRMLS_CC) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); #define YY_FATAL_ERROR zend_fatal_scanner_error @@ -131,16 +135,12 @@ void startup_scanner(TSRMLS_D) SCNG(yy_start_stack_ptr) = 0; SCNG(yy_start_stack_depth) = 0; SCNG(current_buffer) = NULL; -#ifdef ZEND_MULTIBYTE - SCNG(script_org) = NULL; - SCNG(script_org_size) = 0; - SCNG(script_filtered) = NULL; - SCNG(script_filtered_size) = 0; - SCNG(input_filter) = NULL; - SCNG(output_filter) = NULL; - SCNG(script_encoding) = NULL; - SCNG(internal_encoding) = NULL; -#endif /* ZEND_MULTIBYTE */ + + SCNG(input_conv) = NULL; + SCNG(output_conv) = NULL; + SCNG(encoding_checked) = 0; + SCNG(rest_str) = NULL; + SCNG(rest_len) = 0; } @@ -155,23 +155,21 @@ void shutdown_scanner(TSRMLS_D) SCNG(yy_start_stack) = NULL; } RESET_DOC_COMMENT(); - -#ifdef ZEND_MULTIBYTE - if (SCNG(script_org)) { - efree(SCNG(script_org)); - SCNG(script_org) = NULL; - } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); - SCNG(script_filtered) = NULL; - } - SCNG(script_org_size) = 0; - SCNG(script_filtered_size) = 0; - SCNG(input_filter) = NULL; - SCNG(output_filter) = NULL; - SCNG(script_encoding) = NULL; - SCNG(internal_encoding) = NULL; -#endif /* ZEND_MULTIBYTE */ + + if (SCNG(input_conv)) { + ucnv_close(SCNG(input_conv)); + SCNG(input_conv) = NULL; + } + if (SCNG(output_conv)) { + ucnv_close(SCNG(output_conv)); + SCNG(output_conv) = NULL; + } + SCNG(encoding_checked) = 0; + if (SCNG(rest_str)) { + efree(SCNG(rest_str)); + SCNG(rest_str) = NULL; + } + SCNG(rest_len) = 0; } END_EXTERN_C() @@ -184,16 +182,16 @@ ZEND_API void zend_save_lexical_state(zend_lex_state *lex_state TSRMLS_DC) lex_state->filename = zend_get_compiled_filename(TSRMLS_C); lex_state->lineno = CG(zend_lineno); -#ifdef ZEND_MULTIBYTE - lex_state->script_org = SCNG(script_org); - lex_state->script_org_size = SCNG(script_org_size); - lex_state->script_filtered = SCNG(script_filtered); - lex_state->script_filtered_size = SCNG(script_filtered_size); - lex_state->input_filter = SCNG(input_filter); - lex_state->output_filter = SCNG(output_filter); - lex_state->script_encoding = SCNG(script_encoding); - lex_state->internal_encoding = SCNG(internal_encoding); -#endif /* ZEND_MULTIBYTE */ + lex_state->input_conv = SCNG(input_conv); + lex_state->output_conv = SCNG(output_conv); + lex_state->encoding_checked = SCNG(encoding_checked); + lex_state->rest_str = SCNG(rest_str); + lex_state->rest_len = SCNG(rest_len); + SCNG(input_conv) = NULL; + SCNG(output_conv) = NULL; + SCNG(encoding_checked) = 0; + SCNG(rest_str) = NULL; + SCNG(rest_len) = 0; } ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state TSRMLS_DC) @@ -212,24 +210,20 @@ ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state TSRMLS_DC) CG(zend_lineno) = lex_state->lineno; zend_restore_compiled_filename(lex_state->filename TSRMLS_CC); -#ifdef ZEND_MULTIBYTE - if (SCNG(script_org)) { - efree(SCNG(script_org)); - SCNG(script_org) = NULL; + if (SCNG(input_conv)) { + ucnv_close(SCNG(input_conv)); } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); - SCNG(script_filtered) = NULL; + SCNG(input_conv) = lex_state->input_conv; + if (SCNG(output_conv)) { + ucnv_close(SCNG(output_conv)); } - SCNG(script_org) = lex_state->script_org; - SCNG(script_org_size) = lex_state->script_org_size; - SCNG(script_filtered) = lex_state->script_filtered; - SCNG(script_filtered_size) = lex_state->script_filtered_size; - SCNG(input_filter) = lex_state->input_filter; - SCNG(output_filter) = lex_state->output_filter; - SCNG(script_encoding) = lex_state->script_encoding; - SCNG(internal_encoding) = lex_state->internal_encoding; -#endif /* ZEND_MULTIBYTE */ + SCNG(output_conv) = lex_state->output_conv; + SCNG(encoding_checked) = lex_state->encoding_checked; + if (SCNG(rest_str)) { + efree(SCNG(rest_str)); + } + SCNG(rest_str) = lex_state->rest_str; + SCNG(rest_len) = lex_state->rest_len; } @@ -288,52 +282,472 @@ ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle TSRMLS_DC) zend_llist_del_element(&CG(open_files), file_handle, (int (*)(void *, void *)) zend_compare_file_handles); } +/* Convert one octal digit to a numeric value 0..7, or -1 on failure */ +static inline int8_t zend_get_octal_digit(UChar c) { + if (c >= 0x0030 && c <= 0x0037) { + return (int8_t)(c - 0x0030); + } + return -1; +} -ZEND_API int open_file_for_scanning(zend_file_handle *file_handle TSRMLS_DC) +/* + * Convert one hex digit to a numeric value 0..F, or -1 on failure. + * Borrowed from ICU. + */ +static inline int8_t zend_get_hex_digit(UChar c) { + if (c >= 0x0030 && c <= 0x0039) { + return (int8_t)(c - 0x0030); + } + if (c >= 0x0041 && c <= 0x0046) { + return (int8_t)(c - (0x0041 - 10)); + } + if (c >= 0x0061 && c <= 0x0066) { + return (int8_t)(c - (0x0061 - 10)); + } + return -1; +} + +static inline zend_bool zend_digits_to_codepoint(char *s, char *end, UChar32 *c, int8_t digits) { - char *file_path=NULL; + int8_t n = 0; + int8_t digit = 0; + UChar32 codepoint = 0; - if (FAILURE == zend_stream_fixup(file_handle TSRMLS_CC)) { - return FAILURE; + while (s < end && n < digits) { + digit = zend_get_hex_digit((UChar)*s); + if (digit < 0) { + break; + } + codepoint = (codepoint << 4) | digit; + ++s; + ++n; } - zend_llist_add_element(&CG(open_files), file_handle); - - /* Reset the scanner for scanning the new file */ - SCNG(yy_in) = file_handle; + if (n < digits) { + return 0; + } + + *c = codepoint; + return 1; +} -#ifdef ZEND_MULTIBYTE - if (file_handle->handle.stream.interactive == 0) { - if (zend_multibyte_read_script(TSRMLS_C) != 0) { +static inline zend_bool zend_udigits_to_codepoint(UChar *s, UChar *end, UChar32 *c, int8_t digits) +{ + int8_t n = 0; + int8_t digit = 0; + UChar32 codepoint = 0; + + while (s < end && n < digits) { + digit = zend_get_hex_digit(*s); + if (digit < 0) { + break; + } + codepoint = (codepoint << 4) | digit; + ++s; + ++n; + } + + if (n < digits) { + return 0; + } + + *c = codepoint; + return 1; +} + +static inline int zend_uchar_from_name(char *name, UChar32 *c) +{ + UChar32 codepoint = 0; + UErrorCode status = U_ZERO_ERROR; + + codepoint = u_charFromName(U_UNICODE_CHAR_NAME, name, &status); + if (U_SUCCESS(status)) { + *c = codepoint; + return 1; + } else { + return 0; + } +} + +static inline int zend_uchar_from_uname(UChar *name, int32_t name_len, UChar32 *c) +{ + UChar32 codepoint = 0; + UErrorCode status = U_ZERO_ERROR; + char buf[128]; + + u_UCharsToChars(name, buf, name_len); + buf[name_len] = 0; + codepoint = u_charFromName(U_UNICODE_CHAR_NAME, buf, &status); + if (U_SUCCESS(status)) { + *c = codepoint; + return 1; + } else { + return 0; + } +} + +static inline int zend_parse_charname_sequence(UChar **s, UChar *end, UChar32 *c) +{ + UChar *start; + + if (**s == '{') { + start = ++(*s); + while ((*s)++ != end) { + if (**s == '}') { + if (zend_uchar_from_uname(start, *s - start, c)) { + return 1; + } else { + /* safe, since *s points to '}' */ + **s = 0; + zend_error(E_COMPILE_WARNING, "Invalid Unicode character name: '%r'", start); + break; + } + } + } + } + + return 0; +} + +static inline int zend_copy_string_value(zval *zendlval, char *str, zend_uint str_len, zend_uchar type TSRMLS_DC) +{ + UErrorCode status = U_ZERO_ERROR; + int32_t consumed = 0; + + if (type == IS_UNICODE) { + consumed = zend_convert_scanner_output(&zendlval->value.ustr.val, &zendlval->value.ustr.len, str, str_len, &status TSRMLS_CC); + + if (U_FAILURE(status)) { + zend_error(E_COMPILE_WARNING,"Illegal or truncated character in input: offset %d, state=%d", consumed, YYSTATE); + efree(zendlval->value.ustr.val); + return 0; + } + zendlval->type = IS_UNICODE; + } else { + zendlval->value.str.val = (char *)estrndup(str, str_len); + zendlval->value.str.len = str_len; + zendlval->type = type; + } + + return 1; +} + +static inline int zend_check_and_normalize_identifier(zval *zendlval) +{ + UChar *norm; + int32_t norm_len; + + if (!zend_is_valid_identifier(Z_USTRVAL_P(zendlval), Z_USTRLEN_P(zendlval))) { + zend_error(E_COMPILE_WARNING, "Invalid identifier syntax: %r", Z_USTRVAL_P(zendlval)); + efree(Z_USTRVAL_P(zendlval)); + return 0; + } + if (!zend_normalize_identifier(&norm, &norm_len, Z_USTRVAL_P(zendlval), Z_USTRLEN_P(zendlval), 0)) { + zend_error(E_COMPILE_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(zendlval)); + efree(Z_USTRVAL_P(zendlval)); + return 0; + } + if (norm != Z_USTRVAL_P(zendlval)) { + efree(Z_USTRVAL_P(zendlval)); + ZVAL_UNICODEL(zendlval, norm, norm_len, 0); + } + return 1; +} + +static void zend_scanner_output_callback( + const void *context, + UConverterToUnicodeArgs *toUArgs, + const char *codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode *err + ) +{ + if (*err == U_TRUNCATED_CHAR_FOUND || + *err == U_ILLEGAL_CHAR_FOUND || + *err == U_INVALID_CHAR_FOUND) { + *(const char **)context = toUArgs->source - length; + } + + return; +} + +static int is_encoding_flex_compatible(const char *enc TSRMLS_DC) +{ + int key_len = strlen(enc)+1; + unsigned char ret; + unsigned char *ret_ptr; + + if (zend_hash_find(&UG(flex_compatible), (char*)enc, key_len, (void**)&ret_ptr) == SUCCESS) { + return *ret_ptr; + } else { + UErrorCode status = U_ZERO_ERROR; + UConverter *conv = ucnv_open(enc, &status); + + if (U_FAILURE(status)) { + return 0; + } + + switch (ucnv_getType(conv)) { + case UCNV_DBCS: + case UCNV_UTF16_BigEndian: + case UCNV_UTF16_LittleEndian: + case UCNV_UTF32_BigEndian: + case UCNV_UTF32_LittleEndian: + case UCNV_EBCDIC_STATEFUL: + case UCNV_ISO_2022: + case UCNV_LMBCS_1: + case UCNV_LMBCS_2: + case UCNV_LMBCS_3: + case UCNV_LMBCS_4: + case UCNV_LMBCS_5: + case UCNV_LMBCS_6: + case UCNV_LMBCS_8: + case UCNV_LMBCS_11: + case UCNV_LMBCS_16: + case UCNV_LMBCS_17: + case UCNV_LMBCS_18: + case UCNV_LMBCS_19: + case UCNV_HZ: + case UCNV_SCSU: + case UCNV_UTF7: + case UCNV_BOCU1: + case UCNV_UTF16: + case UCNV_UTF32: + case UCNV_IMAP_MAILBOX: + ret = 0; + break; + case UCNV_LATIN_1: + case UCNV_UTF8: + case UCNV_ISCII: + case UCNV_US_ASCII: + case UCNV_CESU8: + ret = 1; + break; + default: { + static const UChar ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E + }; + static const char expected[] = + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F" + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F" + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F" + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F" + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F" + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E"; + char output[sizeof(expected)]; + + if (ucnv_fromUChars(conv, + output, sizeof(output), + ascii, sizeof(expected), + &status) != sizeof(expected) || + U_FAILURE(status)) { + ret = 0; + } else { + ret = (memcmp(expected, output, sizeof(expected)) == 0); + } + } + } + ucnv_close(conv); + + zend_hash_add(&UG(flex_compatible), (char*)enc, key_len, (void**)&ret, sizeof(ret), NULL); + + return ret; + } +} + +ZEND_API int zend_prepare_scanner_converters(const char *onetime_encoding, int run_time TSRMLS_DC) +{ + const char *encoding = NULL; + + if (SCNG(input_conv)) { + /* Script is already converted to UTF-8 */ + return zend_set_converter_encoding(&SCNG(output_conv), "UTF-8"); + } else { + encoding = onetime_encoding; + } + + /* We need to convert the input stream only if script_encoding is not ASCII compatible */ + if (!is_encoding_flex_compatible(encoding TSRMLS_CC)) { + if (zend_set_converter_encoding(&SCNG(input_conv), encoding) == FAILURE) { return FAILURE; } + if (run_time) { + /* Convert rest of the buffer to unicode.runtime_encoding. */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + int offset, length, size; + const char *src, *old_src; + char rt_buf[8192]; + char *target = rt_buf; + UErrorCode status = U_ZERO_ERROR; + + old_src = src = yy_c_buf_p; + offset = yy_c_buf_p - b->yy_ch_buf; + length = b->yy_n_chars - offset; + size = b->yy_buf_size - offset; + + ucnv_convertEx(UG(utf8_conv), + SCNG(input_conv), + &target, rt_buf+size-2, + &src, src+length, + NULL, NULL, NULL, NULL, + TRUE, TRUE, + &status); + + if (src - old_src < length) { + /* Cannot fit into buffer. Schedule for next read. */ + SCNG(rest_len) = length - (src - old_src); + SCNG(rest_str) = emalloc(SCNG(rest_len)); + memcpy(SCNG(rest_str), src, SCNG(rest_len)); + } + length = target - rt_buf; + memcpy(yy_c_buf_p, rt_buf, length); + SCNG(yy_n_chars) = b->yy_n_chars = length + offset; + b->yy_ch_buf[b->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[b->yy_n_chars+1] = YY_END_OF_BUFFER_CHAR; + } + encoding = "UTF-8"; + } + return zend_set_converter_encoding(&SCNG(output_conv), encoding); +} - /* force flex to use buffer only */ - SCNG(yy_in) = NULL; - SCNG(init) = 0; - SCNG(start) = 1; +ZEND_API int32_t zend_convert_scanner_output(UChar **target, int32_t *target_len, const char *source, int32_t source_len, UErrorCode *status TSRMLS_DC) +{ + const char *source_consumed = NULL; + + /* set our custom callback with context */ + ucnv_setToUCallBack(SCNG(output_conv), zend_scanner_output_callback, &source_consumed, NULL, NULL, status); - zend_multibyte_set_filter(NULL TSRMLS_CC); + /* reset the error and perform conversion */ + *status = U_ZERO_ERROR; + zend_convert_to_unicode(SCNG(output_conv), target, target_len, source, source_len, status); - if (!SCNG(input_filter)) { - SCNG(script_filtered) = (char*)emalloc(SCNG(script_org_size)+1); - memcpy(SCNG(script_filtered), SCNG(script_org), SCNG(script_org_size)+1); - SCNG(script_filtered_size) = SCNG(script_org_size); + /* figure out how many source bytes were consumed */ + if (U_SUCCESS(*status)) { + return source_len; + } else if (source_consumed) { + return source_consumed - source; + } else { + return 0; + } +} + +int zend_unicode_yyinput(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC) +{ + size_t n; + int c = '*'; + const char *src = buf; + + /* Look of we have rest from previous call */ + if (SCNG(rest_str)) { + if (len >= SCNG(rest_len)) { + memcpy(buf, SCNG(rest_str), SCNG(rest_len)); + efree(SCNG(rest_str)); + SCNG(rest_str) = NULL; + n = SCNG(rest_len); + SCNG(rest_len) = 0; } else { - SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC); + memcpy(buf, SCNG(rest_str), len); + memcpy(SCNG(rest_str), SCNG(rest_str)+len, SCNG(rest_len)-len); + n = len; + SCNG(rest_len) -= len; } - - /* flex requires doubled null */ - SCNG(script_filtered) = (char*)erealloc(SCNG(script_filtered), SCNG(script_filtered_size)+2); - *(SCNG(script_filtered)+SCNG(script_filtered_size)) = (char)NULL; - *(SCNG(script_filtered)+SCNG(script_filtered_size)+1) = (char)NULL; - yy_scan_buffer(SCNG(script_filtered), SCNG(script_filtered_size)+2 TSRMLS_CC); } else { - yy_switch_to_buffer(yy_create_buffer(SCNG(yy_in), YY_BUF_SIZE TSRMLS_CC) TSRMLS_CC); + if (file_handle->handle.stream.interactive) { + for (n = 0; n < sizeof(buf) && (c = zend_stream_getc(yyin TSRMLS_CC)) != EOF && c != '\n'; ++n) { + buf[n] = (char)c; + } + if (c == '\n') { + buf[n++] = (char) c; + } + } else { + n = zend_stream_read(file_handle, buf, len TSRMLS_CC); + } + } + + /* Don't make any conversions if unicode=off */ + if (!UG(unicode)) { + return n; + } + + /* Autodetect encoding */ + if (!SCNG(encoding_checked)) { + int32_t signatureLength; + UErrorCode status = U_ZERO_ERROR; + const char *encoding; + + encoding = ucnv_detectUnicodeSignature(buf, n, &signatureLength, &status); + if (encoding && U_SUCCESS(status)) { + src += signatureLength; + n -= signatureLength; + if (is_encoding_flex_compatible(encoding TSRMLS_CC)) { + if (SCNG(input_conv)) { + ucnv_close(SCNG(input_conv)); + SCNG(input_conv) = NULL; + } + zend_set_converter_encoding(&SCNG(output_conv), encoding); + if (signatureLength > 0) { + memcpy(buf, src, n); + } + } else { + zend_set_converter_encoding(&SCNG(input_conv), encoding); + zend_set_converter_encoding(&SCNG(output_conv), "UTF-8"); + } + } + status = U_ZERO_ERROR; + SCNG(encoding_checked) = 1; + } + + if (SCNG(input_conv) && n >= 0) { + UErrorCode status = U_ZERO_ERROR; + char rt_buf[8192]; + char *target = rt_buf; + const char *old_src = src; + + ucnv_convertEx(UG(utf8_conv), + SCNG(input_conv), + &target, rt_buf+len, + &src, src+n, + NULL, NULL, NULL, NULL, + TRUE, TRUE, + &status); + if (src - old_src < n) { + /* Cannot fit into buffer. Schedule for next read. */ + SCNG(rest_len) = n - (src - old_src); + SCNG(rest_str) = emalloc(SCNG(rest_len)); + memcpy(SCNG(rest_str), src, SCNG(rest_len)); + } + n = target - rt_buf; + memcpy(buf, rt_buf, n); + } + return n; +} + +ZEND_API int open_file_for_scanning(zend_file_handle *file_handle TSRMLS_DC) +{ + char *file_path=NULL; + UErrorCode status = U_ZERO_ERROR; + + if (FAILURE == zend_stream_fixup(file_handle TSRMLS_CC)) { + return FAILURE; } -#else /* !ZEND_MULTIBYTE */ + + zend_llist_add_element(&CG(open_files), file_handle); + + /* Reset the scanner for scanning the new file */ + SCNG(yy_in) = file_handle; + + zend_prepare_scanner_converters(ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status), 0 TSRMLS_CC); yy_switch_to_buffer(yy_create_buffer(SCNG(yy_in), YY_BUF_SIZE TSRMLS_CC) TSRMLS_CC); -#endif /* ZEND_MULTIBYTE */ BEGIN(INITIAL); @@ -460,6 +874,16 @@ zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC) ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_DC) { + const char *encoding; + + if (Z_TYPE_P(str) == IS_UNICODE) { + convert_to_string_with_converter(str, UG(utf8_conv)); + encoding = "UTF-8"; + } else { + UErrorCode status = U_ZERO_ERROR; + encoding = ucnv_getName(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &status); + } + /* enforce two trailing NULLs for flex... */ STR_REALLOC(str->value.str.val, str->value.str.len+2); @@ -467,28 +891,8 @@ ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_D SCNG(yy_in)=NULL; -#ifdef ZEND_MULTIBYTE - SCNG(script_org) = estrdup(str->value.str.val); - SCNG(script_org_size) = str->value.str.len; - - zend_multibyte_set_filter(CG(internal_encoding) TSRMLS_CC); - - if (!SCNG(input_filter)) { - SCNG(script_filtered) = (char*)emalloc(SCNG(script_org_size)+1); - memcpy(SCNG(script_filtered), SCNG(script_org), SCNG(script_org_size)+1); - SCNG(script_filtered_size) = SCNG(script_org_size); - } else { - SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC); - } - - /* flex requires doubled null */ - SCNG(script_filtered) = (char*)erealloc(SCNG(script_filtered), SCNG(script_filtered_size)+2); - *(SCNG(script_filtered)+SCNG(script_filtered_size)) = (char)NULL; - *(SCNG(script_filtered)+SCNG(script_filtered_size)+1) = (char)NULL; - yy_scan_buffer(SCNG(script_filtered), SCNG(script_filtered_size)+2 TSRMLS_CC); -#else /* !ZEND_MULTIBYTE */ + zend_prepare_scanner_converters(encoding, 0 TSRMLS_CC); yy_scan_buffer(str->value.str.val, str->value.str.len+2 TSRMLS_CC); -#endif /* ZEND_MULTIBYTE */ zend_set_compiled_filename(filename TSRMLS_CC); CG(zend_lineno) = 1; @@ -521,18 +925,21 @@ zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC) int compiler_result; zend_bool original_in_compilation = CG(in_compilation); - if (source_string->value.str.len==0) { + tmp = *source_string; + zval_copy_ctor(&tmp); + if (Z_TYPE(tmp) != IS_STRING && Z_TYPE(tmp) != IS_UNICODE) { + convert_to_text(&tmp); + } + source_string = &tmp; + + if (Z_USTRLEN_P(source_string)==0) { efree(op_array); + zval_dtor(&tmp); return NULL; } CG(in_compilation) = 1; - tmp = *source_string; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - source_string = &tmp; - zend_save_lexical_state(&original_lex_state TSRMLS_CC); if (zend_prepare_string_for_scanning(source_string, filename TSRMLS_CC)==FAILURE) { efree(op_array); @@ -543,17 +950,6 @@ zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC) BEGIN(ST_IN_SCRIPTING); compiler_result = zendparse(TSRMLS_C); -#ifdef ZEND_MULTIBYTE - if (SCNG(script_org)) { - efree(SCNG(script_org)); - SCNG(script_org) = NULL; - } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); - SCNG(script_filtered) = NULL; - } -#endif /* ZEND_MULTIBYTE */ - if (compiler_result==1) { CG(active_op_array) = original_active_op_array; CG(unclean_shutdown)=1; @@ -589,16 +985,6 @@ int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlight return FAILURE; } zend_highlight(syntax_highlighter_ini TSRMLS_CC); -#ifdef ZEND_MULTIBYTE - if (SCNG(script_org)) { - efree(SCNG(script_org)); - SCNG(script_org) = NULL; - } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); - SCNG(script_filtered) = NULL; - } -#endif /* ZEND_MULTIBYTE */ zend_destroy_file_handle(&file_handle TSRMLS_CC); zend_restore_lexical_state(&original_lex_state TSRMLS_CC); return SUCCESS; @@ -616,166 +1002,384 @@ int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ return FAILURE; } zend_highlight(syntax_highlighter_ini TSRMLS_CC); -#ifdef ZEND_MULTIBYTE - if (SCNG(script_org)) { - efree(SCNG(script_org)); - SCNG(script_org) = NULL; - } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); - SCNG(script_filtered) = NULL; - } -#endif /* ZEND_MULTIBYTE */ zend_restore_lexical_state(&original_lex_state TSRMLS_CC); zval_dtor(str); return SUCCESS; } END_EXTERN_C() -#ifdef ZEND_MULTIBYTE -BEGIN_EXTERN_C() -ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, zend_encoding *old_encoding TSRMLS_DC) +#define zend_copy_value(zendlval, yytext, yyleng) \ + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); \ + zendlval->value.str.len = yyleng; + +int zend_scan_unicode_double_string(zval *zendlval TSRMLS_DC) { - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - int offset, original_offset, length, free_flag; - char *p; - zend_encoding *new_encoding; - - /* calculate current position */ - offset = original_offset = yy_c_buf_p - b->yy_ch_buf; - if (old_input_filter && original_offset > 0) { - new_encoding = SCNG(script_encoding); - SCNG(script_encoding) = old_encoding; - do { - (old_input_filter)(&p, &length, SCNG(script_org), offset TSRMLS_CC); - if (!p) { - SCNG(script_encoding) = new_encoding; - return; + register UChar *s, *t, c; + UChar *end; + UChar32 codepoint = 0; + int8_t digit; + int8_t min_digits = 0, max_digits = 0; + int8_t bits; + int8_t n; + + HANDLE_NEWLINES(yytext, yyleng); + + if (!zend_copy_string_value(zendlval, yytext+1, yyleng-2, IS_UNICODE TSRMLS_CC)) { + return 0; + } + + /* convert escape sequences */ + s = t = zendlval->value.ustr.val; + end = s+zendlval->value.ustr.len; + while (s=end) { + continue; } - efree(p); - if (length > original_offset) { - offset--; - } else if (length < original_offset) { - offset++; + + min_digits = 0; + codepoint = 0; + bits = 4; + n = 0; + + switch(c) { + case 0x6E: /*'n'*/ + *t++ = (UChar) 0x0A; /*'\n'*/ + zendlval->value.ustr.len--; + break; + case 0x72: /*'r'*/ + *t++ = (UChar) 0x0D; /*'\r'*/ + zendlval->value.ustr.len--; + break; + case 0x74: /*'t'*/ + *t++ = (UChar) 0x09; /*'\t'*/ + zendlval->value.ustr.len--; + break; + case 0x5C: /*'\\'*/ + case 0x24: /*'$'*/ + case 0x22: /*'"'*/ + *t++ = *s; + zendlval->value.ustr.len--; + break; + case 0x43: /*'C'*/ + { + UChar *p = s+1; + if (p < end && zend_parse_charname_sequence(&p, end, &codepoint)) { + zendlval->value.ustr.len -= p - s + 1; + s = p; + if (U_IS_BMP(codepoint)) { + *t++ = (UChar) codepoint; + } else { + *t++ = (UChar) U16_LEAD(codepoint); + *t++ = (UChar) U16_TRAIL(codepoint); + zendlval->value.ustr.len++; + } + } else { + zend_error(E_COMPILE_WARNING, "Invalid \\C{..} sequence"); + efree(zendlval->value.ustr.val); + return 0; + } + break; + } + case 0x75: /*'u'*/ + min_digits = 4; + max_digits = 4; + zendlval->value.ustr.len--; + break; + case 0x55: /*'U'*/ + min_digits = 6; + max_digits = 6; + zendlval->value.ustr.len--; + break; + default: + digit = zend_get_octal_digit(*s); + if (digit >= 0) { + min_digits = 1; + max_digits = 3; + bits = 3; + n = 1; /* already have one digit */ + codepoint = digit; + } else if (c == 0x78 /*'x'*/ + && (s+1) < end && (digit = zend_get_hex_digit(*(s+1))) >= 0) { + min_digits = 1; + max_digits = 2; + zendlval->value.ustr.len--; + s++; + n = 1; /* already have one digit */ + codepoint = digit; + } else { + *t++ = 0x5C; /*'\\'*/ + *t++ = *s; + } + break; } - } while (original_offset != length); - SCNG(script_encoding) = new_encoding; - } - /* convert and set */ - if (!SCNG(input_filter)) { - length = SCNG(script_org_size)-offset-1; - p = SCNG(script_org)+offset+1; - free_flag = 0; - } else { - SCNG(input_filter)(&p, &length, SCNG(script_org)+offset+1, SCNG(script_org_size)-offset-1 TSRMLS_CC); - free_flag = 1; - } - if (original_offset+length+1 > (int)b->yy_buf_size) { - b->yy_buf_size = original_offset+length+1; - b->yy_ch_buf = (char*)erealloc(b->yy_ch_buf, b->yy_buf_size+2); - SCNG(script_filtered) = b->yy_ch_buf; - SCNG(script_filtered_size) = b->yy_buf_size; + /* need to parse a number for one of the escape sequences */ + if (min_digits != 0) { + while (s++ < end && n < max_digits) { + digit = (bits == 4) ? zend_get_hex_digit(*s) : zend_get_octal_digit(*s); + if (digit < 0) { + break; + } + codepoint = (codepoint << bits) | digit; + n++; + } + + if (n < min_digits) { + /* can only happen for \u and \U sequences */ + zend_error(E_COMPILE_WARNING,"\\%c escape sequence requires exactly %d hexadecimal digits", (char) c, min_digits); + efree(zendlval->value.ustr.val); + return 0; + } + + if (U_IS_BMP(codepoint)) { + *t++ = (UChar) codepoint; + zendlval->value.ustr.len -= n; + } else if (codepoint <= 0x10FFFF) { + *t++ = (UChar) U16_LEAD(codepoint); + *t++ = (UChar) U16_TRAIL(codepoint); + zendlval->value.ustr.len -= n-1; + } else { + zend_error(E_COMPILE_WARNING,"\\U%06x is above the highest valid codepoint 0x10FFFF", codepoint); + efree(zendlval->value.ustr.val); + return 0; + } + } else { + s++; + } + } else { + *t++ = *s++; + } } - yy_c_buf_p = b->yy_ch_buf + original_offset; - strncpy(yy_c_buf_p+1, p, length); - b->yy_n_chars = original_offset + length + 1; - SCNG(yy_n_chars) = b->yy_n_chars; - b->yy_ch_buf[SCNG(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[SCNG(yy_n_chars)+1] = YY_END_OF_BUFFER_CHAR; + *t = 0; - if (free_flag) { - efree(p); - } + return T_CONSTANT_ENCAPSED_STRING; } - -ZEND_API int zend_multibyte_yyinput(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC) +int zend_scan_unicode_single_string(zval *zendlval TSRMLS_DC) { - int c = '*', n; + register UChar *s, *t; + UChar *end; + UChar32 codepoint = 0; - if (file_handle->handle.stream.interactive == 0) { - return zend_stream_read(file_handle, buf, len TSRMLS_CC); - } + HANDLE_NEWLINES(yytext, yyleng); - /* interactive */ - if (SCNG(script_org)) { - efree(SCNG(script_org)); - } - if (SCNG(script_filtered)) { - efree(SCNG(script_filtered)); + if (!zend_copy_string_value(zendlval, yytext+1, yyleng-2, IS_UNICODE TSRMLS_CC)) { + return 0; } - SCNG(script_org) = NULL; - SCNG(script_org_size) = 0; - /* TODO: support widechars */ - - for (n = 0; n < sizeof(buf) && (c = zend_stream_getc(yyin TSRMLS_CC)) != EOF && c != '\n'; ++n) { - buf[n] = (char)c; - } - if (c == '\n') { - buf[n++] = (char) c; + /* convert escape sequences */ + s = t = zendlval->value.ustr.val; + end = s+zendlval->value.ustr.len; + while (s=end) { + continue; + } + switch(*s) { + case 0x5C: /*'\\'*/ + case 0x27: /*'\''*/ + *t++ = *s; + zendlval->value.ustr.len--; + break; + case 0x43: /*'C'*/ + { + UChar *p = s+1; + if (p < end && zend_parse_charname_sequence(&p, end, &codepoint)) { + zendlval->value.ustr.len -= p - s + 1; + s = p; + if (U_IS_BMP(codepoint)) { + *t++ = (UChar) codepoint; + } else { + *t++ = (UChar) U16_LEAD(codepoint); + *t++ = (UChar) U16_TRAIL(codepoint); + zendlval->value.ustr.len++; + } + } else { + zend_error(E_COMPILE_WARNING, "Invalid \\C{..} sequence"); + efree(zendlval->value.ustr.val); + return 0; + } + break; + } + case 0x75 /*'u'*/: + { + codepoint = 0; + if (zend_udigits_to_codepoint(s+1, end, &codepoint, 4)) { + *t++ = (UChar) codepoint; + s += 4; + zendlval->value.ustr.len -= 5; + } else { + zend_error(E_COMPILE_WARNING,"\\u escape sequence requires exactly 4 hexadecimal digits"); + efree(zendlval->value.ustr.val); + return 0; + } + break; + } + case 0x55 /*'U'*/: + { + codepoint = 0; + if (zend_udigits_to_codepoint(s+1, end, &codepoint, 6)) { + if (U_IS_BMP(codepoint)) { + *t++ = (UChar) codepoint; + zendlval->value.ustr.len -= 7; + } else if (codepoint <= 0x10FFFF) { + *t++ = (UChar) U16_LEAD(codepoint); + *t++ = (UChar) U16_TRAIL(codepoint); + zendlval->value.ustr.len -= 6; + } else { + zend_error(E_COMPILE_WARNING,"\\U%06x is above the highest valid codepoint 0x10FFFF", codepoint); + efree(zendlval->value.ustr.val); + return 0; + } + s += 6; + } else { + zend_error(E_COMPILE_WARNING,"\\U escape sequence requires exactly 6 hexadecimal digits"); + efree(zendlval->value.ustr.val); + return 0; + } + break; + } + default: + *t++ = 0x5C; /*'\\'*/ + *t++ = *s; + break; + } + s++; + } else { + *t++ = *s++; + } } + *t = 0; - SCNG(script_org_size) = n; - SCNG(script_org) = (char*)emalloc(SCNG(script_org_size)+1); - memcpy(SCNG(script_org)+SCNG(script_org_size)-n, buf, n); - - return n; + return T_CONSTANT_ENCAPSED_STRING; } - -ZEND_API int zend_multibyte_read_script(TSRMLS_D) +int zend_scan_binary_double_string(zval *zendlval TSRMLS_DC) { - char buf[8192]; - int n; + register char *s, *t; + char *end; - if (SCNG(script_org)) { - efree(SCNG(script_org)); - } - SCNG(script_org) = NULL; - SCNG(script_org_size) = 0; + zendlval->value.str.val = estrndup(yytext+1, yyleng-2); + zendlval->value.str.len = yyleng-2; + zendlval->type = UG(unicode) ? IS_BINARY : IS_STRING; + HANDLE_NEWLINES(yytext, yyleng); - for (;;) { - n = zend_stream_read(yyin, buf, sizeof(buf) TSRMLS_CC); - if (n <= 0) { - break; - } + /* convert escape sequences */ + s = t = zendlval->value.str.val; + end = s+zendlval->value.str.len; + while (s=end) { + continue; + } + switch(*s) { + case 'n': + *t++ = '\n'; + zendlval->value.str.len--; + break; + case 'r': + *t++ = '\r'; + zendlval->value.str.len--; + break; + case 't': + *t++ = '\t'; + zendlval->value.str.len--; + break; + case '\\': + case '$': + case '"': + *t++ = *s; + zendlval->value.str.len--; + break; + default: + /* check for an octal */ + if (ZEND_IS_OCT(*s)) { + char octal_buf[4] = { 0, 0, 0, 0 }; + + octal_buf[0] = *s; + zendlval->value.str.len--; + if ((s+1)value.str.len--; + if ((s+1)value.str.len--; + } + } + *t++ = (char) strtol(octal_buf, NULL, 8); + } else if (*s=='x' && (s+1)value.str.len--; /* for the 'x' */ - SCNG(script_org_size) += n; - if (SCNG(script_org)) { - SCNG(script_org) = (char*)erealloc(SCNG(script_org), SCNG(script_org_size)+1); + hex_buf[0] = *(++s); + zendlval->value.str.len--; + if ((s+1)value.str.len--; + } + *t++ = (char) strtol(hex_buf, NULL, 16); + } else { + *t++ = '\\'; + *t++ = *s; + } + break; + } + s++; } else { - SCNG(script_org) = (char*)emalloc(SCNG(script_org_size)+1); + *t++ = *s++; } - memcpy(SCNG(script_org)+SCNG(script_org_size)-n, buf, n); } + *t = 0; - if (n < 0) { - return -1; - } + return T_CONSTANT_ENCAPSED_STRING; +} + +int zend_scan_binary_single_string(zval *zendlval TSRMLS_DC) +{ + register char *s, *t; + char *end; + + zendlval->value.str.val = estrndup(yytext+1, yyleng-2); + zendlval->value.str.len = yyleng-2; + zendlval->type = UG(unicode) ? IS_BINARY : IS_STRING; + HANDLE_NEWLINES(yytext, yyleng); - if (!SCNG(script_org)) { - SCNG(script_org) = emalloc(SCNG(script_org_size)+1); + /* convert escape sequences */ + s = t = zendlval->value.str.val; + end = s+zendlval->value.str.len; + while (s=end) { + continue; + } + switch(*s) { + case '\\': + case '\'': + *t++ = *s; + zendlval->value.str.len--; + break; + default: + *t++ = '\\'; + *t++ = *s; + break; + } + s++; + } else { + *t++ = *s++; + } } - *(SCNG(script_org)+SCNG(script_org_size)) = (char)NULL; + *t = 0; - return 0; + return T_CONSTANT_ENCAPSED_STRING; } - -# define zend_copy_value(zendlval, yytext, yyleng) \ - if (SCNG(output_filter)) { \ - SCNG(output_filter)(&(zendlval->value.str.val), &(zendlval->value.str.len), yytext, yyleng TSRMLS_CC); \ - } else { \ - zendlval->value.str.val = (char *) estrndup(yytext, yyleng); \ - zendlval->value.str.len = yyleng; \ - } -#else /* ZEND_MULTIBYTE */ -# define zend_copy_value(zendlval, yytext, yyleng) \ - zendlval->value.str.val = (char *)estrndup(yytext, yyleng); \ - zendlval->value.str.len = yyleng; -#endif /* ZEND_MULTIBYTE */ %} LNUM [0-9]+ @@ -942,8 +1546,12 @@ NEWLINE ("\r"|"\n"|"\r\n") {LABEL} { yy_pop_state(TSRMLS_C); - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, UG(unicode)?IS_UNICODE:IS_STRING TSRMLS_CC)) { + return 0; + } + if (UG(unicode) && !zend_check_and_normalize_identifier(zendlval)) { + return 0; + } return T_STRING; } @@ -980,6 +1588,14 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_STRING_CAST; } +"("{TABS_AND_SPACES}"unicode"{TABS_AND_SPACES}")" { + return T_UNICODE_CAST; +} + +"("{TABS_AND_SPACES}"binary"{TABS_AND_SPACES}")" { + return T_BINARY_CAST; +} + "("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" { return T_ARRAY_CAST; } @@ -1208,8 +1824,12 @@ NEWLINE ("\r"|"\n"|"\r\n") {LABEL} { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, UG(unicode)?IS_UNICODE:IS_STRING TSRMLS_CC)) { + return 0; + } + if (UG(unicode) && !zend_check_and_normalize_identifier(zendlval)) { + return 0; + } yy_pop_state(TSRMLS_C); yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return T_STRING_VARNAME; @@ -1257,9 +1877,9 @@ NEWLINE ("\r"|"\n"|"\r\n") } {LNUM}|{HNUM} { /* treat numbers (almost) as strings inside encapsulated strings */ - zendlval->value.str.val = (char *)estrndup(yytext, yyleng); - zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_NUM_STRING; } @@ -1276,12 +1896,25 @@ NEWLINE ("\r"|"\n"|"\r\n") class_name = CG(active_class_entry)->name; } - if (!class_name) { - class_name = ""; + if (UG(unicode)) { + if (!class_name) { + zendlval->value.ustr.len = 0; + zendlval->value.ustr.val = USTR_MAKE(""); + } else { + zendlval->value.ustr.len = u_strlen((UChar*)class_name); + zendlval->value.ustr.val = eustrndup((UChar*)class_name, zendlval->value.ustr.len); + } + zendlval->type = IS_UNICODE; + } else { + if (!class_name) { + zendlval->value.str.len = 0; + zendlval->value.str.val = estrndup("", 0); + } else { + zendlval->value.str.len = strlen(class_name); + zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); + } + zendlval->type = IS_STRING; } - zendlval->value.str.len = strlen(class_name); - zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); - zendlval->type = IS_STRING; return T_CLASS_C; } @@ -1295,9 +1928,25 @@ NEWLINE ("\r"|"\n"|"\r\n") if (!func_name) { func_name = ""; } - zendlval->value.str.len = strlen(func_name); - zendlval->value.str.val = estrndup(func_name, zendlval->value.str.len); - zendlval->type = IS_STRING; + if (UG(unicode)) { + if (!func_name) { + zendlval->value.ustr.len = 0; + zendlval->value.ustr.val = USTR_MAKE(""); + } else { + zendlval->value.ustr.len = u_strlen((UChar*)func_name); + zendlval->value.ustr.val = eustrndup((UChar*)func_name, zendlval->value.ustr.len); + } + zendlval->type = IS_UNICODE; + } else { + if (!func_name) { + zendlval->value.str.len = 0; + zendlval->value.str.val = estrndup("", 0); + } else { + zendlval->value.str.len = strlen(func_name); + zendlval->value.str.val = estrndup(func_name, zendlval->value.str.len); + } + zendlval->type = IS_STRING; + } return T_FUNC_C; } @@ -1306,21 +1955,47 @@ NEWLINE ("\r"|"\n"|"\r\n") char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL; size_t len = 0; - if (class_name) { - len += strlen(class_name) + 2; - } - if (func_name) { - len += strlen(func_name); - } + if (UG(unicode)) { + size_t len1; - zendlval->value.str.val = emalloc(len+1); - zendlval->value.str.len = sprintf(zendlval->value.str.val, "%s%s%s", - class_name ? class_name : "", - class_name && func_name ? "::" : "", - func_name ? func_name : "" - ); - zendlval->value.str.len = strlen(zendlval->value.str.val); - zendlval->type = IS_STRING; + if (class_name) { + len += len1 = u_strlen((UChar*)class_name); + len += 2; + } + if (func_name) { + len += u_strlen((UChar*)func_name); + } else { + func_name = EMPTY_STR; + } + zendlval->value.str.len = len; + Z_USTRVAL_P(zendlval) = eumalloc(len+1); + if (class_name) { + u_strcpy(Z_USTRVAL_P(zendlval), (UChar*)class_name); + Z_USTRVAL_P(zendlval)[len1] = 0x3a; /* ':' */ + Z_USTRVAL_P(zendlval)[len1+1] = 0x3a; /* ':' */ + Z_USTRVAL_P(zendlval)[len1+2] = 0; + } else { + Z_USTRVAL_P(zendlval)[0] = 0; + } + u_strcat(Z_USTRVAL_P(zendlval), (UChar*)func_name); + zendlval->type = IS_UNICODE; + } else { + if (class_name) { + len += strlen(class_name) + 2; + } + if (func_name) { + len += strlen(func_name); + } + + zendlval->value.str.val = emalloc(len+1); + zendlval->value.str.len = sprintf(zendlval->value.str.val, "%s%s%s", + class_name ? class_name : "", + class_name && func_name ? "::" : "", + func_name ? func_name : "" + ); + zendlval->value.str.len = strlen(zendlval->value.str.val); + zendlval->type = IS_STRING; + } return T_METHOD_C; } @@ -1343,22 +2018,9 @@ NEWLINE ("\r"|"\n"|"\r\n") } (([^<]|"<"[^?%s<]){1,400})|"value.str.val), &(zendlval->value.str.len), yytext, yyleng TSRMLS_CC); - if (readsize < yyleng) { - yyless(readsize); - } - } else { - zendlval->value.str.val = (char *) estrndup(yytext, yyleng); - zendlval->value.str.len = yyleng; - } -#else /* !ZEND_MULTIBYTE */ zendlval->value.str.val = (char *) estrndup(yytext, yyleng); zendlval->value.str.len = yyleng; -#endif /* ZEND_MULTIBYTE */ - zendlval->type = IS_STRING; + zendlval->type = IS_BINARY; HANDLE_NEWLINES(yytext, yyleng); return T_INLINE_HTML; } @@ -1374,7 +2036,7 @@ NEWLINE ("\r"|"\n"|"\r\n") } else { zendlval->value.str.val = (char *) estrndup(yytext, yyleng); zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + zendlval->type = IS_BINARY; return T_INLINE_HTML; } } @@ -1390,7 +2052,7 @@ NEWLINE ("\r"|"\n"|"\r\n") } else { zendlval->value.str.val = (char *) estrndup(yytext, yyleng); zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + zendlval->type = IS_BINARY; return T_INLINE_HTML; } } @@ -1406,7 +2068,7 @@ NEWLINE ("\r"|"\n"|"\r\n") } else { zendlval->value.str.val = (char *) estrndup(yytext, yyleng); zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + zendlval->type = IS_BINARY; return T_INLINE_HTML; } } @@ -1422,20 +2084,29 @@ NEWLINE ("\r"|"\n"|"\r\n") } "$"{LABEL} { - zend_copy_value(zendlval, (yytext+1), (yyleng-1)); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, (yytext+1), (yyleng-1), UG(unicode)?IS_UNICODE:IS_STRING TSRMLS_CC)) { + return 0; + } + if (UG(unicode) && !zend_check_and_normalize_identifier(zendlval)) { + return 0; + } return T_VARIABLE; } {LABEL} { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, UG(unicode)?IS_UNICODE:IS_STRING TSRMLS_CC)) { + return 0; + } + if (UG(unicode) && !zend_check_and_normalize_identifier(zendlval)) { + return 0; + } return T_STRING; } {LABEL} { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_STRING; } @@ -1544,140 +2215,34 @@ NEWLINE ("\r"|"\n"|"\r\n") (["]([^$"\\]|("\\".))*["]) { - register char *s, *t; - char *end; - - zendlval->value.str.val = estrndup(yytext+1, yyleng-2); - zendlval->value.str.len = yyleng-2; - zendlval->type = IS_STRING; - HANDLE_NEWLINES(yytext, yyleng); - - /* convert escape sequences */ - s = t = zendlval->value.str.val; - end = s+zendlval->value.str.len; - while (s=end) { - continue; - } - switch(*s) { - case 'n': - *t++ = '\n'; - zendlval->value.str.len--; - break; - case 'r': - *t++ = '\r'; - zendlval->value.str.len--; - break; - case 't': - *t++ = '\t'; - zendlval->value.str.len--; - break; - case '\\': - case '$': - case '"': - *t++ = *s; - zendlval->value.str.len--; - break; - default: - /* check for an octal */ - if (ZEND_IS_OCT(*s)) { - char octal_buf[4] = { 0, 0, 0, 0 }; - - octal_buf[0] = *s; - zendlval->value.str.len--; - if ((s+1)value.str.len--; - if ((s+1)value.str.len--; - } - } - *t++ = (char) strtol(octal_buf, NULL, 8); - } else if (*s=='x' && (s+1)value.str.len--; /* for the 'x' */ - - hex_buf[0] = *(++s); - zendlval->value.str.len--; - if ((s+1)value.str.len--; - } - *t++ = (char) strtol(hex_buf, NULL, 16); - } else { - *t++ = '\\'; - *t++ = *s; - } - break; - } - s++; - } else { - *t++ = *s++; - } + if (UG(unicode)) { + return zend_scan_unicode_double_string(zendlval TSRMLS_CC); + } else { + return zend_scan_binary_double_string(zendlval TSRMLS_CC); } - *t = 0; +} -#ifdef ZEND_MULTIBYTE - if (SCNG(output_filter)) { - s = zendlval->value.str.val; - SCNG(output_filter)(&(zendlval->value.str.val), &(zendlval->value.str.len), s, zendlval->value.str.len TSRMLS_CC); - efree(s); - } -#endif /* ZEND_MULTIBYTE */ - return T_CONSTANT_ENCAPSED_STRING; +(b["]([^$"\\]|("\\".))*["]) { + yytext++; /* adjust for 'b' */ + yyleng--; + return zend_scan_binary_double_string(zendlval TSRMLS_CC); } ([']([^'\\]|("\\".))*[']) { - register char *s, *t; - char *end; - - zendlval->value.str.val = estrndup(yytext+1, yyleng-2); - zendlval->value.str.len = yyleng-2; - zendlval->type = IS_STRING; - HANDLE_NEWLINES(yytext, yyleng); - - /* convert escape sequences */ - s = t = zendlval->value.str.val; - end = s+zendlval->value.str.len; - while (s=end) { - continue; - } - switch(*s) { - case '\\': - case '\'': - *t++ = *s; - zendlval->value.str.len--; - break; - default: - *t++ = '\\'; - *t++ = *s; - break; - } - s++; - } else { - *t++ = *s++; - } + if (UG(unicode)) { + return zend_scan_unicode_single_string(zendlval TSRMLS_CC); + } else { + return zend_scan_binary_single_string(zendlval TSRMLS_CC); } - *t = 0; +} -#ifdef ZEND_MULTIBYTE - if (SCNG(output_filter)) { - s = zendlval->value.str.val; - SCNG(output_filter)(&(zendlval->value.str.val), &(zendlval->value.str.len), s, zendlval->value.str.len TSRMLS_CC); - efree(s); - } -#endif /* ZEND_MULTIBYTE */ - return T_CONSTANT_ENCAPSED_STRING; +("b'"([^'\\]|("\\".))*[']) { + yytext++; /* adjust for 'b' */ + yyleng--; + return zend_scan_binary_single_string(zendlval TSRMLS_CC); } @@ -1686,6 +2251,25 @@ NEWLINE ("\r"|"\n"|"\r\n") return '\"'; } +b["] { + BEGIN(ST_DOUBLE_QUOTES); + return T_BINARY_DOUBLE; +} + +b"<<<"{TABS_AND_SPACES}{LABEL}{NEWLINE} { + char *s; + CG(zend_lineno)++; + CG(heredoc_len) = yyleng-4-1-(yytext[yyleng-2]=='\r'?1:0); + s = yytext+4; + while ((*s == ' ') || (*s == '\t')) { + s++; + CG(heredoc_len)--; + } + CG(heredoc) = estrndup(s, CG(heredoc_len)); + BEGIN(ST_HEREDOC); + return T_BINARY_HEREDOC; +} + "<<<"{TABS_AND_SPACES}{LABEL}{NEWLINE} { char *s; @@ -1708,12 +2292,6 @@ NEWLINE ("\r"|"\n"|"\r\n") } -['] { - BEGIN(ST_SINGLE_QUOTE); - return '\''; -} - - ^{LABEL}(";")?{NEWLINE} { int label_len; unsigned char unput_semicolon; @@ -1744,8 +2322,9 @@ NEWLINE ("\r"|"\n"|"\r\n") BEGIN(ST_IN_SCRIPTING); return T_END_HEREDOC; } else { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_STRING; } } @@ -1753,30 +2332,24 @@ NEWLINE ("\r"|"\n"|"\r\n") {ESCAPED_AND_WHITESPACE} { HANDLE_NEWLINES(yytext, yyleng); - zendlval->value.str.val = (char *) estrndup(yytext, yyleng); - zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; - return T_ENCAPSED_AND_WHITESPACE; -} - -([^'\\]|\\[^'\\])+ { - HANDLE_NEWLINES(yytext, yyleng); - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_ENCAPSED_AND_WHITESPACE; } - [`]+ { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_ENCAPSED_AND_WHITESPACE; } ["]+ { - zend_copy_value(zendlval, yytext, yyleng); - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_ENCAPSED_AND_WHITESPACE; } @@ -1803,16 +2376,6 @@ NEWLINE ("\r"|"\n"|"\r\n") } -"\\'" { - zendlval->value.lval = (long) '\''; - return T_CHARACTER; -} - -"\\\\" { - zendlval->value.lval = (long)'\\'; - return T_CHARACTER; -} - "\\\"" { zendlval->value.lval = (long) '"'; return T_CHARACTER; @@ -1833,6 +2396,61 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_CHARACTER; } + +"\\u"[0-9A-Fa-f]{0,6} { + UChar32 codepoint; + int req_digits = (yytext[1] == 'U') ? 6 : 4; + + if (CG(literal_type) == IS_UNICODE) { + if (zend_digits_to_codepoint(yytext+2, yytext+yyleng, &codepoint, req_digits)) { + if (codepoint <= 0x10FFFF) { + zendlval->value.lval = (long) codepoint; + /* give back if we grabbed more than needed for \u case */ + if (yyleng > req_digits + 2) { + yyless(req_digits + 2); + } + return T_CHARACTER; + } else { + zend_error(E_COMPILE_WARNING,"\\U%06x is above the highest valid codepoint 0x10FFFF", codepoint); + return 0; + } + } else { + zend_error(E_COMPILE_WARNING,"\\%c escape sequence requires exactly %d hexadecimal digits", yytext[1], req_digits); + return 0; + } + } else { + zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC); + return T_STRING; + } +} + + +"\\C"("{"[A-Z0-9 -]+"}")? { + UChar32 codepoint; + + if (CG(literal_type) == IS_UNICODE && (yytext[1] == 'C')) { + /* minimum valid string is \C{.} */ + if (yyleng >= 5) { + /* safe, since we have } at the end */ + yytext[yyleng-1] = 0; + if (zend_uchar_from_name(yytext+3, &codepoint)) { + zendlval->value.lval = (long) codepoint; + return T_CHARACTER; + } else { + zend_error(E_COMPILE_WARNING, "Invalid Unicode character name: '%s'", yytext+3); + return 0; + } + } else { + zend_error(E_COMPILE_WARNING, "Invalid \\C{..} sequence"); + return 0; + } + } else { + zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC); + return T_STRING; + } +} + + "\\"{ANY_CHAR} { switch (yytext[1]) { case 'n': @@ -1854,9 +2472,9 @@ NEWLINE ("\r"|"\n"|"\r\n") zendlval->value.lval = (long) yytext[1]; break; default: - zendlval->value.str.val = estrndup(yytext, yyleng); - zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_BAD_CHARACTER; break; } @@ -1865,9 +2483,9 @@ NEWLINE ("\r"|"\n"|"\r\n") ["'`]+ { - zendlval->value.str.val = (char *) estrndup(yytext, yyleng); - zendlval->value.str.len = yyleng; - zendlval->type = IS_STRING; + if (!zend_copy_string_value(zendlval, yytext, yyleng, CG(literal_type) TSRMLS_CC)) { + return 0; + } return T_ENCAPSED_AND_WHITESPACE; } @@ -1884,12 +2502,6 @@ NEWLINE ("\r"|"\n"|"\r\n") } -['] { - BEGIN(ST_IN_SCRIPTING); - return '\''; -} - - <> { return 0; } @@ -1901,6 +2513,6 @@ NEWLINE ("\r"|"\n"|"\r\n") -{ANY_CHAR} { +{ANY_CHAR} { zend_error(E_COMPILE_WARNING,"Unexpected character in input: '%c' (ASCII=%d) state=%d", yytext[0], yytext[0], YYSTATE); } diff --git a/Zend/zend_multibyte.c b/Zend/zend_multibyte.c index d7a444b32e..6dde60ad95 100644 --- a/Zend/zend_multibyte.c +++ b/Zend/zend_multibyte.c @@ -474,7 +474,7 @@ zend_encoding *zend_encoding_table[] = { }; - +#if 0 ZEND_API int zend_multibyte_set_script_encoding(char *encoding_list, int encoding_list_size TSRMLS_DC) { if (CG(script_encoding_list)) { @@ -491,11 +491,14 @@ ZEND_API int zend_multibyte_set_script_encoding(char *encoding_list, int encodin return 0; } - +#endif ZEND_API int zend_multibyte_set_internal_encoding(char *encoding_name, int encoding_name_size TSRMLS_DC) { - CG(internal_encoding) = zend_multibyte_fetch_encoding(encoding_name); + //CG(internal_encoding) = zend_multibyte_fetch_encoding(encoding_name); + //CG(internal_encoding) = zend_multibyte_fetch_encoding(ZEND_INTERNAL_ENCODING); + /* set this to NULL so that input filtering is done only when really necessary */ + CG(internal_encoding) = NULL; return 0; } @@ -523,17 +526,19 @@ ZEND_API int zend_multibyte_set_filter(zend_encoding *onetime_encoding TSRMLS_DC if (!LANG_SCNG(internal_encoding) || LANG_SCNG(script_encoding) == LANG_SCNG(internal_encoding)) { /* if encoding specfic filters exist, use them */ + /* if (LANG_SCNG(script_encoding)->input_filter && LANG_SCNG(script_encoding)->output_filter) { LANG_SCNG(input_filter) = LANG_SCNG(script_encoding)->input_filter; LANG_SCNG(output_filter) = LANG_SCNG(script_encoding)->output_filter; return 0; } + */ if (!LANG_SCNG(script_encoding)->compatible) { /* and if not, work around w/ script_encoding -> utf-8 -> script_encoding conversion */ - LANG_SCNG(internal_encoding) = LANG_SCNG(script_encoding); + //LANG_SCNG(internal_encoding) = LANG_SCNG(script_encoding); LANG_SCNG(input_filter) = zend_multibyte_script_encoding_filter; - LANG_SCNG(output_filter) = zend_multibyte_internal_encoding_filter; + //LANG_SCNG(output_filter) = zend_multibyte_internal_encoding_filter; return 0; } else { /* nothing to do in this case */ @@ -916,6 +921,7 @@ static char* zend_multibyte_assemble_encoding_list(zend_encoding **encoding_list } +#if 0 static int zend_multibyte_parse_encoding_list(const char *encoding_list, int encoding_list_size, zend_encoding ***result, int *result_size) { int n, size; @@ -982,7 +988,7 @@ static int zend_multibyte_parse_encoding_list(const char *encoding_list, int enc return 0; } - +#endif static zend_encoding* zend_multibyte_find_script_encoding(zend_encoding *onetime_encoding TSRMLS_DC) { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 6f385c1b51..795868f314 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -220,7 +220,7 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce if (EG(scope) != ce && is_derived_class(ce, EG(scope)) && EG(scope) - && zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS + && zend_u_hash_quick_find(&EG(scope)->properties_info, Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS && scope_property_info->flags & ZEND_ACC_PRIVATE) { return scope_property_info; } else if (property_info) { @@ -229,15 +229,15 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce if (silent) { return NULL; } - zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member)); + zend_error(E_ERROR, "Cannot access %s property %v::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member)); } else { /* fall through, return property_info... */ } } else { EG(std_property_info).flags = ZEND_ACC_PUBLIC; - EG(std_property_info).name = Z_STRVAL_P(member); - EG(std_property_info).name_length = Z_STRLEN_P(member); - EG(std_property_info).h = zend_get_hash_value(EG(std_property_info).name, EG(std_property_info).name_length+1); + EG(std_property_info).name = Z_UNIVAL_P(member); + EG(std_property_info).name_length = Z_UNILEN_P(member); + EG(std_property_info).h = zend_u_get_hash_value(Z_TYPE_P(member), EG(std_property_info).name, EG(std_property_info).name_length+1); property_info = &EG(std_property_info); } return property_info; @@ -249,14 +249,19 @@ ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name zend_property_info *property_info; char *class_name, *prop_name; zval member; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; - zend_unmangle_property_name(prop_info_name, &class_name, &prop_name); - ZVAL_STRING(&member, prop_name, 0); + zend_u_unmangle_property_name(utype, prop_info_name, &class_name, &prop_name); + if (utype == IS_UNICODE) { + ZVAL_UNICODE(&member, (UChar*)prop_name, 0); + } else { + ZVAL_STRING(&member, prop_name, 0); + } property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC); if (!property_info) { return FAILURE; } - if (prop_info_name[0] == '\0' && prop_info_name[1] != '*') { + if (class_name && class_name[0] != '*') { if (!(property_info->flags & ZEND_ACC_PRIVATE)) { /* we we're looking for a private prop but found a non private one of the same name */ return FAILURE; @@ -298,7 +303,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* make zend_get_property_info silent if we have getter - we may want to use it */ property_info = zend_get_property_info(zobj->ce, member, use_get TSRMLS_CC); - if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { + if (!property_info || zend_u_hash_quick_find(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { if (use_get) { /* have getter - try with it! */ zobj->in_get = 1; /* prevent circular getting */ @@ -312,7 +317,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) } } else { if (!silent) { - zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member)); + zend_error(E_NOTICE,"Undefined property: %v::$%s", zobj->ce->name, Z_STRVAL_P(member)); } retval = &EG(uninitialized_zval_ptr); } @@ -338,18 +343,18 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM zobj = Z_OBJ_P(object); use_set = (zobj->ce->__set && !zobj->in_set); - if (member->type != IS_STRING) { + if (member->type != IS_STRING && member->type != IS_UNICODE) { ALLOC_ZVAL(tmp_member); *tmp_member = *member; INIT_PZVAL(tmp_member); zval_copy_ctor(tmp_member); - convert_to_string(tmp_member); + convert_to_text(tmp_member); member = tmp_member; } property_info = zend_get_property_info(zobj->ce, member, use_set TSRMLS_CC); - if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) { + if (property_info && zend_u_hash_quick_find(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) { if (*variable_ptr == value) { /* if we already have this value there, we don't actually need to do anything */ setter_done = 1; @@ -386,7 +391,7 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } - zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo); + zend_u_hash_quick_update(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo); } if (tmp_member) { zval_ptr_dtor(&tmp_member); @@ -411,7 +416,7 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) if (!retval) { if (!EG(exception)) { - zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); + zend_error(E_ERROR, "Undefined offset for object of type %v used as array", ce->name); } return 0; } @@ -421,7 +426,7 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) return retval; } else { - zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); + zend_error(E_ERROR, "Cannot use object of type %v as array", ce->name); return 0; } } @@ -440,7 +445,7 @@ static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSR zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value); zval_ptr_dtor(&offset); } else { - zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); + zend_error(E_ERROR, "Cannot use object of type %v as array", ce->name); } } @@ -469,7 +474,7 @@ static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TS } zval_ptr_dtor(&offset); } else { - zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); + zend_error(E_ERROR, "Cannot use object of type %v as array", ce->name); return 0; } return result; @@ -485,10 +490,10 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC zobj = Z_OBJ_P(object); - if (member->type != IS_STRING) { + if (member->type != IS_STRING && member->type != IS_UNICODE) { tmp_member = *member; zval_copy_ctor(&tmp_member); - convert_to_string(&tmp_member); + convert_to_text(&tmp_member); member = &tmp_member; } @@ -498,7 +503,7 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC property_info = zend_get_property_info(zobj->ce, member, 0 TSRMLS_CC); - if (zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { + if (zend_u_hash_quick_find(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { zval *new_zval; if (!zobj->ce->__get && !zobj->ce->__set) { @@ -507,7 +512,7 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC /* zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */ new_zval->refcount++; - zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_quick_update(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval); } else { /* we do have getter - fail and let it try again with usual get/set */ retval = NULL; @@ -530,18 +535,18 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC) zobj = Z_OBJ_P(object); use_unset = (zobj->ce->__unset && !zobj->in_unset); - if (member->type != IS_STRING) { + if (member->type != IS_STRING && member->type != IS_UNICODE) { ALLOC_ZVAL(tmp_member); *tmp_member = *member; INIT_PZVAL(tmp_member); zval_copy_ctor(tmp_member); - convert_to_string(tmp_member); + convert_to_text(tmp_member); member = tmp_member; } property_info = zend_get_property_info(zobj->ce, member, 0 TSRMLS_CC); - if (!property_info || zend_hash_del(zobj->properties, property_info->name, property_info->name_length+1) == FAILURE) { + if (!property_info || zend_u_hash_del(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1)) { if (use_unset) { /* have unseter - try with it! */ zobj->in_unset = 1; /* prevent circular unsetting */ @@ -565,7 +570,7 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset); zval_ptr_dtor(&offset); } else { - zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); + zend_error(E_ERROR, "Cannot use object of type %v as array", ce->name); } } @@ -589,7 +594,11 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) ALLOC_ZVAL(method_name_ptr); INIT_PZVAL(method_name_ptr); - ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ + if (UG(unicode)) { + ZVAL_UNICODE(method_name_ptr, (UChar*)func->function_name, 0); /* no dup - it's a copy */ + } else { + ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ + } /* __call handler is called with two arguments: method name @@ -640,7 +649,7 @@ static inline zend_function *zend_check_private_int(zend_function *fbc, zend_cla ce = ce->parent; while (ce) { if (ce == EG(scope)) { - if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS + if (zend_u_hash_find(&ce->function_table, UG(unicode)?IS_UNICODE:IS_STRING, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE && fbc->common.scope == EG(scope)) { return fbc; @@ -692,16 +701,19 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method { zend_object *zobj; zend_function *fbc; + unsigned int lc_method_name_len; char *lc_method_name; zval *object = *object_ptr; - lc_method_name = do_alloca(method_len+1); + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; + /* Create a zend_copy_str_tolower(dest, src, src_length); */ - zend_str_tolower_copy(lc_method_name, method_name, method_len); + lc_method_name = zend_u_str_case_fold(type, method_name, method_len, 1, &lc_method_name_len); zobj = Z_OBJ_P(object); - if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) { - free_alloca(lc_method_name); + if (zend_u_hash_find(&zobj->ce->function_table, type, lc_method_name, lc_method_name_len+1, (void **)&fbc) == FAILURE) { + efree(lc_method_name); if (zobj->ce->__call) { zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function)); call_user_call->type = ZEND_INTERNAL_FUNCTION; @@ -710,7 +722,11 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method call_user_call->num_args = 0; call_user_call->scope = zobj->ce; call_user_call->fn_flags = 0; - call_user_call->function_name = estrndup(method_name, method_len); + if (UG(unicode)) { + call_user_call->function_name = (char*)eustrndup((UChar*)method_name, method_len); + } else { + call_user_call->function_name = estrndup(method_name, method_len); + } call_user_call->pass_rest_by_reference = 0; call_user_call->return_reference = ZEND_RETURN_VALUE; @@ -728,7 +744,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method if (EG(scope) && fbc->op_array.fn_flags & ZEND_ACC_CHANGED) { zend_function *priv_fbc; - if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS + if (zend_u_hash_find(&EG(scope)->function_table, type, lc_method_name, lc_method_name_len+1, (void **) &priv_fbc)==SUCCESS && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE && priv_fbc->common.scope == EG(scope)) { fbc = priv_fbc; @@ -741,18 +757,18 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method */ updated_fbc = zend_check_private_int(fbc, object->value.obj.handlers->get_class_entry(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC); if (!updated_fbc) { - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to %s method %v::%v() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : ""); } fbc = updated_fbc; } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(fbc->common.scope, EG(scope))) { - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to %s method %v::%v() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : ""); } } - free_alloca(lc_method_name); + efree(lc_method_name); return fbc; } @@ -761,14 +777,16 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) { zend_function *fbc; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==FAILURE) { + if (zend_u_hash_find(&ce->function_table, type, function_name_strval, function_name_strlen+1, (void **) &fbc)==FAILURE) { char *class_name = ce->name; if (!class_name) { - class_name = ""; + class_name = EMPTY_STR; } - zend_error(E_ERROR, "Call to undefined method %s::%s()", class_name, function_name_strval); + zend_error(E_ERROR, "Call to undefined method %R::%R()", type, class_name, type, function_name_strval); } if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) { /* No further checks necessary, most common case */ @@ -779,14 +797,14 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f */ updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC); if (!updated_fbc) { - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to %s method %v::%v() from context '%v'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : EMPTY_STR); } fbc = updated_fbc; } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(EG(scope), fbc->common.scope)) { - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to %s method %v::%v() from context '%v'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : EMPTY_STR); } } @@ -800,8 +818,9 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *propert zend_class_entry *tmp_ce = ce; zend_property_info *property_info; zend_property_info std_property_info; + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) { + if (zend_u_hash_find(&ce->properties_info, type, property_name, property_name_len+1, (void **) &property_info)==FAILURE) { std_property_info.flags = ZEND_ACC_PUBLIC; std_property_info.name = property_name; std_property_info.name_length = property_name_len; @@ -810,23 +829,23 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *propert } #if DEBUG_OBJECT_HANDLERS - zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags)); + zend_printf("Access type for %v::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags)); #endif if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) { if (!silent) { - zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name); + zend_error(E_ERROR, "Cannot access %s property %v::$%s", zend_visibility_string(property_info->flags), ce->name, property_name); } return NULL; } - zend_hash_quick_find(tmp_ce->static_members, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); + zend_u_hash_quick_find(tmp_ce->static_members, type, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); if (!retval) { if (silent) { return NULL; } else { - zend_error(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); + zend_error(E_ERROR, "Access to undeclared static property: %v::$%s", ce->name, property_name); } } @@ -837,7 +856,7 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *propert ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) { - zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name); + zend_error(E_ERROR, "Attempt to unset static property %v::$%s", ce->name, property_name); return 0; } @@ -854,13 +873,13 @@ static union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (object->value.obj.handlers->get_class_entry(object TSRMLS_CC) != EG(scope)) { - zend_error(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to private %v::%v() from context '%v'", constructor->common.scope->name, constructor->common.function_name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(constructor->common.scope, EG(scope))) { - zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope) ? EG(scope)->name : ""); + zend_error(E_ERROR, "Call to protected %v::%v() from context '%v'", constructor->common.scope->name, constructor->common.function_name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -897,12 +916,12 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists zobj = Z_OBJ_P(object); use_isset = (zobj->ce->__isset && !zobj->in_isset); - if (member->type != IS_STRING) { + if (member->type != IS_STRING && member->type != IS_UNICODE) { ALLOC_ZVAL(tmp_member); *tmp_member = *member; INIT_PZVAL(tmp_member); zval_copy_ctor(tmp_member); - convert_to_string(tmp_member); + convert_to_text(tmp_member); member = tmp_member; } @@ -912,7 +931,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC); - if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) { + if (!property_info || zend_u_hash_quick_find(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) { result = 0; if (use_isset && (has_set_exists != 2)) { zval *rv; @@ -979,7 +998,11 @@ int zend_std_object_get_class_name(zval *object, char **class_name, zend_uint *c } *class_name_len = ce->name_length; - *class_name = estrndup(ce->name, ce->name_length); + if (UG(unicode)) { + *class_name = (char*)eustrndup((UChar*)ce->name, ce->name_length); + } else { + *class_name = estrndup(ce->name, ce->name_length); + } return SUCCESS; } @@ -989,14 +1012,22 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty switch (type) { case IS_STRING: + case IS_UNICODE: if (!zend_hash_exists(&Z_OBJCE_P(readobj)->function_table, "__tostring", sizeof("__tostring"))) { return FAILURE; } - ZVAL_STRING(&fname, "__tostring", 0); + if (UG(unicode)) { + ZVAL_UNICODE(&fname, USTR_MAKE("__tostring"), 0); + } else { + ZVAL_STRING(&fname, "__tostring", 0); + } if (call_user_function_ex(NULL, &readobj, &fname, &retval, 0, NULL, 0, NULL TSRMLS_CC) == SUCCESS) { + if (UG(unicode)) { + zval_dtor(&fname); + } if (retval) { - if (Z_TYPE_P(retval) != IS_STRING) { - zend_error(E_ERROR, "Method %s::__toString() must return a string value", Z_OBJCE_P(readobj)->name); + if (Z_TYPE_P(retval) != IS_STRING && Z_TYPE_P(retval) != IS_UNICODE) { + zend_error(E_ERROR, "Method %v::__toString() must return a string value", Z_OBJCE_P(readobj)->name); } } else { MAKE_STD_ZVAL(retval); @@ -1008,6 +1039,9 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty zval_ptr_dtor(&retval); return SUCCESS; } + if (UG(unicode)) { + zval_dtor(&fname); + } break; default: break; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 9b5b854220..83f0d809b5 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -42,9 +42,9 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl zend_class_entry *ce = object->ce; zend_error(EG(in_execution) ? E_ERROR : E_WARNING, - "Call to private %s::__destruct() from context '%s'%s", + "Call to private %v::__destruct() from context '%v'%s", ce->name, - EG(scope) ? EG(scope)->name : "", + EG(scope) ? EG(scope)->name : EMPTY_STR, EG(in_execution) ? "" : " during shutdown ignored"); return; } @@ -55,9 +55,9 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl zend_class_entry *ce = object->ce; zend_error(EG(in_execution) ? E_ERROR : E_WARNING, - "Call to protected %s::__destruct() from context '%s'%s", + "Call to protected %v::__destruct() from context '%v'%s", ce->name, - EG(scope) ? EG(scope)->name : "", + EG(scope) ? EG(scope)->name : EMPTY_STR, EG(in_execution) ? "" : " during shutdown ignored"); return; } @@ -78,7 +78,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl zend_call_method_with_0_params(&obj, object->ce, &object->ce->destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL); if (old_exception) { if (EG(exception)) { - zend_error(E_ERROR, "Ignoring exception from %s::__destruct() while an exception is already active", object->ce->name); + zend_error(E_ERROR, "Ignoring exception from %v::__destruct() while an exception is already active", object->ce->name); zval_ptr_dtor(&EG(exception)); } EG(exception) = old_exception; @@ -167,7 +167,7 @@ ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC) new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC); ALLOC_HASHTABLE(new_object->properties); - zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index a13181c5cc..ab62dcfe48 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -186,7 +186,7 @@ ZEND_API zend_object_value zend_objects_store_clone_obj(zval *zobject TSRMLS_DC) obj = &EG(objects_store).object_buckets[handle].bucket.obj; if (obj->clone == NULL) { - zend_error(E_CORE_ERROR, "Trying to clone uncloneable object of class %s", Z_OBJCE_P(zobject)->name); + zend_error(E_CORE_ERROR, "Trying to clone uncloneable object of class %v", Z_OBJCE_P(zobject)->name); } obj->clone(obj->object, &new_object TSRMLS_CC); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 37bb6b604a..56823cccdf 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -386,9 +386,10 @@ int pass_two(zend_op_array *op_array TSRMLS_DC) int print_class(zend_class_entry *class_entry TSRMLS_DC) { - printf("Class %s:\n", class_entry->name); + /* UTODO: fix these to use spprintf() */ + printf("Class %v:\n", class_entry->name); zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC); - printf("End of class %s.\n\n", class_entry->name); + printf("End of class %v.\n\n", class_entry->name); return 0; } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 509f9e2315..bb09fb3bb9 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -31,6 +31,8 @@ #include "zend_multiply.h" #include "zend_strtod.h" +#include "unicode/uchar.h" + #define LONG_SIGN_MASK (1L << (8*sizeof(long)-1)) ZEND_API int zend_atoi(const char *str, int str_len) @@ -111,6 +113,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) { switch (op->type) { case IS_STRING: + case IS_BINARY: { char *strval; @@ -127,6 +130,24 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) STR_FREE(strval); break; } + case IS_UNICODE: + { + UChar *strval; + + strval = op->value.ustr.val; + switch ((op->type=is_numeric_unicode(strval, op->value.ustr.len, &op->value.lval, &op->value.dval, 1))) { + case IS_DOUBLE: + case IS_LONG: + break; + default: + op->value.lval = zend_u_strtol(op->value.ustr.val, NULL, 10); + op->type = IS_LONG; + break; + } + USTR_FREE(strval); + break; + } + break; case IS_BOOL: op->type = IS_LONG; break; @@ -152,6 +173,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) } else { \ switch ((op)->type) { \ case IS_STRING: \ + case IS_BINARY: \ { \ switch (((holder).type=is_numeric_string((op)->value.str.val, (op)->value.str.len, &(holder).value.lval, &(holder).value.dval, 1))) { \ case IS_DOUBLE: \ @@ -165,6 +187,20 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) (op) = &(holder); \ break; \ } \ + case IS_UNICODE: \ + { \ + switch (((holder).type=is_numeric_unicode((op)->value.ustr.val, (op)->value.ustr.len, &(holder).value.lval, &(holder).value.dval, 1))) { \ + case IS_DOUBLE: \ + case IS_LONG: \ + break; \ + default: \ + (holder).value.lval = zend_u_strtol((op)->value.ustr.val, NULL, 10); \ + (holder).type = IS_LONG; \ + break; \ + } \ + (op) = &(holder); \ + break; \ + } \ case IS_BOOL: \ case IS_RESOURCE: \ (holder).value.lval = (op)->value.lval; \ @@ -202,8 +238,12 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) DVAL_TO_LVAL((op)->value.dval, (holder).value.lval); \ break; \ case IS_STRING: \ + case IS_BINARY: \ (holder).value.lval = strtol((op)->value.str.val, NULL, 10); \ break; \ + case IS_UNICODE: \ + (holder).value.lval = zend_u_strtol((op)->value.ustr.val, NULL, 10); \ + break; \ case IS_ARRAY: \ (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \ break; \ @@ -242,6 +282,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) (holder).value.lval = ((op)->value.dval ? 1 : 0); \ break; \ case IS_STRING: \ + case IS_BINARY: \ if ((op)->value.str.len == 0 \ || ((op)->value.str.len==1 && (op)->value.str.val[0]=='0')) { \ (holder).value.lval = 0; \ @@ -249,6 +290,15 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) (holder).value.lval = 1; \ } \ break; \ + case IS_UNICODE: \ + if ((op)->value.ustr.len == 0 \ + || ((op)->value.ustr.len==1 && \ + ((op)->value.ustr.val[0]=='0'))) { \ + (holder).value.lval = 0; \ + } else { \ + (holder).value.lval = 1; \ + } \ + break; \ case IS_ARRAY: \ (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \ break; \ @@ -293,7 +343,6 @@ ZEND_API void convert_to_long(zval *op) ZEND_API void convert_to_long_base(zval *op, int base) { - char *strval; long tmp; switch (op->type) { @@ -313,9 +362,19 @@ ZEND_API void convert_to_long_base(zval *op, int base) DVAL_TO_LVAL(op->value.dval, op->value.lval); break; case IS_STRING: - strval = op->value.str.val; - op->value.lval = strtol(strval, NULL, base); - STR_FREE(strval); + case IS_BINARY: + { + char *strval = op->value.str.val; + op->value.lval = strtol(strval, NULL, base); + STR_FREE(strval); + } + break; + case IS_UNICODE: + { + UChar *strval = op->value.ustr.val; + op->value.lval = zend_u_strtol(strval, NULL, base); + USTR_FREE(strval); + } break; case IS_ARRAY: tmp = (zend_hash_num_elements(op->value.ht)?1:0); @@ -358,7 +417,6 @@ ZEND_API void convert_to_long_base(zval *op, int base) ZEND_API void convert_to_double(zval *op) { - char *strval; double tmp; switch (op->type) { @@ -378,10 +436,21 @@ ZEND_API void convert_to_double(zval *op) case IS_DOUBLE: break; case IS_STRING: - strval = op->value.str.val; + case IS_BINARY: + { + char *strval = op->value.str.val; - op->value.dval = zend_strtod(strval, NULL); - STR_FREE(strval); + op->value.dval = zend_strtod(strval, NULL); + STR_FREE(strval); + } + break; + case IS_UNICODE: + { + UChar *strval = op->value.ustr.val; + + op->value.dval = zend_u_strtod(strval, NULL); + USTR_FREE(strval); + } break; case IS_ARRAY: tmp = (zend_hash_num_elements(op->value.ht)?1:0); @@ -405,7 +474,7 @@ ZEND_API void convert_to_double(zval *op) retval = (zend_hash_num_elements(ht)?1.0:0.0); } } else { - zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name); + zend_error(E_NOTICE, "Object of class %v could not be converted to double", Z_OBJCE_P(op)->name); } zval_dtor(op); @@ -440,7 +509,6 @@ ZEND_API void convert_to_null(zval *op) ZEND_API void convert_to_boolean(zval *op) { - char *strval; int tmp; switch (op->type) { @@ -462,15 +530,32 @@ ZEND_API void convert_to_boolean(zval *op) op->value.lval = (op->value.dval ? 1 : 0); break; case IS_STRING: - strval = op->value.str.val; + case IS_BINARY: + { + char *strval = op->value.str.val; - if (op->value.str.len == 0 - || (op->value.str.len==1 && op->value.str.val[0]=='0')) { - op->value.lval = 0; - } else { - op->value.lval = 1; + if (op->value.str.len == 0 + || (op->value.str.len==1 && op->value.str.val[0]=='0')) { + op->value.lval = 0; + } else { + op->value.lval = 1; + } + STR_FREE(strval); + } + break; + case IS_UNICODE: + { + UChar *strval = op->value.ustr.val; + + if (op->value.ustr.len == 0 + || (op->value.ustr.len==1 && + (op->value.ustr.val[0]=='0'))) { + op->value.lval = 0; + } else { + op->value.lval = 1; + } + USTR_FREE(strval); } - STR_FREE(strval); break; case IS_ARRAY: tmp = (zend_hash_num_elements(op->value.ht)?1:0); @@ -507,7 +592,94 @@ ZEND_API void convert_to_boolean(zval *op) op->type = IS_BOOL; } +ZEND_API void _convert_to_unicode(zval *op TSRMLS_DC ZEND_FILE_LINE_DC) +{ + switch (op->type) { + case IS_NULL: + op->value.ustr.val = USTR_MAKE_REL(""); + op->value.ustr.len = 0; + break; + case IS_UNICODE: + break; + case IS_STRING: + zval_string_to_unicode(op TSRMLS_CC); + break; + case IS_BINARY: + zend_error(E_ERROR, "Cannot convert binary type to Unicode type"); + return; + case IS_BOOL: + if (op->value.lval) { + op->value.ustr.val = USTR_MAKE_REL("1"); + op->value.ustr.len = 1; + } else { + op->value.ustr.val = USTR_MAKE_REL(""); + op->value.ustr.len = 0; + } + break; + case IS_RESOURCE: { + long tmp = op->value.lval; + TSRMLS_FETCH(); + + zend_list_delete(op->value.lval); + op->value.ustr.val = eumalloc_rel(sizeof("Resource id #")-1 + MAX_LENGTH_OF_LONG + 1); + op->value.ustr.len = u_sprintf(op->value.ustr.val, "Resource id #%ld", tmp); + break; + } + case IS_LONG: { + int32_t capacity = MAX_LENGTH_OF_LONG + 1; + long lval = op->value.lval; + + op->value.ustr.val = eumalloc_rel(capacity); + op->value.ustr.len = u_sprintf(op->value.ustr.val, "%ld", lval); + break; + } + case IS_DOUBLE: { + int32_t capacity; + double dval = op->value.dval; + TSRMLS_FETCH(); + + capacity = MAX_LENGTH_OF_DOUBLE + EG(precision) + 1; + op->value.ustr.val = eumalloc_rel(capacity); + op->value.ustr.len = u_sprintf(op->value.ustr.val, "%.*G", (int) EG(precision), dval); + break; + } + case IS_ARRAY: + zend_error(E_NOTICE, "Array to string conversion"); + zval_dtor(op); + op->value.ustr.val = USTR_MAKE_REL("Array"); + op->value.ustr.len = sizeof("Array")-1; + break; + case IS_OBJECT: { + TSRMLS_FETCH(); + + convert_object_to_type(op, IS_UNICODE, convert_to_unicode); + + if (op->type == IS_UNICODE) { + return; + } + + zend_error(E_NOTICE, "Object of class %v to string conversion", Z_OBJCE_P(op)->name); + zval_dtor(op); + op->value.ustr.val = USTR_MAKE_REL("Object"); + op->value.ustr.len = sizeof("Object")-1; + break; + } + default: + zval_dtor(op); + ZVAL_BOOL(op, 0); + break; + } + op->type = IS_UNICODE; +} + + ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) +{ + TSRMLS_FETCH(); + _convert_to_string_with_converter(op, ZEND_U_CONVERTER(UG(runtime_encoding_conv)) TSRMLS_CC ZEND_FILE_LINE_CC); +} + +ZEND_API void _convert_to_string_with_converter(zval *op, UConverter *conv TSRMLS_DC ZEND_FILE_LINE_DC) { long lval; double dval; @@ -518,6 +690,26 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) op->value.str.len = 0; break; case IS_STRING: + if (conv == ZEND_U_CONVERTER(UG(runtime_encoding_conv))) { + break; + } else { + char *s; + int32_t s_len; + UErrorCode status = U_ZERO_ERROR; + s = op->value.str.val; + s_len = op->value.str.len; + zend_convert_encodings(conv, ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &op->value.str.val, &op->value.str.len, s, s_len, &status); + efree(s); + if (U_FAILURE(status)) { + zend_error(E_WARNING, "Error converting string for printing"); + } + } + break; + case IS_BINARY: + zend_error(E_ERROR, "Cannot convert binary type to string type"); + return; + case IS_UNICODE: + zval_unicode_to_string(op, conv TSRMLS_CC); break; case IS_BOOL: if (op->value.lval) { @@ -566,7 +758,7 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) return; } - zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name); + zend_error(E_NOTICE, "Object of class %v to string conversion", Z_OBJCE_P(op)->name); zval_dtor(op); op->value.str.val = estrndup_rel("Object", sizeof("Object")-1); op->value.str.len = sizeof("Object")-1; @@ -580,8 +772,35 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) op->type = IS_STRING; } +ZEND_API void convert_to_binary(zval *op) +{ + switch (op->type) { + case IS_BINARY: + break; + case IS_OBJECT: { + TSRMLS_FETCH(); + + convert_object_to_type(op, IS_BINARY, convert_to_binary); -static void convert_scalar_to_array(zval *op, int type) + if (op->type == IS_BINARY) { + return; + } + + zend_error(E_NOTICE, "Object of class %v to binary conversion", Z_OBJCE_P(op)->name); + zval_dtor(op); + op->value.str.val = estrndup("Object", sizeof("Object")-1); + op->value.str.len = sizeof("Object")-1; + break; + } + default: + convert_to_string(op); + break; + } + op->type = IS_BINARY; +} + + +static void convert_scalar_to_array(zval *op, int type TSRMLS_DC) { zval *entry; @@ -592,7 +811,7 @@ static void convert_scalar_to_array(zval *op, int type) switch (type) { case IS_ARRAY: ALLOC_HASHTABLE(op->value.ht); - zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_index_update(op->value.ht, 0, (void *) &entry, sizeof(zval *), NULL); op->type = IS_ARRAY; break; @@ -624,7 +843,7 @@ ZEND_API void convert_to_array(zval *op) HashTable *ht; ALLOC_HASHTABLE(ht); - zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); if (Z_OBJ_HT_P(op)->get_properties) { HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC); if(obj_ht) { @@ -644,11 +863,11 @@ ZEND_API void convert_to_array(zval *op) return; case IS_NULL: ALLOC_HASHTABLE(op->value.ht); - zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); op->type = IS_ARRAY; break; default: - convert_scalar_to_array(op, IS_ARRAY); + convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC); break; } } @@ -656,12 +875,10 @@ ZEND_API void convert_to_array(zval *op) ZEND_API void convert_to_object(zval *op) { + TSRMLS_FETCH(); switch (op->type) { case IS_ARRAY: { - /* OBJECTS_OPTIMIZE */ - TSRMLS_FETCH(); - object_and_properties_init(op, zend_standard_class_def, op->value.ht); return; break; @@ -677,7 +894,7 @@ ZEND_API void convert_to_object(zval *op) break; } default: - convert_scalar_to_array(op, IS_OBJECT); + convert_scalar_to_array(op, IS_OBJECT TSRMLS_CC); break; } } @@ -957,10 +1174,10 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) result->type = IS_LONG; return SUCCESS; } - if (op1->type == IS_STRING) { + if (op1->type == IS_STRING || op1->type == IS_BINARY) { int i; - result->type = IS_STRING; + result->type = op1->type; result->value.str.val = estrndup(op1->value.str.val, op1->value.str.len); result->value.str.len = op1->value.str.len; for (i = 0; i < op1->value.str.len; i++) { @@ -976,8 +1193,9 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; - - if (op1->type == IS_STRING && op2->type == IS_STRING) { + + if ((op1->type == IS_STRING && op2->type == IS_STRING) || + (op1->type == IS_BINARY && op2->type == IS_BINARY)) { zval *longer, *shorter; char *result_str; int i, result_len; @@ -990,7 +1208,7 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) shorter = op1; } - result->type = IS_STRING; + result->type = op1->type; result_len = longer->value.str.len; result_str = estrndup(longer->value.str.val, longer->value.str.len); for (i = 0; i < shorter->value.str.len; i++) { @@ -1003,6 +1221,10 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result->value.str.len = result_len; return SUCCESS; } + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; + } zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); @@ -1016,7 +1238,8 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; - if (op1->type == IS_STRING && op2->type == IS_STRING) { + if ((op1->type == IS_STRING && op2->type == IS_STRING) || + (op1->type == IS_BINARY && op2->type == IS_BINARY)) { zval *longer, *shorter; char *result_str; int i, result_len; @@ -1029,7 +1252,7 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) shorter = op1; } - result->type = IS_STRING; + result->type = op1->type; result_len = shorter->value.str.len; result_str = estrndup(shorter->value.str.val, shorter->value.str.len); for (i = 0; i < shorter->value.str.len; i++) { @@ -1043,6 +1266,10 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; + } zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); @@ -1057,7 +1284,8 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; - if (op1->type == IS_STRING && op2->type == IS_STRING) { + if ((op1->type == IS_STRING && op2->type == IS_STRING) || + (op1->type == IS_BINARY && op2->type == IS_BINARY)) { zval *longer, *shorter; char *result_str; int i, result_len; @@ -1070,7 +1298,7 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) shorter = op1; } - result->type = IS_STRING; + result->type = op1->type; result_len = shorter->value.str.len; result_str = estrndup(shorter->value.str.val, shorter->value.str.len); for (i = 0; i < shorter->value.str.len; i++) { @@ -1084,6 +1312,11 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; + } + zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); @@ -1097,6 +1330,11 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; + } + zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); result->value.lval = op1->value.lval << op2->value.lval; @@ -1109,6 +1347,11 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; + } + zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); result->value.lval = op1->value.lval >> op2->value.lval; @@ -1117,15 +1360,31 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) } - /* must support result==op1 */ ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2) { - result->value.str.len = op1->value.str.len + 1; - result->value.str.val = (char *) erealloc(op1->value.str.val, result->value.str.len+1); - result->value.str.val[result->value.str.len - 1] = (char) op2->value.lval; - result->value.str.val[result->value.str.len] = 0; - result->type = IS_STRING; + if (op1->type == IS_UNICODE) { + UChar32 codepoint = (UChar32) op2->value.lval; + + if (U_IS_BMP(codepoint)) { + result->value.ustr.len = op1->value.ustr.len + 1; + result->value.ustr.val = eurealloc(op1->value.ustr.val, result->value.ustr.len+1); + result->value.ustr.val[result->value.ustr.len - 1] = (UChar) op2->value.lval; + } else { + result->value.ustr.len = op1->value.ustr.len + 2; + result->value.ustr.val = eurealloc(op1->value.ustr.val, result->value.ustr.len+1); + result->value.ustr.val[result->value.ustr.len - 2] = (UChar) U16_LEAD(codepoint); + result->value.ustr.val[result->value.ustr.len - 1] = (UChar) U16_TRAIL(codepoint); + } + result->value.ustr.val[result->value.ustr.len] = 0; + result->type = IS_UNICODE; + } else { + result->value.str.len = op1->value.str.len + 1; + result->value.str.val = (char *) erealloc(op1->value.str.val, result->value.str.len+1); + result->value.str.val[result->value.str.len - 1] = (char) op2->value.lval; + result->value.str.val[result->value.str.len] = 0; + result->type = op1->type; + } return SUCCESS; } @@ -1133,13 +1392,25 @@ ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2) /* must support result==op1 */ ZEND_API int add_string_to_string(zval *result, zval *op1, zval *op2) { - int length = op1->value.str.len + op2->value.str.len; + assert(op1->type == op2->type); - result->value.str.val = (char *) erealloc(op1->value.str.val, length+1); - memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val, op2->value.str.len); - result->value.str.val[length] = 0; - result->value.str.len = length; - result->type = IS_STRING; + if (op1->type == IS_UNICODE) { + int32_t length = op1->value.ustr.len + op2->value.ustr.len; + + result->value.ustr.val = eurealloc(op1->value.ustr.val, length+1); + u_memcpy(result->value.ustr.val+op1->value.ustr.len, op2->value.ustr.val, op2->value.ustr.len); + result->value.ustr.val[length] = 0; + result->value.ustr.len = length; + result->type = IS_UNICODE; + } else { + int length = op1->value.str.len + op2->value.str.len; + + result->value.str.val = (char *) erealloc(op1->value.str.val, length+1); + memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val, op2->value.str.len); + result->value.str.val[length] = 0; + result->value.str.len = length; + result->type = op1->type; + } return SUCCESS; } @@ -1148,10 +1419,21 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { zval op1_copy, op2_copy; int use_copy1, use_copy2; - - - zend_make_printable_zval(op1, &op1_copy, &use_copy1); - zend_make_printable_zval(op2, &op2_copy, &use_copy2); + zend_uchar result_type; + + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zend_make_unicode_zval(op1, &op1_copy, &use_copy1); + zend_make_unicode_zval(op2, &op2_copy, &use_copy2); + result_type = IS_UNICODE; + } else if (op1->type == IS_BINARY && op2->type == IS_BINARY) { + result_type = IS_BINARY; + /* no conversion necessary */ + use_copy1 = use_copy2 = 0; + } else { + result_type = IS_STRING; + zend_make_string_zval(op1, &op1_copy, &use_copy1); + zend_make_string_zval(op2, &op2_copy, &use_copy2); + } if (use_copy1) { /* We have created a converted copy of op1. Therefore, op1 won't become the result so @@ -1166,20 +1448,23 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) op2 = &op2_copy; } if (result==op1) { /* special case, perform operations on result */ - uint res_len = op1->value.str.len + op2->value.str.len; - - result->value.str.val = erealloc(result->value.str.val, res_len+1); - - memcpy(result->value.str.val+result->value.str.len, op2->value.str.val, op2->value.str.len); - result->value.str.val[res_len]=0; - result->value.str.len = res_len; + add_string_to_string(result, op1, op2); } else { - result->value.str.len = op1->value.str.len + op2->value.str.len; - result->value.str.val = (char *) emalloc(result->value.str.len + 1); - memcpy(result->value.str.val, op1->value.str.val, op1->value.str.len); - memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val, op2->value.str.len); - result->value.str.val[result->value.str.len] = 0; - result->type = IS_STRING; + if (result_type == IS_UNICODE) { + result->value.ustr.len = op1->value.ustr.len + op2->value.ustr.len; + result->value.ustr.val = eumalloc(result->value.ustr.len + 1); + u_memcpy(result->value.ustr.val, op1->value.ustr.val, op1->value.ustr.len); + u_memcpy(result->value.ustr.val+op1->value.ustr.len, op2->value.ustr.val, op2->value.ustr.len); + result->value.ustr.val[result->value.ustr.len] = 0; + result->type = IS_UNICODE; + } else { + result->value.str.len = op1->value.str.len + op2->value.str.len; + result->value.str.val = (char *) emalloc(result->value.str.len + 1); + memcpy(result->value.str.val, op1->value.str.val, op1->value.str.len); + memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val, op2->value.str.len); + result->value.str.val[result->value.str.len] = 0; + result->type = result_type; + } } if (use_copy1) { zval_dtor(op1); @@ -1314,8 +1599,18 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) } } - if (op1->type == IS_STRING && op2->type == IS_STRING) { - zendi_smart_strcmp(result, op1, op2); + if ((op1->type == IS_UNICODE || op1->type == IS_STRING || op1->type == IS_BINARY) && + (op2->type == IS_UNICODE || op2->type == IS_STRING || op2->type == IS_BINARY)) { + + if (op1->type == IS_UNICODE || op2->type == IS_UNICODE) { + zendi_u_smart_strcmp(result, op1, op2); + } else if (op1->type == IS_STRING || op2->type == IS_STRING) { + zendi_smart_strcmp(result, op1, op2); + } else { + result->value.lval = zend_binary_zval_strcmp(op1, op2); + result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval); + result->type = IS_LONG; + } COMPARE_RETURN_AND_FREE(SUCCESS); } @@ -1421,6 +1716,7 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result->value.lval = (op1->value.dval == op2->value.dval); break; case IS_STRING: + case IS_BINARY: if ((op1->value.str.len == op2->value.str.len) && (!memcmp(op1->value.str.val, op2->value.str.val, op1->value.str.len))) { result->value.lval = 1; @@ -1428,6 +1724,14 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result->value.lval = 0; } break; + case IS_UNICODE: + if ((op1->value.ustr.len == op2->value.ustr.len) + && (!memcmp(op1->value.ustr.val, op2->value.ustr.val, UBYTES(op1->value.ustr.len)))) { + result->value.lval = 1; + } else { + result->value.lval = 0; + } + break; case IS_ARRAY: if (zend_hash_compare(op1->value.ht, op2->value.ht, (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0) { result->value.lval = 1; @@ -1682,6 +1986,7 @@ ZEND_API int increment_function(zval *op1) op1->value.lval = 1; op1->type = IS_LONG; break; + case IS_BINARY: case IS_STRING: { long lval; double dval; @@ -1711,6 +2016,9 @@ ZEND_API int increment_function(zval *op1) } } break; + case IS_UNICODE: + zend_error(E_ERROR, "Unsupported operand type"); + break; default: return FAILURE; } @@ -1735,6 +2043,7 @@ ZEND_API int decrement_function(zval *op1) case IS_DOUBLE: op1->value.dval = op1->value.dval - 1; break; + case IS_BINARY: case IS_STRING: /* Like perl we only support string increment */ if (op1->value.str.len == 0) { /* consider as 0 */ STR_FREE(op1->value.str.val); @@ -1760,6 +2069,9 @@ ZEND_API int decrement_function(zval *op1) break; } break; + case IS_UNICODE: + zend_error(E_ERROR, "Unsupported operand type"); + break; default: return FAILURE; } @@ -1788,6 +2100,38 @@ ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned in return dest; } +ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) +{ + return zend_str_tolower_copy((char *)emalloc(length+1), source, length); +} + +ZEND_API void *zend_u_str_tolower_copy(zend_uchar type, void *dest, const void *source, unsigned int length) +{ + if (type == IS_UNICODE) { + register UChar *str = (UChar*)source; + register UChar *result = (UChar*)dest; + register UChar *end = str + length; + + while (str < end) { + *result++ = u_tolower((int)*str++); + } + *result = *end; + + return dest; + } else { + return zend_str_tolower_copy(dest, source, length); + } +} + +ZEND_API void *zend_u_str_tolower_dup(zend_uchar type, const void *source, unsigned int length) +{ + if (type == IS_UNICODE) { + return zend_u_str_tolower_copy(IS_UNICODE, emalloc(UBYTES(length+1)), source, length); + } else { + return zend_str_tolower_copy((char*)emalloc(length+1), (char*)source, length); + } +} + ZEND_API void zend_str_tolower(char *str, unsigned int length) { register unsigned char *p = (unsigned char*)str; @@ -1799,6 +2143,42 @@ ZEND_API void zend_str_tolower(char *str, unsigned int length) } } +ZEND_API void zend_u_str_tolower(zend_uchar type, void *str, unsigned int length) { + if (type == IS_UNICODE) { + register UChar *p = (UChar*)str; + register UChar *end = p + length; + + while (p < end) { + *p = u_tolower((int)*p); + p++; + } + } else { + zend_str_tolower((char*)str, length); + } +} + +ZEND_API void *zend_u_str_case_fold(zend_uchar type, const void *source, unsigned int length, zend_bool normalize, unsigned int *new_len) +{ + if (type == IS_UNICODE) { + UChar *ret; + int32_t ret_len; + + if (normalize) { + zend_normalize_identifier(&ret, &ret_len, (UChar*)source, length, 1); + } else { + UErrorCode status = U_ZERO_ERROR; + + zend_case_fold_string(&ret, &ret_len, (UChar*)source, length, U_FOLD_CASE_DEFAULT, &status); + } + + *new_len = ret_len; + return ret; + } else { + *new_len = length; + return zend_str_tolower_dup(source, length); + } +} + ZEND_API int zend_binary_strcmp(char *s1, uint len1, char *s2, uint len2) { int retval; @@ -1811,6 +2191,20 @@ ZEND_API int zend_binary_strcmp(char *s1, uint len1, char *s2, uint len2) } } + +ZEND_API int zend_u_binary_strcmp(UChar *s1, int32_t len1, UChar *s2, int32_t len2) +{ + int retval; + + retval = u_memcmpCodePointOrder(s1, s2, MIN(len1, len2)); + if (!retval) { + return (len1 - len2); + } else { + return retval; + } +} + + ZEND_API int zend_binary_strncmp(char *s1, uint len1, char *s2, uint len2, uint length) { int retval; @@ -1867,6 +2261,13 @@ ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) return zend_binary_strcmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len); } + +ZEND_API int zend_u_binary_zval_strcmp(zval *s1, zval *s2) +{ + return zend_u_binary_strcmp(s1->value.ustr.val, s1->value.ustr.len, s2->value.ustr.val, s2->value.ustr.len); +} + + ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) { return zend_binary_strncmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len, s3->value.lval); @@ -1891,6 +2292,11 @@ ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) long lval1, lval2; double dval1, dval2; + if (s1->type == IS_BINARY || s2->type == IS_BINARY) { + zend_error(E_ERROR, "Cannot convert binary type to string type"); + return; + } + if ((ret1=is_numeric_string(s1->value.str.val, s1->value.str.len, &lval1, &dval1, 0)) && (ret2=is_numeric_string(s2->value.str.val, s2->value.str.len, &lval2, &dval2, 0))) { if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) { @@ -1916,6 +2322,57 @@ ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) } +ZEND_API void zendi_u_smart_strcmp(zval *result, zval *s1, zval *s2) +{ + int ret1, ret2; + long lval1, lval2; + double dval1, dval2; + zval s1_copy, s2_copy; + int use_copy1 = 0, use_copy2 = 0; + + if (s1->type != IS_UNICODE || s2->type != IS_UNICODE) { + zend_make_unicode_zval(s1, &s1_copy, &use_copy1); + zend_make_unicode_zval(s2, &s2_copy, &use_copy2); + if (use_copy1) { + s1 = &s1_copy; + } + if (use_copy2) { + s2 = &s2_copy; + } + } + + if ((ret1=is_numeric_unicode(s1->value.ustr.val, s1->value.ustr.len, &lval1, &dval1, 0)) && + (ret2=is_numeric_unicode(s2->value.ustr.val, s2->value.ustr.len, &lval2, &dval2, 0))) { + if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) { + if (ret1!=IS_DOUBLE) { + dval1 = zend_u_strtod(s1->value.ustr.val, NULL); + } else if (ret2!=IS_DOUBLE) { + dval2 = zend_u_strtod(s2->value.ustr.val, NULL); + } + result->value.dval = dval1 - dval2; + result->value.lval = ZEND_NORMALIZE_BOOL(result->value.dval); + result->type = IS_LONG; + } else { /* they both have to be long's */ + result->value.lval = lval1 - lval2; + result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval); + result->type = IS_LONG; + } + } else { + result->value.lval = zend_u_binary_zval_strcmp(s1, s2); + result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval); + result->type = IS_LONG; + } + + if (use_copy1) { + zval_dtor(s1); + } + if (use_copy2) { + zval_dtor(s2); + } + return; +} + + static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) { zval result; @@ -1962,6 +2419,22 @@ ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) } } +ZEND_API void zend_locale_usprintf_double(zval *op ZEND_FILE_LINE_DC) +{ + double dval = op->value.dval; + UFILE *strf; + int32_t capacity; + + TSRMLS_FETCH(); + + capacity = MAX_LENGTH_OF_DOUBLE + EG(precision) + 1; + op->value.ustr.val = eumalloc_rel(capacity); + /* UTODO uses default locale for now */ + strf = u_fstropen(op->value.ustr.val, capacity, NULL); + op->value.ustr.len = u_fprintf(strf, "%.*G", (int) EG(precision), dval); + u_fclose(strf); +} + ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) { double dval = op->value.dval; @@ -1973,6 +2446,20 @@ ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) op->value.str.len = strlen(op->value.str.val); } +ZEND_API void zend_locale_usprintf_long(zval *op ZEND_FILE_LINE_DC) +{ + long lval = op->value.lval; + UFILE *strf; + int32_t capacity; + + capacity = MAX_LENGTH_OF_LONG + 1; + op->value.ustr.val = eumalloc_rel(capacity); + /* UTODO uses default locale for now */ + strf = u_fstropen(op->value.ustr.val, capacity, NULL); + op->value.ustr.len = u_fprintf(strf, "%ld", lval); + u_fclose(strf); +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 0f1f23e469..af0b99d1b4 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -30,6 +30,7 @@ #endif #include "zend_strtod.h" +#include "zend_unicode.h" #if 0&&HAVE_BCMATH #include "ext/bcmath/libbcmath/src/bcmath.h" @@ -63,6 +64,8 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR ZEND_API zend_bool instanceof_function_ex(zend_class_entry *instance_ce, zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC); ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC); +ZEND_API long zend_u_strtol(const UChar *nptr, UChar **endptr, int base); +ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr); END_EXTERN_C() static inline zend_bool is_numeric_string(char *str, int length, long *lval, double *dval, zend_bool allow_errors) @@ -128,6 +131,77 @@ static inline zend_bool is_numeric_string(char *str, int length, long *lval, dou return 0; } +static inline zend_bool is_numeric_unicode(UChar *str, int32_t length, long *lval, double *dval, zend_bool allow_errors) +{ + int32_t local_lval; + double local_dval; + UChar *end_ptr_long, *end_ptr_double; + int conv_base=10; + + if (!length) { + return 0; + } + + /* handle hex numbers */ + if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) { + conv_base=16; + } + + errno=0; + local_lval = zend_u_strtol(str, &end_ptr_long, conv_base); + if (errno != ERANGE) { + if (end_ptr_long == str+length) { /* integer string */ + if (lval) { + *lval = local_lval; + } + return IS_LONG; + } else if (end_ptr_long == str && *end_ptr_long != '\0' && *str != '.' && *str != '-') { /* ignore partial string matches */ + return 0; + } + } else { + end_ptr_long = NULL; + } + + if (conv_base == 16) { /* hex string, under UNIX strtod() messes it up */ + /* UTODO: keep compatibility with is_numeric_string() here? */ + return 0; + } + + local_dval = zend_u_strtod(str, &end_ptr_double); + if (local_dval == 0 && end_ptr_double == str) { + end_ptr_double = NULL; + } else { + if (end_ptr_double == str+length) { /* floating point string */ + if (!zend_finite(local_dval)) { + /* "inf","nan" and maybe other weird ones */ + return 0; + } + + if (dval) { + *dval = local_dval; + } + return IS_DOUBLE; + } + } + + if (allow_errors) { + if (end_ptr_double > end_ptr_long && dval) { + *dval = local_dval; + return IS_DOUBLE; + } else if (end_ptr_long && lval) { + *lval = local_lval; + return IS_LONG; + } + } + return 0; +} + +static inline UChar* +zend_u_memnstr(UChar *haystack, UChar *needle, int32_t needle_len, UChar *end) +{ + return u_strFindFirst(haystack, end - haystack, needle, needle_len); +} + static inline char * zend_memnstr(char *haystack, char *needle, int needle_len, char *end) { @@ -160,6 +234,10 @@ ZEND_API int decrement_function(zval *op2); ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC); ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC); +ZEND_API void _convert_to_string_with_converter(zval *op, UConverter *conv TSRMLS_DC ZEND_FILE_LINE_DC); +ZEND_API void _convert_to_unicode(zval *op TSRMLS_DC ZEND_FILE_LINE_DC); +ZEND_API void _convert_to_unicode_with_converter(zval *op, UConverter *conv TSRMLS_DC ZEND_FILE_LINE_DC); +ZEND_API void convert_to_binary(zval *op); ZEND_API void convert_to_long(zval *op); ZEND_API void convert_to_double(zval *op); ZEND_API void convert_to_long_base(zval *op, int base); @@ -172,7 +250,11 @@ ZEND_API void multi_convert_to_double_ex(int argc, ...); ZEND_API void multi_convert_to_string_ex(int argc, ...); ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2); ZEND_API int add_string_to_string(zval *result, zval *op1, zval *op2); -#define convert_to_string(op) _convert_to_string((op) ZEND_FILE_LINE_CC) +#define convert_to_string(op) _convert_to_string((op) ZEND_FILE_LINE_CC) +#define convert_to_string_with_converter(op, conv) _convert_to_string_with_converter((op), (conv) TSRMLS_CC ZEND_FILE_LINE_CC) +#define convert_to_unicode(op) _convert_to_unicode((op) TSRMLS_CC ZEND_FILE_LINE_CC) +#define convert_to_unicode_with_converter(op, conv) _convert_to_unicode_with_converter((op), (conv) TSRMLS_CC ZEND_FILE_LINE_CC) +#define convert_to_text(op) (UG(unicode)?convert_to_unicode(op):convert_to_string(op)) ZEND_API double zend_string_to_double(const char *number, zend_uint length); @@ -186,15 +268,14 @@ ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 T ZEND_API void zend_str_tolower(char *str, unsigned int length); ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); -END_EXTERN_C() +ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length); -static inline char * -zend_str_tolower_dup(const char *source, unsigned int length) -{ - return zend_str_tolower_copy((char *)emalloc(length+1), source, length); -} +ZEND_API void zend_u_str_tolower(zend_uchar type, void *str, unsigned int length); +ZEND_API void *zend_u_str_tolower_copy(zend_uchar type, void *dest, const void *source, unsigned int length); +ZEND_API void *zend_u_str_tolower_dup(zend_uchar type, const void *source, unsigned int length); + +ZEND_API void *zend_u_str_case_fold(zend_uchar type, const void *source, unsigned int length, zend_bool normalize, unsigned int *new_len); -BEGIN_EXTERN_C() ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); @@ -204,7 +285,11 @@ ZEND_API int zend_binary_strncmp(char *s1, uint len1, char *s2, uint len2, uint ZEND_API int zend_binary_strcasecmp(char *s1, uint len1, char *s2, uint len2); ZEND_API int zend_binary_strncasecmp(char *s1, uint len1, char *s2, uint len2, uint length); +ZEND_API int zend_u_binary_zval_strcmp(zval *s1, zval *s2); +ZEND_API int zend_u_binary_strcmp(UChar *s1, int32_t len1, UChar *s2, int32_t len2); + ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2); +ZEND_API void zendi_u_smart_strcmp(zval *result, zval *s1, zval *s2); ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC); ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC); ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC); @@ -212,6 +297,8 @@ ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC); ZEND_API int zend_atoi(const char *str, int str_len); ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); +ZEND_API void zend_locale_usprintf_double(zval *op ZEND_FILE_LINE_DC); +ZEND_API void zend_locale_usprintf_long(zval *op ZEND_FILE_LINE_DC); END_EXTERN_C() #define convert_to_ex_master(ppzv, lower_type, upper_type) \ if ((*ppzv)->type!=IS_##upper_type) { \ @@ -219,14 +306,59 @@ END_EXTERN_C() convert_to_##lower_type(*ppzv); \ } +#define convert_to_explicit_type(pzv, type) \ + do { \ + switch (type) { \ + case IS_NULL: \ + convert_to_null(pzv); \ + break; \ + case IS_LONG: \ + convert_to_long(pzv); \ + break; \ + case IS_DOUBLE: \ + convert_to_double(pzv); \ + break; \ + case IS_BOOL: \ + convert_to_bool(pzv); \ + break; \ + case IS_ARRAY: \ + convert_to_array(pzv); \ + break; \ + case IS_OBJECT: \ + convert_to_object(pzv); \ + break; \ + case IS_STRING: \ + convert_to_string(pzv); \ + break; \ + case IS_UNICODE: \ + convert_to_unicode(pzv); \ + break; \ + case IS_BINARY: \ + convert_to_binary(pzv); \ + break; \ + default: \ + assert(0); \ + break; \ + } \ + } while (0); \ + +#define convert_to_explicit_type_ex(ppzv, type) \ + if ((*ppzv)->type != type) { \ + SEPARATE_ZVAL_IF_NOT_REF(ppzv); \ + convert_to_explicit_type(*ppzv, type); \ + } \ +} #define convert_to_boolean_ex(ppzv) convert_to_ex_master(ppzv, boolean, BOOL) #define convert_to_long_ex(ppzv) convert_to_ex_master(ppzv, long, LONG) #define convert_to_double_ex(ppzv) convert_to_ex_master(ppzv, double, DOUBLE) #define convert_to_string_ex(ppzv) convert_to_ex_master(ppzv, string, STRING) +#define convert_to_unicode_ex(ppzv) convert_to_ex_master(ppzv, unicode, UNICODE) +#define convert_to_binary_ex(ppzv) convert_to_ex_master(ppzv, binary, BINARY) #define convert_to_array_ex(ppzv) convert_to_ex_master(ppzv, array, ARRAY) #define convert_to_object_ex(ppzv) convert_to_ex_master(ppzv, object, OBJECT) #define convert_to_null_ex(ppzv) convert_to_ex_master(ppzv, null, NULL) +#define convert_to_text_ex(ppzv) if (UG(unicode)) {convert_to_unicode_ex(ppzv);} else {convert_to_string_ex(ppzv);} #define convert_scalar_to_number_ex(ppzv) \ if ((*ppzv)->type!=IS_LONG && (*ppzv)->type!=IS_DOUBLE) { \ @@ -242,6 +374,11 @@ END_EXTERN_C() #define Z_DVAL(zval) (zval).value.dval #define Z_STRVAL(zval) (zval).value.str.val #define Z_STRLEN(zval) (zval).value.str.len +#define Z_USTRVAL(zval) (zval).value.ustr.val +#define Z_USTRLEN(zval) (zval).value.ustr.len +#define Z_USTRCPLEN(zval) (u_countChar32((zval).value.ustr.val, (zval).value.ustr.len)) +#define Z_BINVAL(zval) Z_STRVAL(zval) +#define Z_BINLEN(zval) Z_STRLEN(zval) #define Z_ARRVAL(zval) (zval).value.ht #define Z_OBJ_HANDLE(zval) (zval).value.obj.handle #define Z_OBJ_HT(zval) (zval).value.obj.handlers @@ -249,12 +386,19 @@ END_EXTERN_C() #define Z_OBJPROP(zval) Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC) #define Z_OBJ_HANDLER(zval, hf) Z_OBJ_HT((zval))->hf #define Z_RESVAL(zval) (zval).value.lval +#define Z_UNIVAL(zval) ((zval).type==IS_UNICODE?(char*)(zval).value.ustr.val:(zval).value.str.val) +#define Z_UNILEN(zval) ((zval).type==IS_UNICODE?(zval).value.ustr.len:(zval).value.str.len) #define Z_LVAL_P(zval_p) Z_LVAL(*zval_p) #define Z_BVAL_P(zval_p) Z_BVAL(*zval_p) #define Z_DVAL_P(zval_p) Z_DVAL(*zval_p) #define Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p) #define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p) +#define Z_USTRVAL_P(zval_p) Z_USTRVAL(*zval_p) +#define Z_USTRLEN_P(zval_p) Z_USTRLEN(*zval_p) +#define Z_USTRCPLEN_P(zval_p) Z_USTRCPLEN(*zval_p) +#define Z_BINVAL_P(zval) Z_STRVAL_P(zval) +#define Z_BINLEN_P(zval) Z_STRLEN_P(zval) #define Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p) #define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p) #define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p) @@ -262,12 +406,19 @@ END_EXTERN_C() #define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p) #define Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p) #define Z_OBJ_HANDLER_P(zval_p, h) Z_OBJ_HANDLER(*zval_p, h) +#define Z_UNIVAL_P(zval_p) Z_UNIVAL(*zval_p) +#define Z_UNILEN_P(zval_p) Z_UNILEN(*zval_p) #define Z_LVAL_PP(zval_pp) Z_LVAL(**zval_pp) #define Z_BVAL_PP(zval_pp) Z_BVAL(**zval_pp) #define Z_DVAL_PP(zval_pp) Z_DVAL(**zval_pp) #define Z_STRVAL_PP(zval_pp) Z_STRVAL(**zval_pp) #define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp) +#define Z_USTRVAL_PP(zval_pp) Z_USTRVAL(**zval_pp) +#define Z_USTRLEN_PP(zval_pp) Z_USTRLEN(**zval_pp) +#define Z_USTRCPLEN_PP(zval_pp) Z_USTRCPLEN(**zval_pp) +#define Z_BINVAL_PP(zval) Z_STRVAL_PP(zval) +#define Z_BINLEN_PP(zval) Z_STRLEN_PP(zval) #define Z_ARRVAL_PP(zval_pp) Z_ARRVAL(**zval_pp) #define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp) #define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp) @@ -275,6 +426,8 @@ END_EXTERN_C() #define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p) #define Z_OBJ_HT_PP(zval_p) Z_OBJ_HT(**zval_p) #define Z_OBJ_HANDLER_PP(zval_p, h) Z_OBJ_HANDLER(**zval_p, h) +#define Z_UNIVAL_PP(zval_pp) Z_UNIVAL(**zval_pp) +#define Z_UNILEN_PP(zval_pp) Z_UNILEN(**zval_pp) #define Z_TYPE(zval) (zval).type #define Z_TYPE_P(zval_p) Z_TYPE(*zval_p) diff --git a/Zend/zend_reflection_api.c b/Zend/zend_reflection_api.c index 2bbd91bc98..fa001dc9b9 100644 --- a/Zend/zend_reflection_api.c +++ b/Zend/zend_reflection_api.c @@ -43,7 +43,7 @@ zend_class_entry *reflection_extension_ptr; /* Method macros */ #define METHOD_NOTSTATIC \ if (!this_ptr) { \ - zend_error(E_ERROR, "%s() cannot be called statically", get_active_function_name(TSRMLS_C)); \ + zend_error(E_ERROR, "%v() cannot be called statically", get_active_function_name(TSRMLS_C)); \ return; \ } \ @@ -233,7 +233,7 @@ static zend_object_value reflection_objects_new(zend_class_entry *class_type TSR intern->free_ptr = 0; ALLOC_HASHTABLE(intern->zo.properties); - zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, reflection_objects_clone TSRMLS_CC); retval.handlers = &reflection_object_handlers; @@ -297,17 +297,17 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in } string_printf(str, "class "); } - string_write(str, ce->name, ce->name_length); + string_printf(str, "%v", ce->name); if (ce->parent) { - string_printf(str, " extends %s", ce->parent->name); + string_printf(str, " extends %v", ce->parent->name); } if (ce->num_interfaces) { zend_uint i; - string_printf(str, " implements %s", ce->interfaces[0]->name); + string_printf(str, " implements %v", ce->interfaces[0]->name); for (i = 1; i < ce->num_interfaces; ++i) { - string_printf(str, ", %s", ce->interfaces[i]->name); + string_printf(str, ", %v", ce->interfaces[i]->name); } } string_printf(str, " ] {\n"); @@ -540,7 +540,7 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_printf(str, " "); } if (arg_info->class_name) { - string_printf(str, "%s ", arg_info->class_name); + string_printf(str, "%v ", arg_info->class_name); if (arg_info->allow_null) { string_printf(str, "or NULL "); } @@ -554,7 +554,7 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_write(str, "&", sizeof("&")-1); } if (arg_info->name) { - string_printf(str, "$%s", arg_info->name); + string_printf(str, "$%v", arg_info->name); } else { string_printf(str, "$param%d", offset); } @@ -671,7 +671,7 @@ static void _function_string(string *str, zend_function *fptr, char* indent TSRM if (fptr->op_array.return_reference) { string_printf(str, "&"); } - string_printf(str, "%s ] {\n", fptr->common.function_name); + string_printf(str, "%v ] {\n", fptr->common.function_name); /* The information where a function is declared is only available for user classes */ if (fptr->type == ZEND_USER_FUNCTION) { string_printf(str, "%s @@ %s %d - %d\n", indent, @@ -720,8 +720,8 @@ static void _property_string(string *str, zend_property_info *prop, char *prop_n string_printf(str, "static "); } - zend_unmangle_property_name(prop->name, &class_name, &prop_name); - string_printf(str, "$%s", prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, prop->name, &class_name, &prop_name); + string_printf(str, "$%v", prop_name); } string_printf(str, " ]\n"); @@ -865,7 +865,11 @@ ZEND_API void zend_reflection_class_factory(zend_class_entry *ce, zval *object T zval *name; MAKE_STD_ZVAL(name); - ZVAL_STRINGL(name, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(name, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_class_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = ce; @@ -912,7 +916,11 @@ static void reflection_parameter_factory(zend_function *fptr, struct _zend_arg_i MAKE_STD_ZVAL(name); if (arg_info->name) { - ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)arg_info->name, arg_info->name_len, 1); + } else { + ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1); + } } else { ZVAL_NULL(name); } @@ -937,7 +945,11 @@ static void reflection_function_factory(zend_function *function, zval *object TS zval *name; MAKE_STD_ZVAL(name); - ZVAL_STRING(name, function->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)function->common.function_name, 1); + } else { + ZVAL_STRING(name, function->common.function_name, 1); + } reflection_instanciate(reflection_function_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -956,9 +968,14 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho zval *classname; MAKE_STD_ZVAL(name); - ZVAL_STRING(name, method->common.function_name, 1); MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)method->common.function_name, 1); + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRING(name, method->common.function_name, 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_method_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = method; @@ -978,7 +995,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info property_reference *reference; char *class_name, *prop_name; - zend_unmangle_property_name(prop->name, &class_name, &prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, prop->name, &class_name, &prop_name); if (!(prop->flags & ZEND_ACC_PRIVATE)) { /* we have to seach the class hierarchy for this (implicit) public or protected property */ @@ -997,10 +1014,14 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info } MAKE_STD_ZVAL(name); - ZVAL_STRING(name, prop_name, 1); - MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)prop_name, 1); + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRING(name, prop_name, 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_property_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -1144,7 +1165,7 @@ ZEND_METHOD(reflection, export) } if (!retval_ptr) { - zend_error(E_WARNING, "%s::__toString() did not return anything", Z_OBJCE_P(object)->name); + zend_error(E_WARNING, "%v::__toString() did not return anything", Z_OBJCE_P(object)->name); RETURN_FALSE; } @@ -1211,13 +1232,15 @@ ZEND_METHOD(reflection_function, __construct) { zval *name; zval *object; + unsigned int lcname_len; char *lcname; reflection_object *intern; zend_function *fptr; char *name_str; int name_len; + zend_uchar type; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name_str, &name_len, &type) == FAILURE) { return; } @@ -1226,17 +1249,20 @@ ZEND_METHOD(reflection_function, __construct) if (intern == NULL) { return; } - lcname = do_alloca(name_len + 1); - zend_str_tolower_copy(lcname, name_str, name_len); - if (zend_hash_find(EG(function_table), lcname, name_len + 1, (void **)&fptr) == FAILURE) { - free_alloca(lcname); + lcname = zend_u_str_case_fold(type, name_str, name_len, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), type, lcname, lcname_len + 1, (void **)&fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Function %s() does not exist", name_str); + "Function %R() does not exist", type, name_str); return; } - free_alloca(lcname); + efree(lcname); MAKE_STD_ZVAL(name); - ZVAL_STRING(name, fptr->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)fptr->common.function_name, 1); + } else { + ZVAL_STRING(name, fptr->common.function_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = fptr; intern->free_ptr = 0; @@ -1421,7 +1447,7 @@ ZEND_METHOD(reflection_function, invoke) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of function %s() failed", fptr->common.function_name); + "Invocation of function %v() failed", fptr->common.function_name); return; } @@ -1485,7 +1511,7 @@ ZEND_METHOD(reflection_function, invokeArgs) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of function %s() failed", fptr->common.function_name); + "Invocation of function %v() failed", fptr->common.function_name); return; } @@ -1598,19 +1624,20 @@ ZEND_METHOD(reflection_parameter, __construct) /* First, find the function */ switch (Z_TYPE_P(reference)) { + case IS_UNICODE: case IS_STRING: { - char *lcname; + unsigned int lcname_len; + char *lcname; - convert_to_string_ex(&reference); - lcname = do_alloca(Z_STRLEN_P(reference) + 1); - zend_str_tolower_copy(lcname, Z_STRVAL_P(reference), Z_STRLEN_P(reference)); - if (zend_hash_find(EG(function_table), lcname, (int) Z_STRLEN_P(reference) + 1, (void**) &fptr) == FAILURE) { - free_alloca(lcname); + convert_to_text_ex(&reference); + lcname = zend_u_str_case_fold(Z_TYPE_P(reference), Z_STRVAL_P(reference), Z_STRLEN_P(reference), 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(reference), lcname, lcname_len + 1, (void**) &fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Function %s() does not exist", Z_STRVAL_P(reference)); + "Function %R() does not exist", Z_TYPE_P(reference), Z_STRVAL_P(reference)); return; } - free_alloca(lcname); + efree(lcname); } break; @@ -1618,7 +1645,8 @@ ZEND_METHOD(reflection_parameter, __construct) zval **classref; zval **method; zend_class_entry **pce; - char *lcname; + unsigned int lcname_len; + char *lcname; if ((zend_hash_index_find(Z_ARRVAL_P(reference), 0, (void **) &classref) == FAILURE) || (zend_hash_index_find(Z_ARRVAL_P(reference), 1, (void **) &method) == FAILURE)) { @@ -1629,25 +1657,24 @@ ZEND_METHOD(reflection_parameter, __construct) if (Z_TYPE_PP(classref) == IS_OBJECT) { ce = Z_OBJCE_PP(classref); } else { - convert_to_string_ex(classref); - if (zend_lookup_class(Z_STRVAL_PP(classref), Z_STRLEN_PP(classref), &pce TSRMLS_CC) == FAILURE) { + convert_to_text_ex(classref); + if (zend_u_lookup_class(Z_TYPE_PP(classref), Z_UNIVAL_PP(classref), Z_UNILEN_PP(classref), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_PP(classref)); + "Class %R does not exist", Z_TYPE_PP(classref), Z_UNIVAL_PP(classref)); return; } ce = *pce; } - convert_to_string_ex(method); - lcname = do_alloca(Z_STRLEN_PP(method) + 1); - zend_str_tolower_copy(lcname, Z_STRVAL_PP(method), Z_STRLEN_PP(method)); - if (zend_hash_find(&ce->function_table, lcname, (int)(Z_STRLEN_PP(method) + 1), (void **) &fptr) == FAILURE) { - free_alloca(lcname); + convert_to_text_ex(method); + lcname = zend_u_str_case_fold(Z_TYPE_PP(method), Z_UNIVAL_PP(method), Z_UNILEN_PP(method), 1, &lcname_len); + if (zend_u_hash_find(&ce->function_table, Z_TYPE_PP(method), lcname, lcname_len + 1, (void **) &fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s::%s() does not exist", Z_STRVAL_PP(classref), Z_STRVAL_PP(method)); + "Method %R::%R() does not exist", Z_TYPE_PP(classref), Z_UNIVAL_PP(classref), Z_TYPE_PP(method), Z_UNIVAL_PP(method)); return; } - free_alloca(lcname); + efree(lcname); } break; @@ -1683,7 +1710,11 @@ ZEND_METHOD(reflection_parameter, __construct) MAKE_STD_ZVAL(name); if (arg_info[position].name) { - ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)arg_info[position].name, arg_info[position].name_len, 1); + } else { + ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1); + } } else { ZVAL_NULL(name); } @@ -1739,15 +1770,16 @@ ZEND_METHOD(reflection_parameter, getClass) RETURN_NULL(); } else { zend_class_entry **pce; - char *lcname = do_alloca(param->arg_info->class_name_len + 1); - zend_str_tolower_copy(lcname, param->arg_info->class_name, param->arg_info->class_name_len); - if (zend_hash_find(EG(class_table), lcname, param->arg_info->class_name_len + 1, (void **) &pce) == FAILURE) { - free_alloca(lcname); + unsigned int lcname_len; + char *lcname = zend_u_str_case_fold(UG(unicode)?IS_UNICODE:IS_STRING, param->arg_info->class_name, param->arg_info->class_name_len, 0, &lcname_len); + + if (zend_u_hash_find(EG(class_table), UG(unicode)?IS_UNICODE:IS_STRING, lcname, lcname_len + 1, (void **) &pce) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", param->arg_info->class_name); + "Class %v does not exist", param->arg_info->class_name); return; } - free_alloca(lcname); + efree(lcname); zend_reflection_class_factory(*pce, return_value TSRMLS_CC); } } @@ -1884,14 +1916,16 @@ ZEND_METHOD(reflection_method, __construct) zval *name, *classname; zval *object; reflection_object *intern; + unsigned int lcname_len; char *lcname; zend_class_entry **pce; zend_class_entry *ce; zend_function *mptr; char *name_str; int name_len; + zend_uchar type; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zt", &classname, &name_str, &name_len, &type) == FAILURE) { return; } @@ -1904,9 +1938,10 @@ ZEND_METHOD(reflection_method, __construct) /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(classname), Z_UNIVAL_P(classname), Z_UNILEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_P(classname)); + "Class %v does not exist", Z_UNIVAL_P(classname)); return; } ce = *pce; @@ -1922,22 +1957,29 @@ ZEND_METHOD(reflection_method, __construct) } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - lcname = do_alloca(name_len + 1); - zend_str_tolower_copy(lcname, name_str, name_len); + lcname = zend_u_str_case_fold(type, name_str, name_len, 1, &lcname_len); - if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void **) &mptr) == FAILURE) { - free_alloca(lcname); + if (zend_u_hash_find(&ce->function_table, type, lcname, lcname_len + 1, (void **) &mptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s::%s() does not exist", ce->name, name_str); + "Method %v::%R() does not exist", ce->name, type, name_str); return; } - free_alloca(lcname); + efree(lcname); MAKE_STD_ZVAL(name); - ZVAL_STRING(name, mptr->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)mptr->common.function_name, 1); + } else { + ZVAL_STRING(name, mptr->common.function_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = mptr; intern->free_ptr = 0; @@ -1989,11 +2031,11 @@ ZEND_METHOD(reflection_method, invoke) (mptr->common.fn_flags & ZEND_ACC_ABSTRACT)) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s()", + "Trying to invoke abstract method %v::%v()", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s() from scope %s", + "Trying to invoke %s method %v::%v() from scope %v", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2054,7 +2096,7 @@ ZEND_METHOD(reflection_method, invoke) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); + "Invocation of method %v::%v() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2092,11 +2134,11 @@ ZEND_METHOD(reflection_method, invokeArgs) (mptr->common.fn_flags & ZEND_ACC_ABSTRACT)) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s", + "Trying to invoke abstract method %v::%v", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s from scope %s", + "Trying to invoke %s method %v::%v from scope %v", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2123,7 +2165,7 @@ ZEND_METHOD(reflection_method, invokeArgs) if (!object) { efree(params); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke non static method %s::%s without an object", + "Trying to invoke non static method %v::%v without an object", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2158,7 +2200,7 @@ ZEND_METHOD(reflection_method, invokeArgs) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); + "Invocation of method %v::%v() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2308,7 +2350,11 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob if (Z_TYPE_P(argument) == IS_OBJECT) { MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + } else { + ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); intern->ptr = Z_OBJCE_P(argument); if (is_object) { @@ -2317,7 +2363,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob } } else { convert_to_string_ex(&argument); - if (zend_lookup_class(Z_STRVAL_P(argument), Z_STRLEN_P(argument), &ce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(Z_TYPE_P(argument), Z_UNIVAL_P(argument), Z_UNILEN_P(argument), &ce TSRMLS_CC) == FAILURE) { if (!EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, -1 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(argument)); } @@ -2325,7 +2371,11 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)((*ce)->name), (*ce)->name_length, 1); + } else { + ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); intern->ptr = *ce; @@ -2613,17 +2663,19 @@ ZEND_METHOD(reflection_class, hasMethod) { reflection_object *intern; zend_class_entry *ce; + unsigned int lc_name_len; char *name, *lc_name; int name_len; + zend_uchar type; METHOD_NOTSTATIC; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name, &name_len, &type) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if (zend_hash_exists(&ce->function_table, lc_name, name_len + 1)) { + lc_name = zend_u_str_case_fold(type, name, name_len, 1, &lc_name_len); + if (zend_u_hash_exists(&ce->function_table, type, lc_name, lc_name_len + 1)) { efree(lc_name); RETURN_TRUE; } else { @@ -2640,23 +2692,25 @@ ZEND_METHOD(reflection_class, getMethod) reflection_object *intern; zend_class_entry *ce; zend_function *mptr; + unsigned int lc_name_len; char *name, *lc_name; int name_len; + zend_uchar type; METHOD_NOTSTATIC; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name, &name_len, &type) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if (zend_hash_find(&ce->function_table, lc_name, name_len + 1, (void**) &mptr) == SUCCESS) { + lc_name = zend_u_str_case_fold(type, name, name_len, 1, &lc_name_len); + if (zend_u_hash_find(&ce->function_table, type, lc_name, lc_name_len + 1, (void**) &mptr) == SUCCESS) { reflection_method_factory(ce, mptr, return_value TSRMLS_CC); efree(lc_name); } else { efree(lc_name); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s does not exist", name); + "Method %R does not exist", type, name); return; } } @@ -2989,7 +3043,7 @@ ZEND_METHOD(reflection_class, newInstance) zend_fcall_info_cache fcc; if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name); + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %v", ce->name); return; } @@ -3017,7 +3071,7 @@ ZEND_METHOD(reflection_class, newInstance) if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { efree(params); zval_ptr_dtor(&retval_ptr); - zend_error(E_WARNING, "Invocation of %s's constructor failed", ce->name); + zend_error(E_WARNING, "Invocation of %v's constructor failed", ce->name); RETURN_NULL(); } if (retval_ptr) { @@ -3089,7 +3143,8 @@ ZEND_METHOD(reflection_class, isSubclassOf) switch(class_name->type) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s does not exist", Z_STRVAL_P(class_name)); return; @@ -3135,7 +3190,8 @@ ZEND_METHOD(reflection_class, implementsInterface) switch(interface->type) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(interface), Z_STRLEN_P(interface), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(interface), Z_UNIVAL_P(interface), Z_UNILEN_P(interface), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s does not exist", Z_STRVAL_P(interface)); return; @@ -3161,7 +3217,7 @@ ZEND_METHOD(reflection_class, implementsInterface) if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Interface %s is a Class", interface_ce->name); + "Interface %v is a Class", interface_ce->name); return; } RETURN_BOOL(instanceof_function(ce, interface_ce TSRMLS_CC)); @@ -3267,7 +3323,8 @@ ZEND_METHOD(reflection_property, __construct) /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(classname), Z_UNIVAL_P(classname), Z_UNILEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(classname)); return; @@ -3286,7 +3343,7 @@ ZEND_METHOD(reflection_property, __construct) if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Property %s::$%s does not exist", ce->name, name_str); + "Property %v::$%s does not exist", ce->name, name_str); return; } @@ -3307,12 +3364,20 @@ ZEND_METHOD(reflection_property, __construct) } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - zend_unmangle_property_name(property_info->name, &class_name, &prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, property_info->name, &class_name, &prop_name); MAKE_STD_ZVAL(propname); - ZVAL_STRING(propname, prop_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(propname, (UChar*)prop_name, 1); + } else { + ZVAL_STRING(propname, prop_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &propname, sizeof(zval *), NULL); reference = (property_reference*) emalloc(sizeof(property_reference)); @@ -3421,6 +3486,7 @@ ZEND_METHOD(reflection_property, getValue) property_reference *ref; zval *object; zval **member= NULL; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); @@ -3432,16 +3498,16 @@ ZEND_METHOD(reflection_property, getValue) if ((ref->prop->flags & ZEND_ACC_STATIC)) { zend_update_class_constants(intern->ce TSRMLS_CC); - if (zend_hash_quick_find(intern->ce->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(intern->ce->static_members, utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } } else { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { return; } - if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(Z_OBJPROP_P(object), utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } } @@ -3463,6 +3529,7 @@ ZEND_METHOD(reflection_property, setValue) int setter_done = 0; zval *tmp; HashTable *prop_table; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); @@ -3486,8 +3553,8 @@ ZEND_METHOD(reflection_property, setValue) prop_table = Z_OBJPROP_P(object); } - if (zend_hash_quick_find(prop_table, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(prop_table, utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } if (*variable_ptr == value) { @@ -3510,7 +3577,7 @@ ZEND_METHOD(reflection_property, setValue) if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } - zend_hash_quick_update(prop_table, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); + zend_u_hash_quick_update(prop_table, utype, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); } } /* }}} */ @@ -3943,12 +4010,13 @@ static zend_object_handlers *zend_std_obj_handlers; /* {{{ _reflection_write_property */ static void _reflection_write_property(zval *object, zval *member, zval *value TSRMLS_DC) { - if (Z_TYPE_P(member) == IS_STRING - && zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) - && (!strcmp(Z_STRVAL_P(member), "name") || !strcmp(Z_STRVAL_P(member), "class"))) + if ((Z_TYPE_P(member) == IS_STRING || Z_TYPE_P(member) == IS_UNICODE) + && zend_u_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member)+1) + && (ZEND_U_EQUAL(Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member), "name", sizeof("name")-1) || + ZEND_U_EQUAL(Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member), "class", sizeof("class")-1))) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Cannot set read-only property %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member)); + "Cannot set read-only property %v::$%R", Z_OBJCE_P(object)->name, Z_TYPE_P(member), Z_UNIVAL_P(member)); } else { @@ -4038,6 +4106,20 @@ ZEND_API void zend_register_reflection_api(TSRMLS_D) { } /* }}} */ +void init_reflection_api(TSRMLS_D) +{ + reflection_exception_ptr = zend_get_named_class_entry("ReflectionException", sizeof("ReflectionException")-1 TSRMLS_CC); + reflection_ptr = zend_get_named_class_entry("Reflection", sizeof("Reflection")-1 TSRMLS_CC); + reflector_ptr = zend_get_named_class_entry("Reflector", sizeof("Reflector")-1 TSRMLS_CC); + reflection_function_ptr = zend_get_named_class_entry("ReflectionFunction", sizeof("ReflectionFunction")-1 TSRMLS_CC); + reflection_parameter_ptr = zend_get_named_class_entry("ReflectionParameter", sizeof("ReflectionParameter")-1 TSRMLS_CC); + reflection_method_ptr = zend_get_named_class_entry("ReflectionMethod", sizeof("ReflectionMethod")-1 TSRMLS_CC); + reflection_class_ptr = zend_get_named_class_entry("ReflectionClass", sizeof("ReflectionClass")-1 TSRMLS_CC); + reflection_object_ptr = zend_get_named_class_entry("ReflectionObject", sizeof("ReflectionObject")-1 TSRMLS_CC); + reflection_property_ptr = zend_get_named_class_entry("ReflectionProperty", sizeof("ReflectionProperty")-1 TSRMLS_CC); + reflection_extension_ptr = zend_get_named_class_entry("ReflectionExtension", sizeof("ReflectionExtension")-1 TSRMLS_CC); +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_reflection_api.h b/Zend/zend_reflection_api.h index fb06af4687..a16ed9b7f9 100644 --- a/Zend/zend_reflection_api.h +++ b/Zend/zend_reflection_api.h @@ -26,6 +26,8 @@ BEGIN_EXTERN_C() ZEND_API void zend_register_reflection_api(TSRMLS_D); ZEND_API void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_DC); +void init_reflection_api(TSRMLS_D); + END_EXTERN_C() #endif diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index 87d755006a..1810c5bf27 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -90,6 +90,8 @@ */ #include +#include +#include #ifdef HAVE_SYS_TYPES_H #include @@ -1778,3 +1780,23 @@ zend_strtod result = sign ? -value(rv) : value(rv); return result; } + +/* UTODO: someone can reimplement this using the code above, if they really want to. */ +ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr) +{ + double value; + int32_t num_conv = 0, num_read = 0; + + num_conv = u_sscanf(nptr, "%f%n", &value, &num_read); + if (num_conv != EOF) { + if (endptr != 0) { + *endptr = (UChar *)nptr + num_read; + } + return value; + } else { + if (endptr != 0) { + *endptr = (UChar *)nptr; + } + return 0; + } +} diff --git a/Zend/zend_strtol.c b/Zend/zend_strtol.c new file mode 100644 index 0000000000..9a56cac107 --- /dev/null +++ b/Zend/zend_strtol.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Convert a Unicode string to a long integer. + * + * Ignores `locale' stuff. + */ +long +zend_u_strtol(nptr, endptr, base) + const UChar *nptr; + UChar **endptr; + register int base; +{ + register const UChar *s = nptr; + register unsigned long acc; + register UChar c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + register int32_t val; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (u_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + (c == '0') + && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = (c == '0') ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if ((val = u_digit(c, base)) < 0) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += val; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (UChar *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/Zend/zend_unicode.c b/Zend/zend_unicode.c new file mode 100644 index 0000000000..edaf9568a2 --- /dev/null +++ b/Zend/zend_unicode.c @@ -0,0 +1,597 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2004 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andrei Zmievski | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "zend_globals.h" +#include "zend_operators.h" +#include "zend_API.h" +#include "zend_unicode.h" +#include + +#ifdef ZTS +ZEND_API ts_rsrc_id unicode_globals_id; +#else +ZEND_API zend_unicode_globals unicode_globals; +#endif + +static void zend_from_unicode_substitute_cb( + const void *context, + UConverterFromUnicodeArgs *toUArgs, + const char *codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode *err + ) +{ + if (context == NULL) { + if (reason > UCNV_IRREGULAR) + { + return; + } + + *err = U_ZERO_ERROR; + //ucnv_cbFromUWriteSub(fromArgs, 0, err); + return; + } else if (*((char*)context)=='i') { + if (reason != UCNV_UNASSIGNED) + { + /* the caller must have set + * the error code accordingly + */ + return; + } else { + *err = U_ZERO_ERROR; + //ucnv_cbFromUWriteSub(fromArgs, 0, err); + return; + } + } +} + +/* {{{ zend_set_converter_error_mode */ +void zend_set_converter_error_mode(UConverter *conv, uint8_t error_mode) +{ + UErrorCode status = U_ZERO_ERROR; + + switch (error_mode) { + case ZEND_FROM_U_ERROR_STOP: + ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_SKIP: + ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_SKIP, UCNV_SKIP_STOP_ON_ILLEGAL, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_ESCAPE: + /* UTODO replace with custom callback for various substitution patterns */ + ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_ESCAPE, UCNV_ESCAPE_UNICODE, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_SUBST: + ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_SUBSTITUTE, UCNV_SKIP_STOP_ON_ILLEGAL, NULL, NULL, &status); + break; + + default: + assert(0); + break; + } +} +/* }}} */ + +/* {{{ zend_set_converter_subst_char */ +void zend_set_converter_subst_char(UConverter *conv, UChar *subst_char, int8_t subst_char_len) +{ + char dest[8]; + int8_t dest_len = 8; + UErrorCode status = U_ZERO_ERROR; + UErrorCode temp = U_ZERO_ERROR; + const void *old_context; + UConverterFromUCallback old_cb; + + if (!subst_char_len) + return; + + ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_STOP, NULL, &old_cb, &old_context, &temp); + dest_len = ucnv_fromUChars(conv, dest, dest_len, subst_char, subst_char_len, &status); + ucnv_setFromUCallBack(conv, old_cb, old_context, NULL, NULL, &temp); + if (U_FAILURE(status)) { + zend_error(E_WARNING, "Could not set substitution character for the converter"); + return; + } + ucnv_setSubstChars(conv, dest, dest_len, &status); + if (status == U_ILLEGAL_ARGUMENT_ERROR) { + zend_error(E_WARNING, "Substitution character byte sequence is too short or long for this converter"); + return; + } +} +/* }}} */ + +/* {{{ zend_set_converter_encoding */ +int zend_set_converter_encoding(UConverter **converter, const char *encoding) +{ + UErrorCode status = U_ZERO_ERROR; + UConverter *new_converter = NULL; + + if (!converter) { + return FAILURE; + } + + /* + * The specified encoding might be the same as converter's existing one, + * which results in a no-op. + */ + if (*converter && encoding && encoding[0]) { + const char *current = ucnv_getName(*converter, &status); + status = U_ZERO_ERROR; /* reset error */ + if (!ucnv_compareNames(current, encoding)) { + return SUCCESS; + } + } + + /* + * If encoding is NULL, ucnv_open() will return a converter based on + * the default platform encoding as determined by ucnv_getDefaultName(). + */ + new_converter = ucnv_open(encoding, &status); + if (U_FAILURE(status)) { + return FAILURE; + } + + if (*converter) { + ucnv_close(*converter); + } + *converter = new_converter; + + return SUCCESS; +} +/* }}} */ + +/* {{{ zend_copy_converter */ +int zend_copy_converter(UConverter **target, UConverter *source) +{ + UErrorCode status = U_ZERO_ERROR; + const char *encoding; + + assert(source != NULL); + + encoding = ucnv_getName(source, &status); + if (U_FAILURE(status)) { + return FAILURE; + } + + return zend_set_converter_encoding(target, encoding); +} +/* }}} */ + +/* {{{ zend_convert_to_unicode */ +ZEND_API void zend_convert_to_unicode(UConverter *conv, UChar **target, int32_t *target_len, const char *source, int32_t source_len, UErrorCode *status) +{ + UChar *buffer = NULL; + UChar *output; + int32_t buffer_len = 0; + int32_t converted = 0; + const char *input = source; + UConverterType conv_type; + + if (U_FAILURE(*status)) { + return; + } + + ucnv_resetToUnicode(conv); + conv_type = ucnv_getType(conv); + + switch (conv_type) { + case UCNV_SBCS: + case UCNV_LATIN_1: + case UCNV_US_ASCII: + /* + * For single-byte charsets, 1 input byte = 1 output UChar + */ + buffer_len = source_len; + break; + + default: + /* + * Initial estimate: 1.25 UChar's for every 2 source bytes + 2 (past a + * certain limit (2)). The rationale behind this is that (atleast + * in the case of GB2312) it is possible that there are single byte + * characters in the input string. By using an GD2312 text as + * example it seemed that a value of 1.25 allowed for as little + * re-allocations as possible without over estimating the buffer + * too much. In case there is a lot of single-byte characters + * around a single multi-byte character this estimation is too low, + * and then the re-allocation routines in the loop below kick in. + * Here we multiply by 1.33 and add 1 so that it's even quite + * efficient for smaller input strings without causing too much + * iterations of this loop. + */ + buffer_len = (source_len > 2) ? ((source_len >> 1) + (source_len >> 3) + 2) : source_len; + break; + } + + while (1) { + buffer = eurealloc(buffer, buffer_len + 1); + output = buffer + converted; + ucnv_toUnicode(conv, &output, buffer + buffer_len, &input, source + source_len, NULL, TRUE, status); + converted = (int32_t) (output - buffer); + if (*status == U_BUFFER_OVERFLOW_ERROR) { + buffer_len = (buffer_len * 1.33) + 1; + *status = U_ZERO_ERROR; + } else { + break; + } + } + + /* + * We return the buffer in case of failure anyway. The caller may want to + * use partially converted string for something. + */ + + buffer[converted] = 0; + *target = buffer; + *target_len = converted; +} +/* }}} */ + +/* {{{ zend_convert_from_unicode */ +ZEND_API void zend_convert_from_unicode(UConverter *conv, char **target, int32_t *target_len, const UChar *source, int32_t source_len, UErrorCode *status) +{ + char *buffer = NULL; + char *output; + int32_t buffer_len = 0; + int32_t converted = 0; + const UChar *input = source; + + if (U_FAILURE(*status)) { + return; + } + + ucnv_resetFromUnicode(conv); + + buffer_len = ucnv_getMaxCharSize(conv) * source_len; + + while (1) { + buffer = erealloc(buffer, buffer_len + 1); + output = buffer + converted; + ucnv_fromUnicode(conv, &output, buffer + buffer_len, &input, source + source_len, NULL, TRUE, status); + converted = (int32_t) (output - buffer); + if (*status == U_BUFFER_OVERFLOW_ERROR) { + buffer_len += 64; + *status = U_ZERO_ERROR; + } else { + break; + } + } + + /* + * We return the buffer in case of failure anyway. The caller may want to + * use partially converted string for something. + */ + + buffer[converted] = 0; /* NULL-terminate the output string */ + *target = buffer; + *target_len = converted; + + /* Report the conversion error */ + if (U_FAILURE(*status)) { + zend_error(E_NOTICE, "Error converting from Unicode to codepage string: %s", u_errorName(*status)); + } +} +/* }}} */ + +/* {{{ zend_convert_encodings */ +ZEND_API void zend_convert_encodings(UConverter *target_conv, UConverter *source_conv, + char **target, int32_t *target_len, + const char *source, int32_t source_len, UErrorCode *status) +{ + char *buffer = NULL; + char *output; + const char *input = source; + int32_t allocated = 0; + int32_t converted = 0; + int8_t null_size; + UChar pivot_buf[1024], *pivot, *pivot2; + + if (U_FAILURE(*status)) { + return; + } + + null_size = ucnv_getMinCharSize(target_conv); + allocated = source_len + null_size; + + ucnv_resetToUnicode(source_conv); + ucnv_resetFromUnicode(target_conv); + pivot = pivot2 = pivot_buf; + + while (1) { + buffer = (char *) erealloc(buffer, allocated); + output = buffer + converted; + ucnv_convertEx(target_conv, source_conv, &output, buffer + allocated - null_size, + &input, source + source_len, pivot_buf, &pivot, &pivot2, pivot_buf + 1024, FALSE, TRUE, status); + converted = (int32_t) (output - buffer); + if (*status == U_BUFFER_OVERFLOW_ERROR) { + allocated += 1024; + *status = U_ZERO_ERROR; + } else { + break; + } + } + + memset(buffer + converted, 0, null_size); /* NULL-terminate the output string */ + *target = buffer; + *target_len = converted; + + /* Report the conversion error */ + if (U_FAILURE(*status)) { + zend_error(E_NOTICE, "Error converting from codepage string to Unicode: %s", u_errorName(*status)); + } +} +/* }}} */ + +/* {{{ zval_unicode_to_string */ +ZEND_API int zval_unicode_to_string(zval *string, UConverter *conv TSRMLS_DC) +{ + UErrorCode status = U_ZERO_ERROR; + int retval = TRUE; + char *s = NULL; + int s_len; + +#if 0 + /* UTODO Putting it here for now, until we figure out the framework */ + switch (UG(from_u_error_mode)) { + case ZEND_FROM_U_ERROR_STOP: + ucnv_setFromUCallBack(UG(runtime_encoding_conv), UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_SKIP: + ucnv_setFromUCallBack(UG(runtime_encoding_conv), UCNV_FROM_U_CALLBACK_SKIP, NULL, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_ESCAPE: + ucnv_setFromUCallBack(UG(runtime_encoding_conv), UCNV_FROM_U_CALLBACK_ESCAPE, UCNV_ESCAPE_UNICODE, NULL, NULL, &status); + break; + + case ZEND_FROM_U_ERROR_SUBST: + ucnv_setFromUCallBack(UG(runtime_encoding_conv), UCNV_FROM_U_CALLBACK_SUBSTITUTE, NULL, NULL, NULL, &status); + break; + + default: + assert(0); + break; + } + + if (UG(subst_chars)) { + char subchar[16]; + int8_t char_len = 16; + status = U_ZERO_ERROR; + ucnv_getSubstChars(UG(runtime_encoding_conv), subchar, &char_len, &status); + if (U_FAILURE(status)) { + zend_error(E_WARNING, "Could not get substitution characters"); + return FAILURE; + } + status = U_ZERO_ERROR; + ucnv_setSubstChars(UG(runtime_encoding_conv), UG(subst_chars), MIN(char_len, UG(subst_chars_len)), &status); + if (U_FAILURE(status)) { + zend_error(E_WARNING, "Could not set substitution characters"); + return FAILURE; + } + } + + status = U_ZERO_ERROR; +#endif + + UChar *u = Z_USTRVAL_P(string); + int32_t u_len = Z_USTRLEN_P(string); + + Z_TYPE_P(string) = IS_STRING; + zend_convert_from_unicode(conv, &s, &s_len, u, u_len, &status); + ZVAL_STRINGL(string, s, s_len, 0); + + if (U_FAILURE(status)) { + retval = FAILURE; + } + + efree(u); + return retval; +} +/* }}} */ + +/* {{{ zval_string_to_unicode */ +ZEND_API int zval_string_to_unicode(zval *string TSRMLS_DC) +{ + UErrorCode status = U_ZERO_ERROR; + int retval = TRUE; + UChar *u = NULL; + int32_t u_len; + + char *s = Z_STRVAL_P(string); + int s_len = Z_STRLEN_P(string); + + Z_TYPE_P(string) = IS_UNICODE; + zend_convert_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &u, &u_len, s, s_len, &status); + ZVAL_UNICODEL(string, u, u_len, 0); + + if (U_FAILURE(status)) { + retval = FALSE; + } + + efree(s); + return retval; +} +/* }}} */ + +/* {{{ zend_cmp_unicode_and_string */ +ZEND_API int zend_cmp_unicode_and_string(UChar *ustr, char* str, uint len) +{ + UErrorCode status = U_ZERO_ERROR; + UChar *u = NULL; + int32_t u_len; + int retval = TRUE; + TSRMLS_FETCH(); + + zend_convert_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &u, &u_len, str, len, &status); + if (U_FAILURE(status)) { + efree(u); + return FALSE; + } + retval = u_memcmp(ustr, u, u_len); + efree(u); + return retval; +} +/* }}} */ + +/* {{{ zend_cmp_unicode_and_literal */ +/* + * Compare a Unicode string and an ASCII literal. Because ASCII maps nicely onto Unicode + * range U+0000 .. U+007F, we can simply casst ASCII chars to Unicode values and avoid + * memory allocation. + */ +ZEND_API int zend_cmp_unicode_and_literal(UChar *ustr, int32_t ulen, char *str, int32_t slen) +{ + int32_t result; + uint len = MIN(ulen, slen); + + while (len--) { + result = (int32_t)(uint16_t)*ustr - (int32_t)(uint16_t)*str; + if (result != 0) + return result; + ustr++; + str++; + } + + return ulen - slen; +} +/* }}} */ + +/* {{{ zend_is_valid_identifier */ +ZEND_API int zend_is_valid_identifier(UChar *ident, int32_t ident_len) +{ + UChar32 codepoint; + int32_t i; + UProperty id_prop = UCHAR_XID_START; + + for (i = 0; i < ident_len; ) { + U16_NEXT(ident, i, ident_len, codepoint); + if (!u_hasBinaryProperty(codepoint, id_prop) && + codepoint != 0x5f) { /* special case for starting '_' */ + return 0; + } + id_prop = UCHAR_XID_CONTINUE; + } + + return 1; +} +/* }}} */ + +/* {{{ zend_normalize_string */ +static inline void zend_normalize_string(UChar **dest, int32_t *dest_len, UChar *src, int32_t src_len, UErrorCode *status) +{ + UChar *buffer = NULL; + int32_t buffer_len; + + buffer_len = src_len; + while (1) { + *status = U_ZERO_ERROR; + buffer = eurealloc(buffer, buffer_len+1); + buffer_len = unorm_normalize(src, src_len, UNORM_NFKC, 0, buffer, buffer_len, status); + if (*status != U_BUFFER_OVERFLOW_ERROR) { + break; + } + } + if (U_SUCCESS(*status)) { + buffer[buffer_len] = 0; + *dest = buffer; + *dest_len = buffer_len; + } else { + efree(buffer); + } +} +/* }}} */ + +/* {{{ zend_case_fold_string */ +ZEND_API void zend_case_fold_string(UChar **dest, int32_t *dest_len, UChar *src, int32_t src_len, uint32_t options, UErrorCode *status) +{ + UChar *buffer = NULL; + int32_t buffer_len; + + buffer_len = src_len; + while (1) { + *status = U_ZERO_ERROR; + buffer = eurealloc(buffer, buffer_len+1); + buffer_len = u_strFoldCase(buffer, buffer_len, src, src_len, options, status); + if (*status != U_BUFFER_OVERFLOW_ERROR) { + break; + } + } + if (U_SUCCESS(*status)) { + buffer[buffer_len] = 0; + *dest = buffer; + *dest_len = buffer_len; + } else { + efree(buffer); + } +} +/* }}} */ + +/* {{{ zend_normalize_identifier */ +ZEND_API int zend_normalize_identifier(UChar **dest, int32_t *dest_len, UChar *ident, int32_t ident_len, zend_bool fold_case) +{ + UChar *buffer = NULL; + UChar *orig_ident = ident; + int32_t buffer_len; + UErrorCode status = U_ZERO_ERROR; + + if (unorm_quickCheck(ident, ident_len, UNORM_NFKC, &status) != UNORM_YES) { + zend_normalize_string(&buffer, &buffer_len, ident, ident_len, &status); + if (U_FAILURE(status)) { + return 0; + } + ident = buffer; + ident_len = buffer_len; + } + + if (fold_case) { + zend_case_fold_string(&buffer, &buffer_len, ident, ident_len, U_FOLD_CASE_DEFAULT, &status); + if (ident != orig_ident) { + efree(ident); + } + if (U_FAILURE(status)) { + return 0; + } + ident = buffer; + ident_len = buffer_len; + + if (unorm_quickCheck(ident, ident_len, UNORM_NFKC, &status) != UNORM_YES) { + zend_normalize_string(&buffer, &buffer_len, ident, ident_len, &status); + if (ident != orig_ident) { + efree(ident); + } + if (U_FAILURE(status)) { + return 0; + } + ident = buffer; + ident_len = buffer_len; + } + } + + *dest = ident; + *dest_len = ident_len; + return 1; +} +/* }}} */ + +/* vim: set fdm=marker et sts=4: */ diff --git a/Zend/zend_unicode.h b/Zend/zend_unicode.h new file mode 100644 index 0000000000..950dc7c1fd --- /dev/null +++ b/Zend/zend_unicode.h @@ -0,0 +1,90 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2004 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andrei Zmievski | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_UNICODE_H +#define ZEND_UNICODE_H + +#include "zend.h" +#include +#include +#include +#include +#include +#include +#include + +#define ZEND_FROM_U_ERROR_STOP 0 +#define ZEND_FROM_U_ERROR_SKIP 1 +#define ZEND_FROM_U_ERROR_SUBST 2 +#define ZEND_FROM_U_ERROR_ESCAPE 3 + +/* internal functions */ + +int zend_set_converter_encoding(UConverter **converter, const char *encoding); +void zend_set_converter_subst_char(UConverter *conv, UChar *subst_char, int8_t subst_char_len); +void zend_set_converter_error_mode(UConverter *conv, uint8_t error_mode); + + +/* API functions */ + +ZEND_API void zend_convert_to_unicode(UConverter *conv, UChar **target, int32_t *target_len, const char *source, int32_t source_len, UErrorCode *status); +ZEND_API void zend_convert_from_unicode(UConverter *conv, char **target, int32_t *target_len, const UChar *source, int32_t source_len, UErrorCode *status); +ZEND_API void zend_convert_encodings(UConverter *target_conv, UConverter *source_conv, char **target, int32_t *target_len, const char *source, int32_t source_len, UErrorCode *status); +ZEND_API int zval_string_to_unicode(zval *string TSRMLS_DC); +ZEND_API int zval_unicode_to_string(zval *string, UConverter *conv TSRMLS_DC); + +ZEND_API int zend_cmp_unicode_and_string(UChar *ustr, char* str, uint len); +ZEND_API int zend_cmp_unicode_and_literal(UChar *ustr, int32_t ulen, char* str, int32_t slen); + +ZEND_API void zend_case_fold_string(UChar **dest, int32_t *dest_len, UChar *src, int32_t src_len, uint32_t options, UErrorCode *status); + +ZEND_API int zend_is_valid_identifier(UChar *ident, int32_t ident_len); +ZEND_API int zend_normalize_identifier(UChar **dest, int32_t *dest_len, UChar *ident, int32_t ident_len, zend_bool fold_case); + +/* + * Function to get a codepoint at position n. Iterates over codepoints starting from the + * beginning of the string. Does not check for n > length, this is left up to the caller. + */ +static inline UChar32 zend_get_codepoint_at(UChar *str, int32_t length, int32_t n) +{ + int32_t offset = 0; + UChar32 c = 0; + + U16_FWD_N(str, offset, length, n); + U16_GET(str, 0, offset, length, c); + + return c; +} + +#define ZEND_U_CONVERTER(c) ((c)?(c):UG(fallback_encoding_conv)) + +#define USTR_FREE(ustr) do { if (ustr) { efree(ustr); } } while (0); +#define UBYTES(len) ((len) * sizeof(UChar)) +#define USTR_LEN(str) (UG(unicode)?u_strlen((UChar*)(str)):strlen((char*)(str))) + +#define USTR_MAKE(cs) zend_ascii_to_unicode(cs, sizeof(cs) ZEND_FILE_LINE_CC) +#define USTR_MAKE_REL(cs) zend_ascii_to_unicode(cs, sizeof(cs) ZEND_FILE_LINE_RELAY_CC) +static inline UChar* zend_ascii_to_unicode(const char *cs, size_t cs_size ZEND_FILE_LINE_DC) +{ + /* u_charsToUChars() takes care of the terminating NULL */ + UChar *us = eumalloc_rel(cs_size); + u_charsToUChars(cs, us, cs_size); + return us; +} + +#endif /* ZEND_UNICODE_H */ diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 3bedc0a4ad..7d5b208ca1 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -30,11 +30,21 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) { switch (zvalue->type & ~IS_CONSTANT_INDEX) { + case IS_CONSTANT: { + TSRMLS_FETCH(); + + if (UG(unicode)) goto dtor_unicode; + } case IS_STRING: - case IS_CONSTANT: + case IS_BINARY: CHECK_ZVAL_STRING_REL(zvalue); STR_FREE_REL(zvalue->value.str.val); break; + case IS_UNICODE: +dtor_unicode: + CHECK_ZVAL_UNICODE_REL(zvalue); + STR_FREE_REL(zvalue->value.ustr.val); + break; case IS_ARRAY: case IS_CONSTANT_ARRAY: { TSRMLS_FETCH(); @@ -74,11 +84,21 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) { switch (zvalue->type & ~IS_CONSTANT_INDEX) { + case IS_CONSTANT: { + TSRMLS_FETCH(); + + if (UG(unicode)) goto dtor_unicode; + } case IS_STRING: - case IS_CONSTANT: + case IS_BINARY: CHECK_ZVAL_STRING_REL(zvalue); free(zvalue->value.str.val); break; + case IS_UNICODE: +dtor_unicode: + CHECK_ZVAL_UNICODE_REL(zvalue); + free(zvalue->value.ustr.val); + break; case IS_ARRAY: case IS_CONSTANT_ARRAY: case IS_OBJECT: @@ -114,11 +134,21 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) case IS_LONG: case IS_NULL: break; - case IS_CONSTANT: + case IS_CONSTANT: { + TSRMLS_FETCH(); + + if (UG(unicode)) goto copy_unicode; + } case IS_STRING: + case IS_BINARY: CHECK_ZVAL_STRING_REL(zvalue); zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len); break; + case IS_UNICODE: +copy_unicode: + CHECK_ZVAL_UNICODE_REL(zvalue); + zvalue->value.ustr.val = eustrndup_rel(zvalue->value.ustr.val, zvalue->value.ustr.len); + break; case IS_ARRAY: case IS_CONSTANT_ARRAY: { zval *tmp; @@ -130,7 +160,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) return; /* do nothing */ } ALLOC_HASHTABLE_REL(tmp_ht); - zend_hash_init(tmp_ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(tmp_ht, 0, NULL, ZVAL_PTR_DTOR, 0, original_ht->unicode); zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); zvalue->value.ht = tmp_ht; } @@ -144,7 +174,6 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) } } - ZEND_API int zend_print_variable(zval *var) { return zend_print_zval(var, 0); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b96d1a1e7f..52bfccf37d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -886,11 +886,27 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY) zval *z = GET_OP1_ZVAL_PTR(BP_VAR_R); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } FREE_OP1(); @@ -932,23 +948,23 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, ANY, int type ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -956,6 +972,10 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, ANY, int type } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (OP1_TYPE != IS_TMP_VAR) { + FREE_OP1(); + } + break; case ZEND_FETCH_LOCAL: FREE_OP1(); break; @@ -1519,11 +1539,18 @@ ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY) { zval *tmp = &EX_T(EX(opline)->result.u.var).tmp_var; - tmp->value.str.val = emalloc(1); - tmp->value.str.val[0] = 0; - tmp->value.str.len = 0; + if (EX(opline)->extended_value == IS_UNICODE) { + tmp->value.ustr.val = eumalloc(1); + tmp->value.ustr.val[0] = 0; + tmp->value.ustr.len = 0; + tmp->type = IS_UNICODE; + } else { + tmp->value.str.val = emalloc(1); + tmp->value.str.val[0] = 0; + tmp->value.str.len = 0; + tmp->type = EX(opline)->extended_value; + } tmp->refcount = 1; - tmp->type = IS_STRING; tmp->is_ref = 0; ZEND_VM_NEXT_OPCODE(); } @@ -1534,8 +1561,8 @@ ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP, CONST) zend_free_op free_op1; add_char_to_string(&EX_T(opline->result.u.var).tmp_var, - GET_OP1_ZVAL_PTR(BP_VAR_NA), - &opline->op2.u.constant); + GET_OP1_ZVAL_PTR(BP_VAR_NA), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -1546,8 +1573,8 @@ ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP, CONST) zend_free_op free_op1; add_string_to_string(&EX_T(opline->result.u.var).tmp_var, - GET_OP1_ZVAL_PTR(BP_VAR_NA), - &opline->op2.u.constant); + GET_OP1_ZVAL_PTR(BP_VAR_NA), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -1560,13 +1587,16 @@ ZEND_VM_HANDLER(56, ZEND_ADD_VAR, TMP, TMP|VAR|CV) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - GET_OP1_ZVAL_PTR(BP_VAR_NA), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + GET_OP1_ZVAL_PTR(BP_VAR_NA), var); if (use_copy) { zval_dtor(var); } @@ -1600,7 +1630,8 @@ ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -1618,17 +1649,19 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -1642,10 +1675,10 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -1685,21 +1718,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, ANY, CONST|TMP|VAR|UNUSED|CV) ce = EX_T(opline->op1.u.var).class_entry; if(OP2_TYPE != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (OP2_TYPE == IS_CONST); zend_free_op free_op2; if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1733,29 +1765,28 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (OP2_TYPE == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -1782,7 +1813,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) zend_bool should_change_scope; if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -1814,7 +1846,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) severity = E_ERROR; severity_word = "cannot"; } - zend_error(severity, "Non-static method %s::%s() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); + /* FIXME: output identifiers properly */ + zend_error(severity, "Non-static method %v::%v() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); } } if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { @@ -1862,7 +1895,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--); } else { ALLOC_HASHTABLE(EX(function_state).function_symbol_table); - zend_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ } calling_symbol_table = EG(active_symbol_table); @@ -1968,8 +2001,9 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); - if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { - zend_error_noreturn(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Unknown function: %R()\n", Z_TYPE_P(fname), Z_UNIVAL_P(fname)); } EX(object) = NULL; EX(calling_scope) = EX(function_state).function->common.scope; @@ -2031,9 +2065,9 @@ ZEND_VM_C_LABEL(return_by_value): INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -2110,8 +2144,8 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, ANY, ANY) } } - zend_hash_update(EG(active_symbol_table), opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.len+1, &EG(exception), sizeof(zval *), (void **) NULL); + zend_u_hash_update(EG(active_symbol_table), Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), + Z_UNILEN(opline->op2.u.constant)+1, &EG(exception), sizeof(zval *), (void **) NULL); EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); } @@ -2243,9 +2277,9 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC); if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); } if (opline->result.op_type == IS_VAR) { PZVAL_UNLOCK_FREE(*EX_T(opline->result.u.var).var.ptr_ptr); @@ -2400,7 +2434,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) } else { class_type = "abstract class"; } - zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); + zend_error_noreturn(E_ERROR, "Cannot instantiate %s %v", class_type, EX_T(opline->op1.u.var).class_entry->name); } ALLOC_ZVAL(object_zval); object_init_ex(object_zval, EX_T(opline->op1.u.var).class_entry); @@ -2458,7 +2492,7 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -2468,13 +2502,13 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -2511,10 +2545,12 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, CONST|UNUSED, CONST) } } */ - if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + if (!zend_get_constant(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } @@ -2523,12 +2559,12 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, CONST|UNUSED, CONST) ce = EX_T(opline->op1.u.var).class_entry; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { zval_update_constant(value, (void *) 1 TSRMLS_CC); EX_T(opline->result.u.var).tmp_var = **value; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", opline->op2.u.constant.value.str.val); + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } ZEND_VM_NEXT_OPCODE(); @@ -2587,7 +2623,9 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|V zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -2643,13 +2681,27 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -2672,7 +2724,14 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -2789,10 +2848,10 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, ANY) varname = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -2800,17 +2859,17 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, ANY) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = EXECUTE_DATA; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -2857,10 +2916,31 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = EXECUTE_DATA; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -2868,8 +2948,8 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -2877,7 +2957,11 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -3008,7 +3092,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) FREE_OP1_IF_VAR(); } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -3043,8 +3127,11 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -3106,11 +3193,16 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); zend_hash_move_forward(fe_ht); - } while (key_type != HASH_KEY_IS_STRING || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); + } while (key_type == HASH_KEY_NON_EXISTANT || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); if (use_key) { - zend_unmangle_property_name(str_key, &class_name, &prop_name); - str_key_len = strlen(prop_name); - str_key = estrndup(prop_name, str_key_len); + zend_u_unmangle_property_name(key_type == HASH_KEY_IS_UNICODE?IS_UNICODE:IS_STRING, str_key, &class_name, &prop_name); + if (key_type == HASH_KEY_IS_UNICODE) { + str_key_len = u_strlen((UChar*)prop_name); + str_key = (char*)eustrndup((UChar*)prop_name, str_key_len); + } else { + str_key_len = strlen(prop_name); + str_key = estrndup(prop_name, str_key_len); + } str_key_len++; } break; @@ -3200,6 +3292,16 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) key->value.str.len = str_key_len-1; key->type = IS_STRING; break; + case HASH_KEY_IS_BINARY: + key->value.str.val = str_key; + key->value.str.len = str_key_len-1; + key->type = IS_BINARY; + break; + case HASH_KEY_IS_UNICODE: + key->value.ustr.val = (UChar*)str_key; + key->value.ustr.len = str_key_len-1; + key->type = IS_UNICODE; + break; case HASH_KEY_IS_LONG: key->value.lval = int_key; key->type = IS_LONG; @@ -3221,10 +3323,10 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, ANY) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -3235,7 +3337,7 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, ANY) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -3301,10 +3403,34 @@ ZEND_VM_HELPER_EX(zend_isset_isempty_dim_prop_obj_handler, VAR|UNUSED|CV, CONST| } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -3347,7 +3473,9 @@ ZEND_VM_HELPER_EX(zend_isset_isempty_dim_prop_obj_handler, VAR|UNUSED|CV, CONST| } else { FREE_OP2(); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -3359,12 +3487,17 @@ ZEND_VM_HELPER_EX(zend_isset_isempty_dim_prop_obj_handler, VAR|UNUSED|CV, CONST| if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -3432,7 +3565,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name, EX(op_array)->function_name); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EG(scope)->name, EX(op_array)->function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -3558,7 +3691,7 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, ANY) zend_class_entry *iface = EX_T(opline->op2.u.var).class_entry; if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) { - zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); + zend_error_noreturn(E_ERROR, "%v cannot implement %v - it is not an interface", ce->name, iface->name); } ce->interfaces[opline->extended_value] = iface; @@ -3631,4 +3764,39 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) } } +ZEND_VM_HANDLER(151, ZEND_U_NORMALIZE, CONST|TMP|VAR|CV, ANY) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *string = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!IS_OP1_TMP_FREE()) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + FREE_OP1_IF_VAR(); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c60cef5c88..4328aac4ce 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -108,11 +108,18 @@ static int ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zval *tmp = &EX_T(EX(opline)->result.u.var).tmp_var; - tmp->value.str.val = emalloc(1); - tmp->value.str.val[0] = 0; - tmp->value.str.len = 0; + if (EX(opline)->extended_value == IS_UNICODE) { + tmp->value.ustr.val = eumalloc(1); + tmp->value.ustr.val[0] = 0; + tmp->value.ustr.len = 0; + tmp->type = IS_UNICODE; + } else { + tmp->value.str.val = emalloc(1); + tmp->value.str.val[0] = 0; + tmp->value.str.len = 0; + tmp->type = EX(opline)->extended_value; + } tmp->refcount = 1; - tmp->type = IS_STRING; tmp->is_ref = 0; ZEND_VM_NEXT_OPCODE(); } @@ -127,7 +134,8 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_bool should_change_scope; if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -159,7 +167,8 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) severity = E_ERROR; severity_word = "cannot"; } - zend_error(severity, "Non-static method %s::%s() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); + /* FIXME: output identifiers properly */ + zend_error(severity, "Non-static method %v::%v() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); } } if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { @@ -207,7 +216,7 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--); } else { ALLOC_HASHTABLE(EX(function_state).function_symbol_table); - zend_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ } calling_symbol_table = EG(active_symbol_table); @@ -327,8 +336,8 @@ static int ZEND_CATCH_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } - zend_hash_update(EG(active_symbol_table), opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.len+1, &EG(exception), sizeof(zval *), (void **) NULL); + zend_u_hash_update(EG(active_symbol_table), Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), + Z_UNILEN(opline->op2.u.constant)+1, &EG(exception), sizeof(zval *), (void **) NULL); EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); } @@ -346,9 +355,9 @@ static int ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC); if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); } if (opline->result.op_type == IS_VAR) { PZVAL_UNLOCK_FREE(*EX_T(opline->result.u.var).var.ptr_ptr); @@ -383,7 +392,7 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { class_type = "abstract class"; } - zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); + zend_error_noreturn(E_ERROR, "Cannot instantiate %s %v", class_type, EX_T(opline->op1.u.var).class_entry->name); } ALLOC_ZVAL(object_zval); object_init_ex(object_zval, EX_T(opline->op1.u.var).class_entry); @@ -432,7 +441,7 @@ static int ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name, EX(op_array)->function_name); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EG(scope)->name, EX(op_array)->function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -499,7 +508,7 @@ static int ZEND_ADD_INTERFACE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *iface = EX_T(opline->op2.u.var).class_entry; if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) { - zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); + zend_error_noreturn(E_ERROR, "%v cannot implement %v - it is not an interface", ce->name, iface->name); } ce->interfaces[opline->extended_value] = iface; @@ -591,7 +600,8 @@ static int ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -612,21 +622,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ce = EX_T(opline->op1.u.var).class_entry; if(IS_CONST != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_CONST == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -660,29 +669,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_CONST == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -787,7 +795,8 @@ static int ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -809,21 +818,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; if(IS_TMP_VAR != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_TMP_VAR == IS_CONST); zend_free_op free_op2; if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -857,29 +865,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_TMP_VAR == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -941,7 +948,8 @@ static int ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -963,21 +971,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; if(IS_VAR != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_VAR == IS_CONST); zend_free_op free_op2; if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1011,29 +1018,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_VAR == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -1095,7 +1101,8 @@ static int ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -1116,21 +1123,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ce = EX_T(opline->op1.u.var).class_entry; if(IS_UNUSED != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_UNUSED == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = NULL; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1178,7 +1184,8 @@ static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -1199,21 +1206,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ce = EX_T(opline->op1.u.var).class_entry; if(IS_CV != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_CV == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1247,29 +1253,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_CV == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -1342,11 +1347,27 @@ static int ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = &opline->op1.u.constant; if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } ZEND_VM_NEXT_OPCODE(); @@ -1387,23 +1408,23 @@ static int zend_fetch_var_address_helper_SPEC_CONST(int type, ZEND_OPCODE_HANDLE ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -1411,6 +1432,10 @@ static int zend_fetch_var_address_helper_SPEC_CONST(int type, ZEND_OPCODE_HANDLE } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_CONST != IS_TMP_VAR) { + + } + break; case ZEND_FETCH_LOCAL: break; @@ -1577,8 +1602,9 @@ static int ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); - if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { - zend_error_noreturn(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Unknown function: %R()\n", Z_TYPE_P(fname), Z_UNIVAL_P(fname)); } EX(object) = NULL; EX(calling_scope) = EX(function_state).function->common.scope; @@ -1638,9 +1664,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -1753,7 +1779,7 @@ static int ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -1763,13 +1789,13 @@ static int ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -1816,13 +1842,27 @@ static int ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -1845,7 +1885,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -1962,10 +2009,10 @@ static int ZEND_UNSET_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = &opline->op1.u.constant; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -1973,17 +2020,17 @@ static int ZEND_UNSET_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -2059,7 +2106,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -2094,8 +2141,11 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -2129,10 +2179,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -2143,7 +2193,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -2219,6 +2269,41 @@ static int ZEND_TICKS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *string = &opline->op1.u.constant; + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -2502,10 +2587,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS } } */ - if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + if (!zend_get_constant(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } @@ -2514,12 +2601,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS ce = EX_T(opline->op1.u.var).class_entry; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { zval_update_constant(value, (void *) 1 TSRMLS_CC); EX_T(opline->result.u.var).tmp_var = **value; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", opline->op2.u.constant.value.str.val); + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } ZEND_VM_NEXT_OPCODE(); @@ -2578,7 +2665,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_A zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -2925,7 +3014,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3272,7 +3363,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3353,7 +3446,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3699,7 +3794,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3757,11 +3854,27 @@ static int ZEND_ECHO_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } zval_dtor(free_op1.var); @@ -3803,23 +3916,23 @@ static int zend_fetch_var_address_helper_SPEC_TMP(int type, ZEND_OPCODE_HANDLER_ ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -3827,6 +3940,10 @@ static int zend_fetch_var_address_helper_SPEC_TMP(int type, ZEND_OPCODE_HANDLER_ } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_TMP_VAR != IS_TMP_VAR) { + zval_dtor(free_op1.var); + } + break; case ZEND_FETCH_LOCAL: zval_dtor(free_op1.var); break; @@ -4048,9 +4165,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -4170,7 +4287,7 @@ static int ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -4180,13 +4297,13 @@ static int ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -4233,13 +4350,27 @@ static int ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -4262,7 +4393,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -4379,10 +4517,10 @@ static int ZEND_UNSET_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -4390,17 +4528,17 @@ static int ZEND_UNSET_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -4476,7 +4614,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -4511,8 +4649,11 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -4546,10 +4687,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -4560,7 +4701,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -4656,6 +4797,41 @@ static int ZEND_INSTANCEOF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *string = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!1) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -4919,8 +5095,8 @@ static int ZEND_ADD_CHAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; add_char_to_string(&EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - &opline->op2.u.constant); + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -4931,8 +5107,8 @@ static int ZEND_ADD_STRING_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; add_string_to_string(&EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - &opline->op2.u.constant); + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -4944,17 +5120,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -4968,10 +5146,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5082,7 +5260,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -5352,13 +5532,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -5380,17 +5563,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -5404,10 +5589,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5520,7 +5705,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -5790,13 +5977,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -5818,17 +6008,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -5842,10 +6034,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5958,7 +6150,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6039,7 +6233,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6309,13 +6505,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -6336,17 +6535,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -6360,10 +6561,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -6474,7 +6675,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6694,11 +6897,27 @@ static int ZEND_ECHO_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -6740,23 +6959,23 @@ static int zend_fetch_var_address_helper_SPEC_VAR(int type, ZEND_OPCODE_HANDLER_ ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -6764,6 +6983,10 @@ static int zend_fetch_var_address_helper_SPEC_VAR(int type, ZEND_OPCODE_HANDLER_ } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_VAR != IS_TMP_VAR) { + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + } + break; case ZEND_FETCH_LOCAL: if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; break; @@ -6979,9 +7202,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -7190,7 +7413,7 @@ static int ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -7200,13 +7423,13 @@ static int ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -7253,13 +7476,27 @@ static int ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -7282,7 +7519,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -7399,10 +7643,10 @@ static int ZEND_UNSET_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -7410,17 +7654,17 @@ static int ZEND_UNSET_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -7496,7 +7740,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -7531,8 +7775,11 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -7594,11 +7841,16 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); zend_hash_move_forward(fe_ht); - } while (key_type != HASH_KEY_IS_STRING || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); + } while (key_type == HASH_KEY_NON_EXISTANT || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); if (use_key) { - zend_unmangle_property_name(str_key, &class_name, &prop_name); - str_key_len = strlen(prop_name); - str_key = estrndup(prop_name, str_key_len); + zend_u_unmangle_property_name(key_type == HASH_KEY_IS_UNICODE?IS_UNICODE:IS_STRING, str_key, &class_name, &prop_name); + if (key_type == HASH_KEY_IS_UNICODE) { + str_key_len = u_strlen((UChar*)prop_name); + str_key = (char*)eustrndup((UChar*)prop_name, str_key_len); + } else { + str_key_len = strlen(prop_name); + str_key = estrndup(prop_name, str_key_len); + } str_key_len++; } break; @@ -7688,6 +7940,16 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) key->value.str.len = str_key_len-1; key->type = IS_STRING; break; + case HASH_KEY_IS_BINARY: + key->value.str.val = str_key; + key->value.str.len = str_key_len-1; + key->type = IS_BINARY; + break; + case HASH_KEY_IS_UNICODE: + key->value.ustr.val = (UChar*)str_key; + key->value.ustr.len = str_key_len-1; + key->type = IS_UNICODE; + break; case HASH_KEY_IS_LONG: key->value.lval = int_key; key->type = IS_LONG; @@ -7709,10 +7971,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -7723,7 +7985,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -7804,6 +8066,41 @@ static int ZEND_INSTANCEOF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *string = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -8799,17 +9096,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -8823,10 +9122,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -8938,7 +9237,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -8996,10 +9297,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -9007,8 +9329,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -9016,7 +9338,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -9122,10 +9448,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -9168,7 +9518,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -9180,12 +9532,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -10220,17 +10577,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -10244,10 +10603,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -10361,7 +10720,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -10419,10 +10780,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -10430,8 +10812,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -10439,7 +10821,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -10545,10 +10931,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -10591,7 +11001,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -10603,12 +11015,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -11681,17 +12098,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -11705,10 +12124,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -11822,7 +12241,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -11880,10 +12301,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -11891,8 +12333,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -11900,7 +12342,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -12006,10 +12452,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -12052,7 +12522,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -12064,12 +12536,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -12487,7 +12964,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -13546,17 +14025,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -13570,10 +14051,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -13685,7 +14166,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -13743,10 +14226,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -13754,8 +14258,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -13763,7 +14267,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -13869,10 +14377,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -13915,7 +14447,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -13927,12 +14461,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -13991,7 +14530,7 @@ static int ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -14001,13 +14540,13 @@ static int ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -14693,17 +15232,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -14717,10 +15258,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -14765,10 +15306,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG } } */ - if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + if (!zend_get_constant(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } @@ -14777,12 +15320,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { zval_update_constant(value, (void *) 1 TSRMLS_CC); EX_T(opline->result.u.var).tmp_var = **value; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", opline->op2.u.constant.value.str.val); + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } ZEND_VM_NEXT_OPCODE(); @@ -14841,7 +15384,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -14899,10 +15444,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -14910,8 +15476,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -14919,7 +15485,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -15023,10 +15593,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -15069,7 +15663,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -15081,12 +15677,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -15773,17 +16374,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -15797,10 +16400,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -15881,7 +16484,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -15939,10 +16544,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -15950,8 +16576,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -15959,7 +16585,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -16063,10 +16693,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -16109,7 +16763,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -16121,12 +16777,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -16813,17 +17474,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -16837,10 +17500,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -16921,7 +17584,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -16979,10 +17644,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -16990,8 +17676,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -16999,7 +17685,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -17103,10 +17793,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -17149,7 +17863,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -17161,12 +17877,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -17540,7 +18261,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -18217,17 +18940,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -18241,10 +18966,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -18324,7 +19049,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -18382,10 +19109,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -18393,8 +19141,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -18402,7 +19150,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -18506,10 +19258,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -18552,7 +19328,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -18564,12 +19342,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -18793,11 +19576,27 @@ static int ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } ZEND_VM_NEXT_OPCODE(); @@ -18838,23 +19637,23 @@ static int zend_fetch_var_address_helper_SPEC_CV(int type, ZEND_OPCODE_HANDLER_A ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -18862,6 +19661,10 @@ static int zend_fetch_var_address_helper_SPEC_CV(int type, ZEND_OPCODE_HANDLER_A } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_CV != IS_TMP_VAR) { + + } + break; case ZEND_FETCH_LOCAL: break; @@ -19072,9 +19875,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -19275,7 +20078,7 @@ static int ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -19285,13 +20088,13 @@ static int ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -19338,13 +20141,27 @@ static int ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -19367,7 +20184,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -19484,10 +20308,10 @@ static int ZEND_UNSET_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -19495,17 +20319,17 @@ static int ZEND_UNSET_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -19581,7 +20405,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -19616,8 +20440,11 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -19651,10 +20478,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -19665,7 +20492,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -19745,6 +20572,41 @@ static int ZEND_INSTANCEOF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *string = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -20737,17 +21599,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -20761,10 +21625,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -20875,7 +21739,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -20933,10 +21799,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -20944,8 +21831,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -20953,7 +21840,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -21057,10 +21948,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -21103,7 +22018,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -21115,12 +22032,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -22150,17 +23072,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -22174,10 +23098,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -22290,7 +23214,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -22348,10 +23274,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -22359,8 +23306,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -22368,7 +23315,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -22472,10 +23423,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -22518,7 +23493,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -22530,12 +23507,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -23602,17 +24584,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -23626,10 +24610,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -23742,7 +24726,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -23800,10 +24786,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -23811,8 +24818,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -23820,7 +24827,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -23924,10 +24935,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -23970,7 +25005,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -23982,12 +25019,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -24402,7 +25444,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -25457,17 +26501,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -25481,10 +26527,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -25595,7 +26641,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -25653,10 +26701,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -25664,8 +26733,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -25673,7 +26742,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -25777,10 +26850,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -25823,7 +26920,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -25835,12 +26934,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -29661,6 +30765,31 @@ void zend_init_opcodes_handlers() ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 235735d983..c30eed096e 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1058,7 +1058,7 @@ function gen_vm($def, $skel) { fputs($f,"#define $op $code\n"); } fclose($f); - echo "zend_vm_opcodes.h generated succesfull.\n"; + echo "zend_vm_opcodes.h generated succesfully.\n"; // Generate zend_vm_execute.h $f = fopen("zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n"); @@ -1198,7 +1198,7 @@ function gen_vm($def, $skel) { } fclose($f); - echo "zend_vm_execute.h generated succesfull.\n"; + echo "zend_vm_execute.h generated succesfully.\n"; } function usage() { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 319b5483ea..b10683c584 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -147,3 +147,4 @@ #define ZEND_ISSET_ISEMPTY_PROP_OBJ 148 #define ZEND_HANDLE_EXCEPTION 149 #define ZEND_USER_OPCODE 150 +#define ZEND_U_NORMALIZE 151 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 2bbd91bc98..fa001dc9b9 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -43,7 +43,7 @@ zend_class_entry *reflection_extension_ptr; /* Method macros */ #define METHOD_NOTSTATIC \ if (!this_ptr) { \ - zend_error(E_ERROR, "%s() cannot be called statically", get_active_function_name(TSRMLS_C)); \ + zend_error(E_ERROR, "%v() cannot be called statically", get_active_function_name(TSRMLS_C)); \ return; \ } \ @@ -233,7 +233,7 @@ static zend_object_value reflection_objects_new(zend_class_entry *class_type TSR intern->free_ptr = 0; ALLOC_HASHTABLE(intern->zo.properties); - zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, reflection_objects_clone TSRMLS_CC); retval.handlers = &reflection_object_handlers; @@ -297,17 +297,17 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in } string_printf(str, "class "); } - string_write(str, ce->name, ce->name_length); + string_printf(str, "%v", ce->name); if (ce->parent) { - string_printf(str, " extends %s", ce->parent->name); + string_printf(str, " extends %v", ce->parent->name); } if (ce->num_interfaces) { zend_uint i; - string_printf(str, " implements %s", ce->interfaces[0]->name); + string_printf(str, " implements %v", ce->interfaces[0]->name); for (i = 1; i < ce->num_interfaces; ++i) { - string_printf(str, ", %s", ce->interfaces[i]->name); + string_printf(str, ", %v", ce->interfaces[i]->name); } } string_printf(str, " ] {\n"); @@ -540,7 +540,7 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_printf(str, " "); } if (arg_info->class_name) { - string_printf(str, "%s ", arg_info->class_name); + string_printf(str, "%v ", arg_info->class_name); if (arg_info->allow_null) { string_printf(str, "or NULL "); } @@ -554,7 +554,7 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_write(str, "&", sizeof("&")-1); } if (arg_info->name) { - string_printf(str, "$%s", arg_info->name); + string_printf(str, "$%v", arg_info->name); } else { string_printf(str, "$param%d", offset); } @@ -671,7 +671,7 @@ static void _function_string(string *str, zend_function *fptr, char* indent TSRM if (fptr->op_array.return_reference) { string_printf(str, "&"); } - string_printf(str, "%s ] {\n", fptr->common.function_name); + string_printf(str, "%v ] {\n", fptr->common.function_name); /* The information where a function is declared is only available for user classes */ if (fptr->type == ZEND_USER_FUNCTION) { string_printf(str, "%s @@ %s %d - %d\n", indent, @@ -720,8 +720,8 @@ static void _property_string(string *str, zend_property_info *prop, char *prop_n string_printf(str, "static "); } - zend_unmangle_property_name(prop->name, &class_name, &prop_name); - string_printf(str, "$%s", prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, prop->name, &class_name, &prop_name); + string_printf(str, "$%v", prop_name); } string_printf(str, " ]\n"); @@ -865,7 +865,11 @@ ZEND_API void zend_reflection_class_factory(zend_class_entry *ce, zval *object T zval *name; MAKE_STD_ZVAL(name); - ZVAL_STRINGL(name, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(name, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_class_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = ce; @@ -912,7 +916,11 @@ static void reflection_parameter_factory(zend_function *fptr, struct _zend_arg_i MAKE_STD_ZVAL(name); if (arg_info->name) { - ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)arg_info->name, arg_info->name_len, 1); + } else { + ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1); + } } else { ZVAL_NULL(name); } @@ -937,7 +945,11 @@ static void reflection_function_factory(zend_function *function, zval *object TS zval *name; MAKE_STD_ZVAL(name); - ZVAL_STRING(name, function->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)function->common.function_name, 1); + } else { + ZVAL_STRING(name, function->common.function_name, 1); + } reflection_instanciate(reflection_function_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -956,9 +968,14 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho zval *classname; MAKE_STD_ZVAL(name); - ZVAL_STRING(name, method->common.function_name, 1); MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)method->common.function_name, 1); + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRING(name, method->common.function_name, 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_method_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = method; @@ -978,7 +995,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info property_reference *reference; char *class_name, *prop_name; - zend_unmangle_property_name(prop->name, &class_name, &prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, prop->name, &class_name, &prop_name); if (!(prop->flags & ZEND_ACC_PRIVATE)) { /* we have to seach the class hierarchy for this (implicit) public or protected property */ @@ -997,10 +1014,14 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info } MAKE_STD_ZVAL(name); - ZVAL_STRING(name, prop_name, 1); - MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)prop_name, 1); + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRING(name, prop_name, 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } reflection_instanciate(reflection_property_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -1144,7 +1165,7 @@ ZEND_METHOD(reflection, export) } if (!retval_ptr) { - zend_error(E_WARNING, "%s::__toString() did not return anything", Z_OBJCE_P(object)->name); + zend_error(E_WARNING, "%v::__toString() did not return anything", Z_OBJCE_P(object)->name); RETURN_FALSE; } @@ -1211,13 +1232,15 @@ ZEND_METHOD(reflection_function, __construct) { zval *name; zval *object; + unsigned int lcname_len; char *lcname; reflection_object *intern; zend_function *fptr; char *name_str; int name_len; + zend_uchar type; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name_str, &name_len, &type) == FAILURE) { return; } @@ -1226,17 +1249,20 @@ ZEND_METHOD(reflection_function, __construct) if (intern == NULL) { return; } - lcname = do_alloca(name_len + 1); - zend_str_tolower_copy(lcname, name_str, name_len); - if (zend_hash_find(EG(function_table), lcname, name_len + 1, (void **)&fptr) == FAILURE) { - free_alloca(lcname); + lcname = zend_u_str_case_fold(type, name_str, name_len, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), type, lcname, lcname_len + 1, (void **)&fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Function %s() does not exist", name_str); + "Function %R() does not exist", type, name_str); return; } - free_alloca(lcname); + efree(lcname); MAKE_STD_ZVAL(name); - ZVAL_STRING(name, fptr->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)fptr->common.function_name, 1); + } else { + ZVAL_STRING(name, fptr->common.function_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = fptr; intern->free_ptr = 0; @@ -1421,7 +1447,7 @@ ZEND_METHOD(reflection_function, invoke) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of function %s() failed", fptr->common.function_name); + "Invocation of function %v() failed", fptr->common.function_name); return; } @@ -1485,7 +1511,7 @@ ZEND_METHOD(reflection_function, invokeArgs) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of function %s() failed", fptr->common.function_name); + "Invocation of function %v() failed", fptr->common.function_name); return; } @@ -1598,19 +1624,20 @@ ZEND_METHOD(reflection_parameter, __construct) /* First, find the function */ switch (Z_TYPE_P(reference)) { + case IS_UNICODE: case IS_STRING: { - char *lcname; + unsigned int lcname_len; + char *lcname; - convert_to_string_ex(&reference); - lcname = do_alloca(Z_STRLEN_P(reference) + 1); - zend_str_tolower_copy(lcname, Z_STRVAL_P(reference), Z_STRLEN_P(reference)); - if (zend_hash_find(EG(function_table), lcname, (int) Z_STRLEN_P(reference) + 1, (void**) &fptr) == FAILURE) { - free_alloca(lcname); + convert_to_text_ex(&reference); + lcname = zend_u_str_case_fold(Z_TYPE_P(reference), Z_STRVAL_P(reference), Z_STRLEN_P(reference), 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(reference), lcname, lcname_len + 1, (void**) &fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Function %s() does not exist", Z_STRVAL_P(reference)); + "Function %R() does not exist", Z_TYPE_P(reference), Z_STRVAL_P(reference)); return; } - free_alloca(lcname); + efree(lcname); } break; @@ -1618,7 +1645,8 @@ ZEND_METHOD(reflection_parameter, __construct) zval **classref; zval **method; zend_class_entry **pce; - char *lcname; + unsigned int lcname_len; + char *lcname; if ((zend_hash_index_find(Z_ARRVAL_P(reference), 0, (void **) &classref) == FAILURE) || (zend_hash_index_find(Z_ARRVAL_P(reference), 1, (void **) &method) == FAILURE)) { @@ -1629,25 +1657,24 @@ ZEND_METHOD(reflection_parameter, __construct) if (Z_TYPE_PP(classref) == IS_OBJECT) { ce = Z_OBJCE_PP(classref); } else { - convert_to_string_ex(classref); - if (zend_lookup_class(Z_STRVAL_PP(classref), Z_STRLEN_PP(classref), &pce TSRMLS_CC) == FAILURE) { + convert_to_text_ex(classref); + if (zend_u_lookup_class(Z_TYPE_PP(classref), Z_UNIVAL_PP(classref), Z_UNILEN_PP(classref), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_PP(classref)); + "Class %R does not exist", Z_TYPE_PP(classref), Z_UNIVAL_PP(classref)); return; } ce = *pce; } - convert_to_string_ex(method); - lcname = do_alloca(Z_STRLEN_PP(method) + 1); - zend_str_tolower_copy(lcname, Z_STRVAL_PP(method), Z_STRLEN_PP(method)); - if (zend_hash_find(&ce->function_table, lcname, (int)(Z_STRLEN_PP(method) + 1), (void **) &fptr) == FAILURE) { - free_alloca(lcname); + convert_to_text_ex(method); + lcname = zend_u_str_case_fold(Z_TYPE_PP(method), Z_UNIVAL_PP(method), Z_UNILEN_PP(method), 1, &lcname_len); + if (zend_u_hash_find(&ce->function_table, Z_TYPE_PP(method), lcname, lcname_len + 1, (void **) &fptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s::%s() does not exist", Z_STRVAL_PP(classref), Z_STRVAL_PP(method)); + "Method %R::%R() does not exist", Z_TYPE_PP(classref), Z_UNIVAL_PP(classref), Z_TYPE_PP(method), Z_UNIVAL_PP(method)); return; } - free_alloca(lcname); + efree(lcname); } break; @@ -1683,7 +1710,11 @@ ZEND_METHOD(reflection_parameter, __construct) MAKE_STD_ZVAL(name); if (arg_info[position].name) { - ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(name, (UChar*)arg_info[position].name, arg_info[position].name_len, 1); + } else { + ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1); + } } else { ZVAL_NULL(name); } @@ -1739,15 +1770,16 @@ ZEND_METHOD(reflection_parameter, getClass) RETURN_NULL(); } else { zend_class_entry **pce; - char *lcname = do_alloca(param->arg_info->class_name_len + 1); - zend_str_tolower_copy(lcname, param->arg_info->class_name, param->arg_info->class_name_len); - if (zend_hash_find(EG(class_table), lcname, param->arg_info->class_name_len + 1, (void **) &pce) == FAILURE) { - free_alloca(lcname); + unsigned int lcname_len; + char *lcname = zend_u_str_case_fold(UG(unicode)?IS_UNICODE:IS_STRING, param->arg_info->class_name, param->arg_info->class_name_len, 0, &lcname_len); + + if (zend_u_hash_find(EG(class_table), UG(unicode)?IS_UNICODE:IS_STRING, lcname, lcname_len + 1, (void **) &pce) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", param->arg_info->class_name); + "Class %v does not exist", param->arg_info->class_name); return; } - free_alloca(lcname); + efree(lcname); zend_reflection_class_factory(*pce, return_value TSRMLS_CC); } } @@ -1884,14 +1916,16 @@ ZEND_METHOD(reflection_method, __construct) zval *name, *classname; zval *object; reflection_object *intern; + unsigned int lcname_len; char *lcname; zend_class_entry **pce; zend_class_entry *ce; zend_function *mptr; char *name_str; int name_len; + zend_uchar type; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zt", &classname, &name_str, &name_len, &type) == FAILURE) { return; } @@ -1904,9 +1938,10 @@ ZEND_METHOD(reflection_method, __construct) /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(classname), Z_UNIVAL_P(classname), Z_UNILEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_P(classname)); + "Class %v does not exist", Z_UNIVAL_P(classname)); return; } ce = *pce; @@ -1922,22 +1957,29 @@ ZEND_METHOD(reflection_method, __construct) } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - lcname = do_alloca(name_len + 1); - zend_str_tolower_copy(lcname, name_str, name_len); + lcname = zend_u_str_case_fold(type, name_str, name_len, 1, &lcname_len); - if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void **) &mptr) == FAILURE) { - free_alloca(lcname); + if (zend_u_hash_find(&ce->function_table, type, lcname, lcname_len + 1, (void **) &mptr) == FAILURE) { + efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s::%s() does not exist", ce->name, name_str); + "Method %v::%R() does not exist", ce->name, type, name_str); return; } - free_alloca(lcname); + efree(lcname); MAKE_STD_ZVAL(name); - ZVAL_STRING(name, mptr->common.function_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(name, (UChar*)mptr->common.function_name, 1); + } else { + ZVAL_STRING(name, mptr->common.function_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = mptr; intern->free_ptr = 0; @@ -1989,11 +2031,11 @@ ZEND_METHOD(reflection_method, invoke) (mptr->common.fn_flags & ZEND_ACC_ABSTRACT)) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s()", + "Trying to invoke abstract method %v::%v()", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s() from scope %s", + "Trying to invoke %s method %v::%v() from scope %v", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2054,7 +2096,7 @@ ZEND_METHOD(reflection_method, invoke) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); + "Invocation of method %v::%v() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2092,11 +2134,11 @@ ZEND_METHOD(reflection_method, invokeArgs) (mptr->common.fn_flags & ZEND_ACC_ABSTRACT)) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s", + "Trying to invoke abstract method %v::%v", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s from scope %s", + "Trying to invoke %s method %v::%v from scope %v", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2123,7 +2165,7 @@ ZEND_METHOD(reflection_method, invokeArgs) if (!object) { efree(params); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke non static method %s::%s without an object", + "Trying to invoke non static method %v::%v without an object", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2158,7 +2200,7 @@ ZEND_METHOD(reflection_method, invokeArgs) if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); + "Invocation of method %v::%v() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2308,7 +2350,11 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob if (Z_TYPE_P(argument) == IS_OBJECT) { MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + } else { + ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); intern->ptr = Z_OBJCE_P(argument); if (is_object) { @@ -2317,7 +2363,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob } } else { convert_to_string_ex(&argument); - if (zend_lookup_class(Z_STRVAL_P(argument), Z_STRLEN_P(argument), &ce TSRMLS_CC) == FAILURE) { + if (zend_u_lookup_class(Z_TYPE_P(argument), Z_UNIVAL_P(argument), Z_UNILEN_P(argument), &ce TSRMLS_CC) == FAILURE) { if (!EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, -1 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(argument)); } @@ -2325,7 +2371,11 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)((*ce)->name), (*ce)->name_length, 1); + } else { + ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); intern->ptr = *ce; @@ -2613,17 +2663,19 @@ ZEND_METHOD(reflection_class, hasMethod) { reflection_object *intern; zend_class_entry *ce; + unsigned int lc_name_len; char *name, *lc_name; int name_len; + zend_uchar type; METHOD_NOTSTATIC; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name, &name_len, &type) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if (zend_hash_exists(&ce->function_table, lc_name, name_len + 1)) { + lc_name = zend_u_str_case_fold(type, name, name_len, 1, &lc_name_len); + if (zend_u_hash_exists(&ce->function_table, type, lc_name, lc_name_len + 1)) { efree(lc_name); RETURN_TRUE; } else { @@ -2640,23 +2692,25 @@ ZEND_METHOD(reflection_class, getMethod) reflection_object *intern; zend_class_entry *ce; zend_function *mptr; + unsigned int lc_name_len; char *name, *lc_name; int name_len; + zend_uchar type; METHOD_NOTSTATIC; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &name, &name_len, &type) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if (zend_hash_find(&ce->function_table, lc_name, name_len + 1, (void**) &mptr) == SUCCESS) { + lc_name = zend_u_str_case_fold(type, name, name_len, 1, &lc_name_len); + if (zend_u_hash_find(&ce->function_table, type, lc_name, lc_name_len + 1, (void**) &mptr) == SUCCESS) { reflection_method_factory(ce, mptr, return_value TSRMLS_CC); efree(lc_name); } else { efree(lc_name); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Method %s does not exist", name); + "Method %R does not exist", type, name); return; } } @@ -2989,7 +3043,7 @@ ZEND_METHOD(reflection_class, newInstance) zend_fcall_info_cache fcc; if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name); + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %v", ce->name); return; } @@ -3017,7 +3071,7 @@ ZEND_METHOD(reflection_class, newInstance) if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { efree(params); zval_ptr_dtor(&retval_ptr); - zend_error(E_WARNING, "Invocation of %s's constructor failed", ce->name); + zend_error(E_WARNING, "Invocation of %v's constructor failed", ce->name); RETURN_NULL(); } if (retval_ptr) { @@ -3089,7 +3143,8 @@ ZEND_METHOD(reflection_class, isSubclassOf) switch(class_name->type) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s does not exist", Z_STRVAL_P(class_name)); return; @@ -3135,7 +3190,8 @@ ZEND_METHOD(reflection_class, implementsInterface) switch(interface->type) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(interface), Z_STRLEN_P(interface), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(interface), Z_UNIVAL_P(interface), Z_UNILEN_P(interface), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s does not exist", Z_STRVAL_P(interface)); return; @@ -3161,7 +3217,7 @@ ZEND_METHOD(reflection_class, implementsInterface) if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Interface %s is a Class", interface_ce->name); + "Interface %v is a Class", interface_ce->name); return; } RETURN_BOOL(instanceof_function(ce, interface_ce TSRMLS_CC)); @@ -3267,7 +3323,8 @@ ZEND_METHOD(reflection_property, __construct) /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: - if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { + case IS_UNICODE: + if (zend_u_lookup_class(Z_TYPE_P(classname), Z_UNIVAL_P(classname), Z_UNILEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(classname)); return; @@ -3286,7 +3343,7 @@ ZEND_METHOD(reflection_property, __construct) if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Property %s::$%s does not exist", ce->name, name_str); + "Property %v::$%s does not exist", ce->name, name_str); return; } @@ -3307,12 +3364,20 @@ ZEND_METHOD(reflection_property, __construct) } MAKE_STD_ZVAL(classname); - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + if (UG(unicode)) { + ZVAL_UNICODEL(classname, (UChar*)ce->name, ce->name_length, 1); + } else { + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + } zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - zend_unmangle_property_name(property_info->name, &class_name, &prop_name); + zend_u_unmangle_property_name(UG(unicode)?IS_UNICODE:IS_STRING, property_info->name, &class_name, &prop_name); MAKE_STD_ZVAL(propname); - ZVAL_STRING(propname, prop_name, 1); + if (UG(unicode)) { + ZVAL_UNICODE(propname, (UChar*)prop_name, 1); + } else { + ZVAL_STRING(propname, prop_name, 1); + } zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &propname, sizeof(zval *), NULL); reference = (property_reference*) emalloc(sizeof(property_reference)); @@ -3421,6 +3486,7 @@ ZEND_METHOD(reflection_property, getValue) property_reference *ref; zval *object; zval **member= NULL; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); @@ -3432,16 +3498,16 @@ ZEND_METHOD(reflection_property, getValue) if ((ref->prop->flags & ZEND_ACC_STATIC)) { zend_update_class_constants(intern->ce TSRMLS_CC); - if (zend_hash_quick_find(intern->ce->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(intern->ce->static_members, utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } } else { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { return; } - if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(Z_OBJPROP_P(object), utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } } @@ -3463,6 +3529,7 @@ ZEND_METHOD(reflection_property, setValue) int setter_done = 0; zval *tmp; HashTable *prop_table; + zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); @@ -3486,8 +3553,8 @@ ZEND_METHOD(reflection_property, setValue) prop_table = Z_OBJPROP_P(object); } - if (zend_hash_quick_find(prop_table, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { - zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); + if (zend_u_hash_quick_find(prop_table, utype, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { + zend_error(E_ERROR, "Internal error: Could not find the property %v", ref->prop->name); /* Bails out */ } if (*variable_ptr == value) { @@ -3510,7 +3577,7 @@ ZEND_METHOD(reflection_property, setValue) if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } - zend_hash_quick_update(prop_table, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); + zend_u_hash_quick_update(prop_table, utype, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); } } /* }}} */ @@ -3943,12 +4010,13 @@ static zend_object_handlers *zend_std_obj_handlers; /* {{{ _reflection_write_property */ static void _reflection_write_property(zval *object, zval *member, zval *value TSRMLS_DC) { - if (Z_TYPE_P(member) == IS_STRING - && zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) - && (!strcmp(Z_STRVAL_P(member), "name") || !strcmp(Z_STRVAL_P(member), "class"))) + if ((Z_TYPE_P(member) == IS_STRING || Z_TYPE_P(member) == IS_UNICODE) + && zend_u_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member)+1) + && (ZEND_U_EQUAL(Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member), "name", sizeof("name")-1) || + ZEND_U_EQUAL(Z_TYPE_P(member), Z_UNIVAL_P(member), Z_UNILEN_P(member), "class", sizeof("class")-1))) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Cannot set read-only property %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member)); + "Cannot set read-only property %v::$%R", Z_OBJCE_P(object)->name, Z_TYPE_P(member), Z_UNIVAL_P(member)); } else { @@ -4038,6 +4106,20 @@ ZEND_API void zend_register_reflection_api(TSRMLS_D) { } /* }}} */ +void init_reflection_api(TSRMLS_D) +{ + reflection_exception_ptr = zend_get_named_class_entry("ReflectionException", sizeof("ReflectionException")-1 TSRMLS_CC); + reflection_ptr = zend_get_named_class_entry("Reflection", sizeof("Reflection")-1 TSRMLS_CC); + reflector_ptr = zend_get_named_class_entry("Reflector", sizeof("Reflector")-1 TSRMLS_CC); + reflection_function_ptr = zend_get_named_class_entry("ReflectionFunction", sizeof("ReflectionFunction")-1 TSRMLS_CC); + reflection_parameter_ptr = zend_get_named_class_entry("ReflectionParameter", sizeof("ReflectionParameter")-1 TSRMLS_CC); + reflection_method_ptr = zend_get_named_class_entry("ReflectionMethod", sizeof("ReflectionMethod")-1 TSRMLS_CC); + reflection_class_ptr = zend_get_named_class_entry("ReflectionClass", sizeof("ReflectionClass")-1 TSRMLS_CC); + reflection_object_ptr = zend_get_named_class_entry("ReflectionObject", sizeof("ReflectionObject")-1 TSRMLS_CC); + reflection_property_ptr = zend_get_named_class_entry("ReflectionProperty", sizeof("ReflectionProperty")-1 TSRMLS_CC); + reflection_extension_ptr = zend_get_named_class_entry("ReflectionExtension", sizeof("ReflectionExtension")-1 TSRMLS_CC); +} + /* * Local variables: * tab-width: 4 diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index fb06af4687..a16ed9b7f9 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -26,6 +26,8 @@ BEGIN_EXTERN_C() ZEND_API void zend_register_reflection_api(TSRMLS_D); ZEND_API void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_DC); +void init_reflection_api(TSRMLS_D); + END_EXTERN_C() #endif