diff options
Diffstat (limited to 'php/msgpack_unpack.c')
| -rw-r--r-- | php/msgpack_unpack.c | 1070 |
1 files changed, 472 insertions, 598 deletions
diff --git a/php/msgpack_unpack.c b/php/msgpack_unpack.c index c6b9b3f..f3b610d 100644 --- a/php/msgpack_unpack.c +++ b/php/msgpack_unpack.c @@ -2,31 +2,69 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/php_incomplete_class.h" -#include "ext/standard/php_var.h" #include "php_msgpack.h" #include "msgpack_pack.h" #include "msgpack_unpack.h" -#include "msgpack/unpack_define.h" - -#define VAR_ENTRIES_MAX 1024 - #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3) # define Z_ADDREF_PP(ppz) ZVAL_ADDREF(*(ppz)) # define Z_SET_ISREF_PP(ppz) (*(ppz))->is_ref = 1 # define Z_UNSET_ISREF_PP(ppz) (*(ppz))->is_ref = 0 #endif +#define VAR_ENTRIES_MAX 1024 + typedef struct { zval *data[VAR_ENTRIES_MAX]; long used_slots; + long value_slots; + long access_slots[VAR_ENTRIES_MAX]; + bool alloc_slots[VAR_ENTRIES_MAX]; void *next; } var_entries; +#define MSGPACK_UNSERIALIZE_ALLOC(_unpack) \ + if (_unpack->deps <= 0) { \ + *obj = _unpack->retval; \ + msgpack_var_push(_unpack->var_hash, obj, true, false); \ + } else { \ + ALLOC_INIT_ZVAL(*obj); \ + msgpack_var_push(_unpack->var_hash, obj, false, true); \ + } + +#define MSGPACK_UNSERIALIZE_ALLOC_VALUE(_unpack) \ + if (_unpack->deps <= 0) { \ + *obj = _unpack->retval; \ + msgpack_var_push(_unpack->var_hash, obj, true, false); \ + } else { \ + ALLOC_INIT_ZVAL(*obj); \ + msgpack_var_push(_unpack->var_hash, obj, true, true); \ + } + +#define MSGPACK_UNSERIALIZE_PUSH_ITEM(_unpack, _count, _val) \ + msgpack_var_alloc(_unpack->var_hash, _count); \ + if (Z_TYPE_P(_val) != IS_ARRAY && Z_TYPE_P(_val) != IS_OBJECT) { \ + msgpack_var_push(_unpack->var_hash, &_val, true, false); \ + } + +#define MSGPACK_UNSERIALIZE_FINISH_ITEM(_unpack) \ + long deps = _unpack->deps - 1; \ + _unpack->stack[deps]--; \ + if (_unpack->stack[deps] == 0) { \ + _unpack->deps--; \ + } + +#define MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(_unpack, _key, _val) \ + zval_ptr_dtor(&_key); \ + zval_ptr_dtor(&_val); \ + msgpack_var_alloc(_unpack->var_hash, 2); \ + MSGPACK_UNSERIALIZE_FINISH_ITEM(_unpack); + + inline static void msgpack_var_push( - php_unserialize_data_t *var_hashx, zval **rval) + php_unserialize_data_t *var_hashx, zval **rval, bool value, bool alloc) { var_entries *var_hash, *prev = NULL; @@ -47,6 +85,7 @@ inline static void msgpack_var_push( { var_hash = emalloc(sizeof(var_entries)); var_hash->used_slots = 0; + var_hash->value_slots = 0; var_hash->next = 0; if (!var_hashx->first) @@ -59,9 +98,45 @@ inline static void msgpack_var_push( } } + var_hash->alloc_slots[var_hash->used_slots] = alloc; + + if (value) + { + var_hash->access_slots[var_hash->value_slots++] = var_hash->used_slots; + } + var_hash->data[var_hash->used_slots++] = *rval; } +inline static void msgpack_var_alloc( + php_unserialize_data_t *var_hashx, long count) +{ + long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) + { + var_hash = var_hash->next; + } + + if (!var_hash || count <= 0) + { + return; + } + + for (i = var_hash->used_slots - 1; i >= 0; i--) + { + if (var_hash->alloc_slots[i]) + { + var_hash->alloc_slots[i] = false; + if (--count <= 0) + { + break; + } + } + } +} + inline static int msgpack_var_access( php_unserialize_data_t *var_hashx, long id, zval ***store) { @@ -79,6 +154,13 @@ inline static int msgpack_var_access( return !SUCCESS; } + if (id < 0 || id >= var_hash->value_slots) + { + return !SUCCESS; + } + + id = var_hash->access_slots[id]; + if (id < 0 || id >= var_hash->used_slots) { return !SUCCESS; @@ -89,741 +171,533 @@ inline static int msgpack_var_access( return SUCCESS; } -inline static int msgpack_unserialize_array( - zval **return_value, msgpack_unserialize_data *mpsd, - ulong ct, php_unserialize_data_t *var_hash TSRMLS_DC) +inline static zend_class_entry* msgpack_unserialize_class( + zval **container, char *class_name, size_t name_len) { - ulong i; - HashTable *ht; - - msgpack_var_push(var_hash, return_value); + zend_class_entry *ce, **pce; + bool incomplete_class = false; + zval *user_func, *retval_ptr, **args[1], *arg_func_name; + TSRMLS_FETCH(); - if (Z_TYPE_PP(return_value) != IS_ARRAY) + do { - array_init(*return_value); - } + /* Try to find class directly */ + if (zend_lookup_class(class_name, name_len, &pce TSRMLS_CC) == SUCCESS) + { + ce = *pce; + break; + } - ht = HASH_OF(*return_value); + /* Check for unserialize callback */ + if ((PG(unserialize_callback_func) == NULL) || + (PG(unserialize_callback_func)[0] == '\0')) + { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + break; + } - for (i = 0; i < ct; i++) - { - zval *val; + /* Call unserialize callback */ + ALLOC_INIT_ZVAL(user_func); + ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); + args[0] = &arg_func_name; + ALLOC_INIT_ZVAL(arg_func_name); + ZVAL_STRING(arg_func_name, class_name, 1); + if (call_user_function_ex( + CG(function_table), NULL, user_func, &retval_ptr, + 1, args, 0, NULL TSRMLS_CC) != SUCCESS) + { + if (MSGPACK_G(error_display)) + { + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_class) " + "defined (%s) but not found", class_name); + } - /* value */ - ALLOC_INIT_ZVAL(val); + incomplete_class = 1; + ce = PHP_IC_ENTRY; + zval_ptr_dtor(&user_func); + zval_ptr_dtor(&arg_func_name); + break; + } + if (retval_ptr) + { + zval_ptr_dtor(&retval_ptr); + } - if (msgpack_unserialize_zval(&val, mpsd, var_hash TSRMLS_CC) <= 0) + /* The callback function may have defined the class */ + if (zend_lookup_class(class_name, name_len, &pce TSRMLS_CC) == SUCCESS) + { + ce = *pce; + } + else { if (MSGPACK_G(error_display)) { zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_array) " - "Invalid value"); + "[msgpack] (msgpack_unserialize_class) " + "Function %s() hasn't defined the class " + "it was called for", class_name); } - zval_ptr_dtor(&val); - return MSGPACK_UNPACK_PARSE_ERROR; + incomplete_class = true; + ce = PHP_IC_ENTRY; } - /* update */ - zend_hash_index_update(ht, i, &val, sizeof(zval *), NULL); + zval_ptr_dtor(&user_func); + zval_ptr_dtor(&arg_func_name); } + while(0); - return MSGPACK_UNPACK_SUCCESS; -} - -inline static int msgpack_unserialize_object_type( - zval **return_value, msgpack_unserialize_data *mpsd, - php_unserialize_data_t *var_hash, zend_bool is_ref TSRMLS_DC) -{ - int ret = MSGPACK_UNPACK_SUCCESS; - zval *key, *val, **rval; - - ALLOC_INIT_ZVAL(key); - - if (msgpack_unserialize_zval(&key, mpsd, NULL TSRMLS_CC) <= 0) + if (EG(exception)) { - zval_ptr_dtor(&key); - - ZVAL_BOOL(*return_value, 0); + if (MSGPACK_G(error_display)) + { + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_class) " + "Exception error"); + } - return MSGPACK_UNPACK_PARSE_ERROR; + return NULL; } - ALLOC_INIT_ZVAL(val); + object_init_ex(*container, ce); - if (is_ref) - { - ret = msgpack_unserialize_zval(&val, mpsd, NULL TSRMLS_CC); - } - else + /* store incomplete class name */ + if (incomplete_class) { - ret = msgpack_unserialize_zval(&val, mpsd, var_hash TSRMLS_CC); + php_store_class_name(*container, class_name, name_len); } - if (ret <= 0) - { - zval_ptr_dtor(&val); - zval_ptr_dtor(&key); + return ce; +} - ZVAL_BOOL(*return_value, 0); +void msgpack_unserialize_var_init(php_unserialize_data_t *var_hashx) +{ + var_hashx->first = 0; + var_hashx->first_dtor = 0; +} - return MSGPACK_UNPACK_PARSE_ERROR; - } +void msgpack_unserialize_var_destroy(php_unserialize_data_t *var_hashx) +{ + void *next; + long i; + var_entries *var_hash = var_hashx->first; - if (!var_hash || - msgpack_var_access(var_hash, Z_LVAL_P(val) - 1, &rval) != SUCCESS) + while (var_hash) { - if (MSGPACK_G(error_display)) + for (i = 0; i < var_hash->used_slots; i++) { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object_key) " - "Invalid references value: %ld", - Z_LVAL_P(val) - 1); + if (var_hash->alloc_slots[i] && var_hash->data[i]) + { + zval_ptr_dtor(&var_hash->data[i]); + } } - ret = MSGPACK_UNPACK_CONTINUE; + + next = var_hash->next; + efree(var_hash); + var_hash = next; } - else + + /* + var_hash = var_hashx->first_dtor; + + while (var_hash) { - if (*return_value != NULL) + for (i = 0; i < var_hash->used_slots; i++) { - zval_ptr_dtor(return_value); + zval_ptr_dtor(&var_hash->data[i]); } + next = var_hash->next; + efree(var_hash); + var_hash = next; + } + */ +} - *return_value = *rval; +void msgpack_unserialize_init(msgpack_unserialize_data *unpack) +{ + unpack->deps = 0; + unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; +} - Z_ADDREF_PP(return_value); +int msgpack_unserialize_uint8( + msgpack_unserialize_data *unpack, uint8_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - if (is_ref) - { - Z_SET_ISREF_PP(return_value); - } - else - { - Z_UNSET_ISREF_PP(return_value); - } - } + ZVAL_LONG(*obj, data); - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); + return 0; +} + +int msgpack_unserialize_uint16( + msgpack_unserialize_data *unpack, uint16_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - return ret; + ZVAL_LONG(*obj, data); + + return 0; } -inline static int msgpack_unserialize_object( - zval **return_value, msgpack_unserialize_data *mpsd, - ulong ct, php_unserialize_data_t *var_hash TSRMLS_DC) +int msgpack_unserialize_uint32( + msgpack_unserialize_data *unpack, uint32_t data, zval **obj) { - int ret = MSGPACK_UNPACK_SUCCESS; + MSGPACK_UNSERIALIZE_ALLOC(unpack); - zend_class_entry *ce, **pce; - bool incomplete_class = false; - zval *user_func, *retval_ptr, **args[1], *arg_func_name; - HashTable *ht; + ZVAL_LONG(*obj, data); - zval *key, *val; + return 0; +} - int object = 1; - int custom_object = 0; +int msgpack_unserialize_uint64( + msgpack_unserialize_data *unpack, uint64_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - /* Get class */ - ALLOC_INIT_ZVAL(key); + ZVAL_LONG(*obj, data); - if (msgpack_unserialize_zval(&key, mpsd, NULL TSRMLS_CC) <= 0) - { - if (MSGPACK_G(error_display)) - { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "Invalid sign key"); - } + return 0; +} - zval_ptr_dtor(&key); +int msgpack_unserialize_int8( + msgpack_unserialize_data *unpack, int8_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - ZVAL_BOOL(*return_value, 0); + ZVAL_LONG(*obj, data); - return MSGPACK_UNPACK_PARSE_ERROR; - } + return 0; +} - ct--; +int msgpack_unserialize_int16( + msgpack_unserialize_data *unpack, int16_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - if (Z_TYPE_P(key) == IS_NULL) - { - ALLOC_INIT_ZVAL(val); + ZVAL_LONG(*obj, data); - if (msgpack_unserialize_zval(&val, mpsd, NULL TSRMLS_CC) <= 0) - { - if (MSGPACK_G(error_display)) - { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "Invalid sign value"); - } + return 0; +} - zval_ptr_dtor(&val); - zval_ptr_dtor(&key); +int msgpack_unserialize_int32( + msgpack_unserialize_data *unpack, int32_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - ZVAL_BOOL(*return_value, 0); + ZVAL_LONG(*obj, data); - return MSGPACK_UNPACK_PARSE_ERROR; - } + return 0; +} - if (Z_TYPE_P(val) == IS_LONG) - { - switch (Z_LVAL_P(val)) - { - case MSGPACK_SERIALIZE_TYPE_REFERENCE: - ret = msgpack_unserialize_object_type( - return_value, mpsd, var_hash, 1 TSRMLS_CC); +int msgpack_unserialize_int64( + msgpack_unserialize_data *unpack, int64_t data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); + ZVAL_LONG(*obj, data); - return ret; - case MSGPACK_SERIALIZE_TYPE_OBJECT: - ret = msgpack_unserialize_object_type( - return_value, mpsd, var_hash, 0 TSRMLS_CC); + return 0; +} - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); +int msgpack_unserialize_float( + msgpack_unserialize_data *unpack, float data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - return ret; - case MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT: - custom_object = 1; + ZVAL_DOUBLE(*obj, data); - zval_ptr_dtor(&val); + return 0; +} - ALLOC_INIT_ZVAL(val); +int msgpack_unserialize_double( + msgpack_unserialize_data *unpack, double data, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - if (msgpack_unserialize_zval( - &val, mpsd, NULL TSRMLS_CC) <= 0) - { - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); + ZVAL_DOUBLE(*obj, data); - ZVAL_BOOL(*return_value, 0); + return 0; +} - return MSGPACK_UNPACK_PARSE_ERROR; - } - break; - default: - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); +int msgpack_unserialize_nil(msgpack_unserialize_data *unpack, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); - ZVAL_BOOL(*return_value, 0); + ZVAL_NULL(*obj); - return MSGPACK_UNPACK_PARSE_ERROR; - } - } + return 0; +} + +int msgpack_unserialize_true(msgpack_unserialize_data *unpack, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); + + ZVAL_BOOL(*obj, 1); + + return 0; +} + +int msgpack_unserialize_false(msgpack_unserialize_data *unpack, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); + + ZVAL_BOOL(*obj, 0); + + return 0; +} + +int msgpack_unserialize_raw( + msgpack_unserialize_data *unpack, const char* base, + const char* data, unsigned int len, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC(unpack); + + if (len == 0) + { + ZVAL_STRINGL(*obj, "", 0, 1); } else { - object = 0; + ZVAL_STRINGL(*obj, data, len, 1); + } - msgpack_var_push(var_hash, return_value); + return 0; +} - if (Z_TYPE_PP(return_value) != IS_ARRAY) - { - array_init(*return_value); - } +int msgpack_unserialize_array( + msgpack_unserialize_data *unpack, unsigned int count, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC_VALUE(unpack); - ht = HASH_OF(*return_value); + array_init(*obj); - ALLOC_INIT_ZVAL(val); + unpack->stack[unpack->deps++] = count; - if (msgpack_unserialize_zval(&val, mpsd, var_hash TSRMLS_CC) <= 0) - { - if (MSGPACK_G(error_display)) - { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "Invalid sign value"); - } + return 0; +} - zval_ptr_dtor(&val); - zval_ptr_dtor(&key); +int msgpack_unserialize_array_item( + msgpack_unserialize_data *unpack, zval **container, zval *obj) +{ + MSGPACK_UNSERIALIZE_PUSH_ITEM(unpack, 1, obj); - return MSGPACK_UNPACK_PARSE_ERROR; - } + add_next_index_zval(*container, obj); - /* update */ - switch (Z_TYPE_P(key)) - { - case IS_LONG: - zend_hash_index_update( - ht, Z_LVAL_P(key), &val, sizeof(zval *), NULL); - break; - case IS_STRING: - zend_symtable_update( - ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, - &val, sizeof(zval *), NULL); - break; - default: - zval_ptr_dtor(&key); - zval_ptr_dtor(&val); + MSGPACK_UNSERIALIZE_FINISH_ITEM(unpack); - return MSGPACK_UNPACK_PARSE_ERROR; - } - } + return 0; +} - zval_ptr_dtor(&key); +int msgpack_unserialize_map( + msgpack_unserialize_data *unpack, unsigned int count, zval **obj) +{ + MSGPACK_UNSERIALIZE_ALLOC_VALUE(unpack); - if (object) - { - convert_to_string(val); + unpack->stack[unpack->deps++] = count; - do { - /* Try to find class directly */ - if (zend_lookup_class( - Z_STRVAL_P(val), Z_STRLEN_P(val), &pce TSRMLS_CC) == SUCCESS) - { - ce = *pce; - break; - } + unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; - /* Check for unserialize callback */ - if ((PG(unserialize_callback_func) == NULL) || - (PG(unserialize_callback_func)[0] == '\0')) - { - incomplete_class = 1; - ce = PHP_IC_ENTRY; - break; - } + return 0; +} - /* Call unserialize callback */ - ALLOC_INIT_ZVAL(user_func); - ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); - args[0] = &arg_func_name; - ALLOC_INIT_ZVAL(arg_func_name); - ZVAL_STRING(arg_func_name, Z_STRVAL_P(val), 1); - if (call_user_function_ex( - CG(function_table), NULL, user_func, &retval_ptr, - 1, args, 0, NULL TSRMLS_CC) != SUCCESS) - { - if (MSGPACK_G(error_display)) - { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "defined (%s) but not found", Z_STRVAL_P(val)); - } +int msgpack_unserialize_map_item( + msgpack_unserialize_data *unpack, zval **container, zval *key, zval *val) +{ + TSRMLS_FETCH(); - incomplete_class = 1; - ce = PHP_IC_ENTRY; - zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); - break; - } - if (retval_ptr) - { - zval_ptr_dtor(&retval_ptr); - } + if (MSGPACK_G(php_only)) + { + if (Z_TYPE_P(key) == IS_NULL) + { + unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; - /* The callback function may have defined the class */ - if (zend_lookup_class( - Z_STRVAL_P(val), Z_STRLEN_P(val), &pce TSRMLS_CC) == SUCCESS) - { - ce = *pce; - } - else + if (Z_TYPE_P(val) == IS_LONG) { - if (MSGPACK_G(error_display)) + switch (Z_LVAL_P(val)) { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "Function %s() hasn't defined the class" - "it was called for", Z_STRVAL_P(val)); + case MSGPACK_SERIALIZE_TYPE_REFERENCE: + Z_SET_ISREF_PP(container); + break; + case MSGPACK_SERIALIZE_TYPE_RECURSIVE: + unpack->type = MSGPACK_SERIALIZE_TYPE_RECURSIVE; + break; + case MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT: + unpack->type = MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT; + break; + default: + break; } - - incomplete_class = true; - ce = PHP_IC_ENTRY; } + else if (Z_TYPE_P(val) == IS_STRING) + { + zend_class_entry *ce = msgpack_unserialize_class( + container, Z_STRVAL_P(val), Z_STRLEN_P(val)); - zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); - } while(0); + if (ce == NULL) + { + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - if (EG(exception)) - { - if (MSGPACK_G(error_display)) - { - zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " - "Exception error"); + return 0; + } } - zval_ptr_dtor(&val); - - ZVAL_BOOL(*return_value, 0); + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - return MSGPACK_UNPACK_PARSE_ERROR; + return 0; } - - msgpack_var_push(var_hash, return_value); - - object_init_ex(*return_value, ce); - - /* store incomplete class name */ - if (incomplete_class) + else if (unpack->type == MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT) { - php_store_class_name( - *return_value, Z_STRVAL_P(val), Z_STRLEN_P(val)); - } + unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; - zval_ptr_dtor(&val); + zend_class_entry *ce = msgpack_unserialize_class( + container, Z_STRVAL_P(key), Z_STRLEN_P(key)); - /* implementing Serializable */ - if (custom_object) - { - zval *rval; + if (ce == NULL) + { + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); + return 0; + } + + /* implementing Serializable */ if (ce->unserialize == NULL) { if (MSGPACK_G(error_display)) { zend_error(E_WARNING, - "[msgpack] (msgpack_unserialize_object) " + "[msgpack] (msgpack_unserialize_map_item) " "Class %s has no unserializer", ce->name); } - return MSGPACK_UNPACK_PARSE_ERROR; - } + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - /* value */ - ALLOC_INIT_ZVAL(rval); - - if (msgpack_unserialize_zval(&rval, mpsd, var_hash TSRMLS_CC) <= 0) - { - zval_ptr_dtor(&rval); - - return MSGPACK_UNPACK_PARSE_ERROR; + return 0; } ce->unserialize( - return_value, ce, - (const unsigned char *)Z_STRVAL_P(rval), Z_STRLEN_P(rval) + 1, - (zend_unserialize_data *)var_hash TSRMLS_CC); + container, ce, + (const unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val) + 1, + NULL TSRMLS_CC); - zval_ptr_dtor(&key); - zval_ptr_dtor(&rval); + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - return ret; + return 0; } - - ht = HASH_OF(*return_value); - } - - /* object property */ - while (ct-- > 0) - { - zval *rval; - - /* key */ - ALLOC_INIT_ZVAL(key); - - if (msgpack_unserialize_zval(&key, mpsd, NULL TSRMLS_CC) <= 0) + else if (unpack->type == MSGPACK_SERIALIZE_TYPE_RECURSIVE) { - zval_ptr_dtor(&key); - - return MSGPACK_UNPACK_PARSE_ERROR; - } + zval **rval; - /* value */ - ALLOC_INIT_ZVAL(rval); + unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; - if (msgpack_unserialize_zval(&rval, mpsd, var_hash TSRMLS_CC) <= 0) - { - zval_ptr_dtor(&rval); - zval_ptr_dtor(&key); + if (msgpack_var_access( + unpack->var_hash, Z_LVAL_P(val) - 1, &rval) != SUCCESS) + { + if (MSGPACK_G(error_display)) + { + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_map_item) " + "Invalid references value: %ld", + Z_LVAL_P(val) - 1); + } - return MSGPACK_UNPACK_PARSE_ERROR; + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - } + return 0; + } - /* update */ - switch (Z_TYPE_P(key)) - { - case IS_LONG: - zend_hash_index_update( - ht, Z_LVAL_P(key), &rval, sizeof(zval *), NULL); - break; - case IS_STRING: - zend_symtable_update( - ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, - &rval, sizeof(zval *), NULL); - break; - default: - zval_ptr_dtor(&key); - zval_ptr_dtor(&rval); + if (container != NULL) + { + zval_ptr_dtor(container); + } - return MSGPACK_UNPACK_PARSE_ERROR; - } + *container = *rval; - zval_ptr_dtor(&key); - } + Z_ADDREF_PP(container); - /* wakeup */ - if (object && Z_OBJCE_PP(return_value) != PHP_IC_ENTRY && - zend_hash_exists(&Z_OBJCE_PP(return_value)->function_table, - "__wakeup", sizeof("__wakeup"))) - { - zval f, *h = NULL; + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); - INIT_PZVAL(&f); - ZVAL_STRINGL(&f, "__wakeup", sizeof("__wakeup") - 1, 0); - call_user_function_ex( - CG(function_table), return_value, &f, &h, 0, 0, 1, NULL TSRMLS_CC); - if (h) - { - zval_ptr_dtor(&h); - } - - if (EG(exception)) - { - ret = MSGPACK_UNPACK_PARSE_ERROR; + return 0; } } - return ret; -} + MSGPACK_UNSERIALIZE_PUSH_ITEM(unpack, 2, val); -int msgpack_unserialize_zval( - zval **return_value, msgpack_unserialize_data *mpsd, - php_unserialize_data_t *var_hash TSRMLS_DC) -{ - const unsigned char* data = mpsd->data; - const unsigned char* const pe = mpsd->data + mpsd->length; - const void* n = NULL; - - unsigned int trail = 0; - unsigned int cs = CS_HEADER; - - int ret; - unsigned int ct; - -#define next_cs(p) ((unsigned int)*p & 0x1f) - -#define finish_zval_long(val_) \ - msgpack_var_push(var_hash, return_value); \ - ZVAL_LONG(*return_value, val_); \ - goto _finish - -#define finish_zval_null() \ - msgpack_var_push(var_hash, return_value); \ - ZVAL_NULL(*return_value); \ - goto _finish - -#define finish_zval_bool(val_) \ - msgpack_var_push(var_hash, return_value); \ - ZVAL_BOOL(*return_value, val_); \ - goto _finish - -#define finish_zval_double(val_) \ - msgpack_var_push(var_hash, return_value); \ - ZVAL_DOUBLE(*return_value, val_); \ - goto _finish - -#define finish_zval_string(val_, len_) \ - msgpack_var_push(var_hash, return_value); \ - if (len_ == 0) { ZVAL_STRINGL(*return_value, "", 0, 1); } \ - else { ZVAL_STRINGL(*return_value, val_, len_, 1); } \ - goto _finish - -#define finish_zval_array(count_) \ - ct = count_; \ - cs = CS_HEADER; \ - ++(mpsd->data); \ - mpsd->length = (pe - mpsd->data); \ - if (msgpack_unserialize_array(return_value, mpsd, ct, var_hash TSRMLS_CC) <= 0) { goto _failed; } \ - goto _finish_end - -#define finish_zval_object(count_) \ - ct = count_; \ - cs = CS_HEADER; \ - ++(mpsd->data); \ - mpsd->length = (pe - mpsd->data); \ - if (msgpack_unserialize_object(return_value, mpsd, ct, var_hash TSRMLS_CC) <= 0) { goto _failed; } \ - goto _finish_end - -#define again_fixed_trail(_cs, trail_len) \ - trail = trail_len; \ - cs = _cs; \ - goto _fixed_trail_again - -#define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \ - trail = trail_len; \ - if(trail == 0) { goto ifzero; } \ - cs = _cs; \ - goto _fixed_trail_again - - if (mpsd->length <= 0) + if (Z_TYPE_PP(container) != IS_ARRAY && Z_TYPE_PP(container) != IS_OBJECT) { - goto _failed; + array_init(*container); } - if (mpsd->data == pe) - { - goto _out; - } - do + switch (Z_TYPE_P(key)) { - switch (cs) - { - case CS_HEADER: - switch (*(mpsd->data)) - { - case 0x00 ... 0x7f: /* Positive Fixnum */ - finish_zval_long(*(uint8_t*)mpsd->data); - case 0xe0 ... 0xff: /* Negative Fixnum */ - finish_zval_long(*(int8_t*)mpsd->data); - case 0xc0 ... 0xdf: /* Variable */ - switch (*(mpsd->data)) - { - case 0xc0: /* nil */ - finish_zval_null(); - case 0xc2: /* false */ - finish_zval_bool(0); - case 0xc3: /* true */ - finish_zval_bool(1); - case 0xca: /* float */ - case 0xcb: /* double */ - case 0xcc: /* unsigned int 8 */ - case 0xcd: /* unsigned int 16 */ - case 0xce: /* unsigned int 32 */ - case 0xcf: /* unsigned int 64 */ - case 0xd0: /* signed int 8 */ - case 0xd1: /* signed int 16 */ - case 0xd2: /* signed int 32 */ - case 0xd3: /* signed int 64 */ - again_fixed_trail( - next_cs(mpsd->data), - 1 << (((unsigned int)*(mpsd->data)) & 0x03)); - case 0xda: /* raw 16 */ - case 0xdb: /* raw 32 */ - case 0xdc: /* array 16 */ - case 0xdd: /* array 32 */ - case 0xde: /* map 16 */ - case 0xdf: /* map 32 */ - again_fixed_trail( - next_cs(mpsd->data), - 2 << (((unsigned int)*(mpsd->data)) & 0x01)); - default: - goto _failed; - } - case 0xa0 ... 0xbf: /* FixRaw */ - again_fixed_trail_if_zero( - ACS_RAW_VALUE, (unsigned int)*(mpsd->data) & 0x1f, - _raw_zero); - case 0x90 ... 0x9f: /* FixArray */ - finish_zval_array(((unsigned int)*(mpsd->data)) & 0x0f); - case 0x80 ... 0x8f: /* FixMap */ - finish_zval_object(((unsigned int)*(mpsd->data)) & 0x0f); - default: - goto _failed; - } -_fixed_trail_again: - ++(mpsd->data); - default: - if ((size_t)(pe - (mpsd->data)) < trail) + case IS_LONG: + if (zend_hash_index_update( + HASH_OF(*container), Z_LVAL_P(key), &val, + sizeof(val), NULL) == FAILURE) + { + zval_ptr_dtor(&val); + if (MSGPACK_G(error_display)) { - goto _out; + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_map_item) " + "illegal offset type, skip this decoding"); } - n = (mpsd->data); - mpsd->data += trail - 1; - switch (cs) + } + break; + case IS_STRING: + if (zend_symtable_update( + HASH_OF(*container), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, + &val, sizeof(val), NULL) == FAILURE) + { + zval_ptr_dtor(&val); + if (MSGPACK_G(error_display)) { - case CS_FLOAT: - { - union { uint32_t i; float f; } mem; - mem.i = _msgpack_load32(uint32_t, n); - finish_zval_double(mem.f); - } - case CS_DOUBLE: - { - union { uint64_t i; double f; } mem; - mem.i = _msgpack_load64(uint64_t, n); - finish_zval_double(mem.f); - } - case CS_UINT_8: - finish_zval_long(*(uint8_t*)n); - case CS_UINT_16: - finish_zval_long(_msgpack_load16(uint16_t, n)); - case CS_UINT_32: - finish_zval_long(_msgpack_load32(uint32_t, n)); - case CS_UINT_64: - finish_zval_long(_msgpack_load64(uint64_t, n)); - case CS_INT_8: - finish_zval_long(*(int8_t*)n); - case CS_INT_16: - finish_zval_long(_msgpack_load16(int16_t, n)); - case CS_INT_32: - finish_zval_long(_msgpack_load32(int32_t, n)); - case CS_INT_64: - finish_zval_long(_msgpack_load64(int64_t, n)); - case CS_RAW_16: - again_fixed_trail_if_zero( - ACS_RAW_VALUE, _msgpack_load16(uint16_t, n), - _raw_zero); - case CS_RAW_32: - again_fixed_trail_if_zero( - ACS_RAW_VALUE, _msgpack_load32(uint32_t, n), - _raw_zero); - case ACS_RAW_VALUE: -_raw_zero: - finish_zval_string(n, trail); - case CS_ARRAY_16: - finish_zval_array(_msgpack_load16(uint16_t, n)); - case CS_ARRAY_32: - finish_zval_array(_msgpack_load32(uint32_t, n)); - /* FIXME security guard */ - case CS_MAP_16: - finish_zval_object(_msgpack_load16(uint16_t, n)); - case CS_MAP_32: - finish_zval_object(_msgpack_load32(uint32_t, n)); - /* FIXME security guard */ - default: - goto _failed; + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_map_item) " + "illegal offset type, skip this decoding"); } - } - cs = CS_HEADER; - ++(mpsd->data); + } + break; + default: + zval_ptr_dtor(&val); + if (MSGPACK_G(error_display)) + { + zend_error(E_WARNING, + "[msgpack] (msgpack_unserialize_map_item) " + "illegal offset type, skip this decoding"); + } + break; } - while (mpsd->data != pe); - goto _out; - -_finish: - ++(mpsd->data); -_finish_end: - ret = MSGPACK_UNPACK_EXTRA_BYTES; - goto _end; -_failed: - ret = MSGPACK_UNPACK_PARSE_ERROR; - goto _end; - -_out: - ret = MSGPACK_UNPACK_CONTINUE; - goto _end; - -_end: - mpsd->offset = mpsd->data - data; - mpsd->length = pe - mpsd->data; + zval_ptr_dtor(&key); - if (ret == MSGPACK_UNPACK_EXTRA_BYTES && mpsd->length == 0) + long deps = unpack->deps - 1; + unpack->stack[deps]--; + if (unpack->stack[deps] == 0) { - ret = MSGPACK_UNPACK_SUCCESS; + unpack->deps--; + + /* wakeup */ + if (MSGPACK_G(php_only) && + Z_TYPE_PP(container) == IS_OBJECT && + Z_OBJCE_PP(container) != PHP_IC_ENTRY && + zend_hash_exists( + &Z_OBJCE_PP(container)->function_table, + "__wakeup", sizeof("__wakeup"))) + { + zval f, *h = NULL; + + INIT_PZVAL(&f); + ZVAL_STRINGL(&f, "__wakeup", sizeof("__wakeup") - 1, 0); + call_user_function_ex( + CG(function_table), container, &f, &h, 0, 0, 1, NULL TSRMLS_CC); + if (h) + { + zval_ptr_dtor(&h); + } + } } - return ret; + return 0; } - -#undef finish_zval_long -#undef finish_zval_null -#undef finish_zval_bool -#undef finish_zval_double -#undef finish_zval_string -#undef finish_zval_array -#undef finish_zval_object -#undef again_fixed_trail -#undef again_fixed_trail_if_zero - -#undef next_cs |
