]> granicus.if.org Git - php/commitdiff
Unicode support
authorAndrei Zmievski <andrei@php.net>
Thu, 11 Aug 2005 23:35:03 +0000 (23:35 +0000)
committerAndrei Zmievski <andrei@php.net>
Thu, 11 Aug 2005 23:35:03 +0000 (23:35 +0000)
51 files changed:
Zend/Makefile.am
Zend/Zend.m4
Zend/flex.skl
Zend/zend.c
Zend/zend.h
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_alloc.c
Zend/zend_alloc.h
Zend/zend_builtin_functions.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_constants.c
Zend/zend_constants.h
Zend/zend_exceptions.c
Zend/zend_exceptions.h
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_globals_macros.h
Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_highlight.c
Zend/zend_ini.c
Zend/zend_ini_scanner.l
Zend/zend_interfaces.c
Zend/zend_interfaces.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.h
Zend/zend_language_scanner.l
Zend/zend_multibyte.c
Zend/zend_object_handlers.c
Zend/zend_objects.c
Zend/zend_objects_API.c
Zend/zend_opcode.c
Zend/zend_operators.c
Zend/zend_operators.h
Zend/zend_reflection_api.c
Zend/zend_reflection_api.h
Zend/zend_strtod.c
Zend/zend_strtol.c [new file with mode: 0644]
Zend/zend_unicode.c [new file with mode: 0644]
Zend/zend_unicode.h [new file with mode: 0644]
Zend/zend_variables.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_gen.php
Zend/zend_vm_opcodes.h
ext/reflection/php_reflection.c
ext/reflection/php_reflection.h

index 42ae4d5424953ff6de3d38811b925e025eb6b34a..93229c280d60e5bdbe373ece4d784affaa7d53c2 100644 (file)
@@ -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@
index b1d49959883b91916495956f38bf2f1948679f86..ea3bf18ee680ce7d705a95e864fb11bd497024b5 100644 (file)
@@ -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)
index 9a7c5cf873b2ddb3defcce5d400e34ab403a67ab..060a34bbee247fe1cc1a74d5dd2e7a1146752f80 100644 (file)
@@ -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,
index 52ee10b4191ae2d92280032651333635bb5bfe08..4604ace376038a8666c3b16c78eb7123c43219e3 100644 (file)
 #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<indent; i++) {
                        ZEND_PUTS(" ");
                }
                ZEND_PUTS("[");
-               switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator)) {
+               switch ((key_type = zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator))) {
                        case HASH_KEY_IS_STRING:
+                       case HASH_KEY_IS_UNICODE:
+                       case HASH_KEY_IS_BINARY:
                                if (is_object) {
                                        char *prop_name, *class_name;
 
-                                       zend_unmangle_property_name(string_key, &class_name, &prop_name);
-                                       ZEND_PUTS(prop_name);
+                                       zend_u_unmangle_property_name(key_type==HASH_KEY_IS_UNICODE?IS_UNICODE:IS_STRING, string_key, &class_name, &prop_name);
+                                       if (key_type == HASH_KEY_IS_UNICODE) {
+                                               zend_printf("%r", prop_name);
+                                       } else {
+                                               ZEND_PUTS(prop_name);
+                                       }
                                        if (class_name) {
                                                if (class_name[0]=='*') {
                                                        ZEND_PUTS(":protected");
@@ -137,7 +277,11 @@ static void print_hash(HashTable *ht, int indent, zend_bool is_object TSRMLS_DC)
                                                }
                                        }
                                } else {
-                                       ZEND_WRITE(string_key, str_len-1);
+                                       if (key_type == HASH_KEY_IS_UNICODE) {
+                                               zend_printf("%r", string_key);
+                                       } else {
+                                               ZEND_WRITE(string_key, str_len-1);
+                                       }
                                }
                                break;
                        case HASH_KEY_IS_LONG:
@@ -158,39 +302,99 @@ static void print_hash(HashTable *ht, int indent, zend_bool is_object TSRMLS_DC)
 
 static void print_flat_hash(HashTable *ht TSRMLS_DC)
 {
-    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);
-    }
+       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 <floatingpoint.h>
@@ -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, ...)
 {
index d2aa70b6ed3bc88be187404eef24877e3992bde3..b517ceff95be46a61afa39ee2aa35ddc9ae60391 100644 (file)
@@ -35,6 +35,7 @@
 #endif
 
 #include <stdio.h>
+#include <assert.h>
 
 /*
  * general definitions
@@ -225,6 +226,8 @@ char *alloca ();
 
 #include "zend_types.h"
 
+#include <unicode/utypes.h>
+
 #ifdef HAVE_LIMITS_H
 # include <limits.h>
 #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 */
 
 /*
index 537cb9086ebc105b358b01bdcc22bc507be4c8f7..852821c8173c6d75b374ee47993792b250e97cb3 100644 (file)
@@ -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
index d42c91451267605e73eb142b79a912bac50d78cd..38b4a9f19998a535557eb39456996c7bc9c5ee70 100644 (file)
@@ -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) {                                                                                                                                                         \
                                                                {                                                                                                                                                       \
index f77c54ef9c271ff8767b158c64e6743757dc7a47..26b41adf51c342d8fccbb1d379d2775a5d0e1f6f 100644 (file)
@@ -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 <signal.h>
 #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)
 {
index 6d4b58192fcc76189baa6455accef050e1343e5a..fc0edf0a4d39ed1d4881aa08bad80d90f9d4ef20 100644 (file)
@@ -28,6 +28,7 @@
 #include "zend_globals_macros.h"
 
 #include "zend_mm.h"
+#include <unicode/utypes.h>
 
 #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))
index 0506d5f2630e3e8b058a8d409a63f950d5cea794..c1ca31c25e7e781688899d9f6e7e2d8b6e76fc5f 100644 (file)
@@ -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);
                        }
 
index a7c09b0a147ed06498ac777048530f2e733929d6..86c68cad137d5bae77d1ab5f2b8e410d0c0f9569 100644 (file)
 #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; i<num_references->u.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
index b63dd8c90a308499454f6f4d6564dac1415291bb..869a0a89ea8b9275c4192bacd42d679b09f80389 100644 (file)
@@ -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);
index ae06f837e717ec4f7df064d6fc2de3ef65514ce8..613bc0a962a694a8307efd6342a7504dc884e87c 100644 (file)
@@ -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
index 241050da5b3dc41476aaf7aba4671c3a72510330..a3ca212d3b62da3bd8767abb474ae507ec7e2f14 100644 (file)
@@ -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()
index ca410c56f02d4938fca395eab89538ed72428a92..b19a460f3a53ba1e650379863ce29017be55e932 100644 (file)
@@ -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
index 0a470622653f2f57d6188c606388552727e7e30c..b546b08c24539071beda82d7bb89cf04bcd9ea50 100644 (file)
@@ -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
index 888b60e9d23f8d3f391dab5e97d2c5d1b643dc41..8aa30d3c861aac6d572647e254d50912932029f3 100644 (file)
@@ -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; i<T->str_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:
index bf7657ed0f5ab5c2e20844a2d85971f12fced8ae..ad05ea771906e4c49127d5b2ba1ffe104e8d9c09 100644 (file)
@@ -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 */
index 4a131ccf296af1126de071955ea4aa19e21c638e..94e462a33ee420bec320beb139d53d10092d7e8e 100644 (file)
@@ -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
index bdbf72e6591a2edf8b379f8bb2cac6e4b7113939..1182b4a833ed8d54aa47fc8969d5d4b03b011029 100644 (file)
@@ -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 <unicode/ucnv.h>
+#include <unicode/ucol.h>
 
 /* 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 */
index ce98d15d5b63906dee0904b56742832faeb4ce3f..58d43080fe2b730ac75e59448c9524d0abfbfe12 100644 (file)
@@ -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()
index 407b7627b95caa1cca8e3ac1226f9b835c4802cd..41178883fb60281b89346e53efc94e8d5429a214 100644 (file)
@@ -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  |
 /* $Id$ */
 
 #include "zend.h"
+#include "zend_operators.h"
+#include "zend_globals.h"
+
+#include <unicode/utypes.h>
+#include <unicode/uchar.h>
 
 #define CONNECT_TO_BUCKET_DLLIST(element, list_head)           \
        (element)->pNext = (list_head);                                                 \
                (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<end) {                                                                                                                               \
+                       if (!(*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 (tmp<end) {                                                                                                                               \
+                       if (u_digit(*tmp, 10) < 0) {                                                                                    \
+                               break;                                                                                                                                  \
+                       }                                                                                                                                                       \
+                       tmp++;                                                                                                                                          \
+               }                                                                                                                                                               \
+               if (tmp==end && *tmp==0) { /* a numeric index */                                                                \
+                       if (*key=='-') {                                                                                                                        \
+                               idx = zend_u_strtol(key, NULL, 10);                                                                                     \
+                               if (idx!=LONG_MIN) {                                                                                                    \
+                                       return func;                                                                                                            \
+                               }                                                                                                                                               \
+                       } else {                                                                                                                                        \
+                               idx = zend_u_strtol(key, NULL, 10);                                                                                     \
+                               if (idx!=LONG_MAX) {                                                                                                    \
+                                       return func;                                                                                                            \
+                               }                                                                                                                                               \
+                       }                                                                                                                                                       \
+               }                                                                                                                                                               \
+       } while (0);                                                                                                                                            \
+}
+
+ZEND_API int zend_u_symtable_update(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest)
+{
+       if (type == IS_STRING) {
+               HANDLE_NUMERIC((char*)arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
+       } else if (type == IS_UNICODE) {
+               HANDLE_U_NUMERIC((UChar*)arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
+       }
+       return zend_u_hash_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest);
+}
+
+
+ZEND_API int zend_u_symtable_del(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength)
+{
+       if (type == IS_STRING) {
+               HANDLE_NUMERIC((char*)arKey, nKeyLength, zend_hash_index_del(ht, idx));
+       } else if (type == IS_UNICODE) {
+               HANDLE_U_NUMERIC((UChar*)arKey, nKeyLength, zend_hash_index_del(ht, idx));
+       }
+       return zend_u_hash_del(ht, type, arKey, nKeyLength);
+}
+
+
+ZEND_API int zend_u_symtable_find(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength, void **pData)
+{
+       if (type == IS_STRING) {
+               HANDLE_NUMERIC((char*)arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
+       } else if (type == IS_UNICODE) {
+               HANDLE_U_NUMERIC((UChar*)arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
+       }
+       return zend_u_hash_find(ht, type, arKey, nKeyLength, pData);
+}
+
+
+ZEND_API int zend_u_symtable_exists(HashTable *ht, zend_uchar type, void *arKey, uint nKeyLength)
+{
+       if (type == IS_STRING) {
+               HANDLE_NUMERIC((char*)arKey, nKeyLength, zend_hash_index_exists(ht, idx));
+       } else if (type == IS_UNICODE) {
+               HANDLE_U_NUMERIC((UChar*)arKey, nKeyLength, zend_hash_index_exists(ht, idx));
+       }
+       return zend_u_hash_exists(ht, type, arKey, nKeyLength);
+}
+
+ZEND_API 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_del(HashTable *ht, char *arKey, uint nKeyLength)
+{
+       HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx))
+       return zend_hash_del(ht, arKey, nKeyLength);
+}
+
+
+ZEND_API 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);
+}
+
+
+ZEND_API 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);
+}
 
 #if ZEND_DEBUG
 void zend_hash_display_pListTail(HashTable *ht)
@@ -1386,7 +1723,11 @@ void zend_hash_display_pListTail(HashTable *ht)
 
        p = ht->pListTail;
        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;
        }
 }
index 774c607418b324befc09ad3750a4d6f86c5a4c36..f0aa3e6034c3da6853d39c644fc4dab595ad288b 100644 (file)
@@ -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)
 #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<end) {                                                                                                                               \
-                       if (!(*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 */
 
index cbd269ed29eefed627564b4991914bf2b46addf4..980616ebf0839f34a13f6bdfe8ca075163b5c5f9 100644 (file)
@@ -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("<code>");
        zend_printf("<span style=\"color: %s\">\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;
                        }
                }
index 91e320b621bfc51dfa0d0c75a5fbfec8a5e1c780..61976052e4d775a84c5f33cf8a9bf0eb03b63e22 100644 (file)
@@ -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);
        }
 }
 
index c18a0695a4c8e56b8bf5eb542606482aa08341f6..9fb3461c95a8c47f6fded4ad313e5471be7297d5 100644 (file)
@@ -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;
 
index 7454311d61a146fab89c706f78a68aef598839b5..c53a657c6611689b69c59c5ebd2ee7a0fe5bc07b 100755 (executable)
@@ -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
index f2ebdbac3755e2a830f8210f6d8a5b183a3d02a2..0894e8ae17cbb142b93058629a90ec3b4973815f 100755 (executable)
@@ -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 */
index 5861031321d26b9ca75674d25b15399315d4fe13..8286e266e0455b4a2f85492db312af655212ac5c 100644 (file)
@@ -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
 %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:
index 7928198f3f63bc530215691c04c0e8c072ff60ca..a7778d8d02b98ea68c8a763182b882d299aa83de 100644 (file)
@@ -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;
 
 
index cd6c17f06e549323f54671e2294734957dc007fb..a7ab4ea4e854192e6f6dd04a079bb09c3697b6b2 100644 (file)
@@ -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 <stdarg.h>
@@ -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) {
+               if (*s==0x5C /*'\\'*/) {
+                       s++;
+                       c = *s;
+                       if (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) {
+               if (*s==0x5C /*'\\'*/) {
+                       s++;
+                       if (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) {
+               if (*s=='\\') {
+                       s++;
+                       if (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)<end && ZEND_IS_OCT(*(s+1))) {
+                                                       octal_buf[1] = *(++s);
+                                                       zendlval->value.str.len--;
+                                                       if ((s+1)<end && ZEND_IS_OCT(*(s+1))) {
+                                                               octal_buf[2] = *(++s);
+                                                               zendlval->value.str.len--;
+                                                       }
+                                               }
+                                               *t++ = (char) strtol(octal_buf, NULL, 8);
+                                       } else if (*s=='x' && (s+1)<end && ZEND_IS_HEX(*(s+1))) {
+                                               char hex_buf[3] = { 0, 0, 0};
+
+                                               zendlval->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)<end && ZEND_IS_HEX(*(s+1))) {
+                                                       hex_buf[1] = *(++s);
+                                                       zendlval->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) {
+               if (*s=='\\') {
+                       s++;
+                       if (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")
 
 <ST_LOOKING_FOR_PROPERTY>{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;
 }
 
+<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"unicode"{TABS_AND_SPACES}")" {
+       return T_UNICODE_CAST;
+}
+
+<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"binary"{TABS_AND_SPACES}")" {
+       return T_BINARY_CAST;
+}
+
 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" {
        return T_ARRAY_CAST;
 }
@@ -1208,8 +1824,12 @@ NEWLINE ("\r"|"\n"|"\r\n")
 
 
 <ST_LOOKING_FOR_VARNAME>{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")
 }
 
 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{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")
 }
 
 <INITIAL>(([^<]|"<"[^?%s<]){1,400})|"<s"|"<" {
-#ifdef ZEND_MULTIBYTE
-       if (SCNG(output_filter)) {
-               int readsize;
-               readsize = SCNG(output_filter)(&(zendlval->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")
 }
 
 <ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{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;
 }
 
 <ST_IN_SCRIPTING>{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;
 }
 
 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{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")
 
 
 <ST_IN_SCRIPTING>(["]([^$"\\]|("\\".))*["]) {
-       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) {
-               if (*s=='\\') {
-                       s++;
-                       if (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)<end && ZEND_IS_OCT(*(s+1))) {
-                                                       octal_buf[1] = *(++s);
-                                                       zendlval->value.str.len--;
-                                                       if ((s+1)<end && ZEND_IS_OCT(*(s+1))) {
-                                                               octal_buf[2] = *(++s);
-                                                               zendlval->value.str.len--;
-                                                       }
-                                               }
-                                               *t++ = (char) strtol(octal_buf, NULL, 8);
-                                       } else if (*s=='x' && (s+1)<end && ZEND_IS_HEX(*(s+1))) {
-                                               char hex_buf[3] = { 0, 0, 0};
-
-                                               zendlval->value.str.len--; /* for the 'x' */
-
-                                               hex_buf[0] = *(++s);
-                                               zendlval->value.str.len--;
-                                               if ((s+1)<end && ZEND_IS_HEX(*(s+1))) {
-                                                       hex_buf[1] = *(++s);
-                                                       zendlval->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;
+<ST_IN_SCRIPTING>(b["]([^$"\\]|("\\".))*["]) {
+       yytext++; /* adjust for 'b' */
+       yyleng--;
+       return zend_scan_binary_double_string(zendlval TSRMLS_CC);
 }
 
 
 <ST_IN_SCRIPTING>([']([^'\\]|("\\".))*[']) {
-       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) {
-               if (*s=='\\') {
-                       s++;
-                       if (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;
+<ST_IN_SCRIPTING>("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 '\"';
 }
 
+<ST_IN_SCRIPTING>b["] {
+       BEGIN(ST_DOUBLE_QUOTES);
+       return T_BINARY_DOUBLE;
+}
+
+<ST_IN_SCRIPTING>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;
+}
+
 
 <ST_IN_SCRIPTING>"<<<"{TABS_AND_SPACES}{LABEL}{NEWLINE} {
        char *s;
@@ -1708,12 +2292,6 @@ NEWLINE ("\r"|"\n"|"\r\n")
 }
 
 
-<ST_IN_SCRIPTING>['] {
-       BEGIN(ST_SINGLE_QUOTE);
-       return '\'';
-}
-
-
 <ST_HEREDOC>^{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")
 
 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{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;
-}
-
-<ST_SINGLE_QUOTE>([^'\\]|\\[^'\\])+ {
-       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;
 }
 
-
 <ST_DOUBLE_QUOTES>[`]+ {
-       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;
 }
 
 
 <ST_BACKQUOTE>["]+ {
-       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")
 }
 
 
-<ST_SINGLE_QUOTE>"\\'" {
-       zendlval->value.lval = (long) '\'';
-       return T_CHARACTER;
-}
-
-<ST_SINGLE_QUOTE>"\\\\" {
-       zendlval->value.lval = (long)'\\';
-       return T_CHARACTER;
-}
-
 <ST_DOUBLE_QUOTES>"\\\"" {
        zendlval->value.lval = (long) '"';
        return T_CHARACTER;
@@ -1833,6 +2396,61 @@ NEWLINE ("\r"|"\n"|"\r\n")
        return T_CHARACTER;
 }
 
+
+<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"\\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;
+       }
+}
+
+
+<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"\\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;
+       }
+}
+
+
 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"\\"{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")
 
 
 <ST_HEREDOC>["'`]+ {
-       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")
 }
 
 
-<ST_SINGLE_QUOTE>['] {
-       BEGIN(ST_IN_SCRIPTING);
-       return '\'';
-}
-
-
 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,INITIAL,ST_IN_SCRIPTING,ST_LOOKING_FOR_PROPERTY><<EOF>> {
        return 0;
 }
@@ -1901,6 +2513,6 @@ NEWLINE ("\r"|"\n"|"\r\n")
 
 
 
-<ST_IN_SCRIPTING,INITIAL,ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_SINGLE_QUOTE,ST_HEREDOC>{ANY_CHAR} {
+<ST_IN_SCRIPTING,INITIAL,ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{ANY_CHAR} {
        zend_error(E_COMPILE_WARNING,"Unexpected character in input:  '%c' (ASCII=%d) state=%d", yytext[0], yytext[0], YYSTATE);
 }
index d7a444b32e9462eb4c454855cdbaf02595905b6e..6dde60ad9594763f6d40546ea29a90b14930c1f8 100644 (file)
@@ -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)
 {
index 6f385c1b51d63cab6dce82033e7331f666c5b1cf..795868f3141d812774c87d68ee18188e471d7efd 100644 (file)
@@ -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;
index 9b5b85422038a9f452d12e511725e8b587ffc450..83f0d809b595d35ba47cd9ab40efe2fec5c2fa25 100644 (file)
@@ -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);
 
index a13181c5cca13668a52a02b87aac90871a63401e..ab62dcfe48821e6905b1f70a37673b228b349ed0 100644 (file)
@@ -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);
index 37bb6b604a1d2344dbb4947fc169b25124798e8f..56823cccdf4aa902d1670a1952e38e22ba6d4e10 100644 (file)
@@ -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;
 }
 
index 509f9e231581f284285cb2bfdcc9058d6ce4089b..bb09fb3bb983888037a2f893da9fb78ead0016a1 100644 (file)
@@ -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
index 0f1f23e4695981f650fa37361f7fb9e98832cf55..af0b99d1b47bad87aa27882c570712d8b9fb884f 100644 (file)
@@ -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)
index 2bbd91bc982db7735321a241eb699bbdfae625e6..fa001dc9b97ebf48e377545533fa724d3982ad31 100644 (file)
@@ -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, "<required> ");
        }
        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
index fb06af468757a9085cd72f25cbd9def888982f73..a16ed9b7f958b2f13df6c32a2754c6d2446ba54e 100644 (file)
@@ -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
index 87d755006a4e0f445e31aaee07dbf15e566f210f..1810c5bf2743f67c06a728848afab668181eaa18 100644 (file)
@@ -90,6 +90,8 @@
  */
 
 #include <zend_strtod.h>
+#include <unicode/utypes.h>
+#include <unicode/ustdio.h>
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -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 (file)
index 0000000..9a56cac
--- /dev/null
@@ -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 <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unicode/utypes.h>
+#include <unicode/uchar.h>
+
+/*
+ * 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 (file)
index 0000000..edaf956
--- /dev/null
@@ -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 <andrei@php.net>                            |
+   +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "zend_globals.h"
+#include "zend_operators.h"
+#include "zend_API.h"
+#include "zend_unicode.h"
+#include <unicode/unorm.h>
+
+#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 (file)
index 0000000..950dc7c
--- /dev/null
@@ -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 <andrei@php.net>                            |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_UNICODE_H
+#define ZEND_UNICODE_H
+
+#include "zend.h"
+#include <unicode/utypes.h>
+#include <unicode/ustring.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustdio.h>
+#include <unicode/uchar.h>
+#include <unicode/uloc.h>
+#include <unicode/ucol.h>
+
+#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 */
index 3bedc0a4ad8552129aa01d96dcb93c0cde260101..7d5b208ca1d064cc051ceb3d4a2190fd55d3fc25 100644 (file)
 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);
index b96d1a1e7f80a80f72181a7ce3dd558f78c49932..52bfccf37d795bedfeaa3167cc0126000bc6f547 100644 (file)
@@ -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)
index c60cef5c88c3a3c08fe5af4e2992891e3db3d20d..4328aac4cee31548550cb073296e0db8578bfbac 100644 (file)
@@ -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;
index 235735d9834bba9d40fdf5743046b7be7fb8bd11..c30eed096efc12aa3a6c33ce0cd49fff35d08571 100644 (file)
@@ -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() {
index 319b5483eaa7e6951c20dd721d8a40dd522bfc51..b10683c584dcd5a8606d6e06f7fd50c15baec993 100644 (file)
 #define ZEND_ISSET_ISEMPTY_PROP_OBJ  148
 #define ZEND_HANDLE_EXCEPTION        149
 #define ZEND_USER_OPCODE             150
+#define ZEND_U_NORMALIZE             151
index 2bbd91bc982db7735321a241eb699bbdfae625e6..fa001dc9b97ebf48e377545533fa724d3982ad31 100644 (file)
@@ -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, "<required> ");
        }
        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
index fb06af468757a9085cd72f25cbd9def888982f73..a16ed9b7f958b2f13df6c32a2754c6d2446ba54e 100644 (file)
@@ -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