int msgpack_convert_object(zval *return_value, zval *tpl, zval **value) { zend_class_entry *ce, **pce; TSRMLS_FETCH(); switch (Z_TYPE_P(tpl)) { case IS_STRING: if (zend_lookup_class( Z_STRVAL_P(tpl), Z_STRLEN_P(tpl), &pce TSRMLS_CC) != SUCCESS) { MSGPACK_ERROR("[msgpack] (%s) Class '%s' not found", __FUNCTION__, Z_STRVAL_P(tpl)); return FAILURE; } ce = *pce; break; case IS_OBJECT: ce = zend_get_class_entry(tpl TSRMLS_CC); break; default: MSGPACK_ERROR("[msgpack] (%s) object type is unsupported", __FUNCTION__); return FAILURE; } if (Z_TYPE_PP(value) == IS_OBJECT) { zend_class_entry *vce; vce = zend_get_class_entry(*value TSRMLS_CC); if (strcmp(ce->name, vce->name) == 0) { *return_value = **value; zval_copy_ctor(return_value); zval_ptr_dtor(value); return SUCCESS; } } object_init_ex(return_value, ce); /* Run the constructor if there is one */ if (ce->constructor && (ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { zval *retval_ptr = NULL; zval ***params = NULL; int num_args = 0; zend_fcall_info fci; zend_fcall_info_cache fcc; #if ZEND_MODULE_API_NO >= 20090626 fci.size = sizeof(fci); fci.function_table = EG(function_table); fci.function_name = NULL; fci.symbol_table = NULL; fci.object_ptr = return_value; fci.retval_ptr_ptr = &retval_ptr; fci.param_count = num_args; fci.params = params; fci.no_separation = 1; fcc.initialized = 1; fcc.function_handler = ce->constructor; fcc.calling_scope = EG(scope); fcc.called_scope = Z_OBJCE_P(return_value); fcc.object_ptr = return_value; #else fci.size = sizeof(fci); fci.function_table = EG(function_table); fci.function_name = NULL; fci.symbol_table = NULL; fci.object_pp = &return_value; fci.retval_ptr_ptr = &retval_ptr; fci.param_count = num_args; fci.params = params; fci.no_separation = 1; fcc.initialized = 1; fcc.function_handler = ce->constructor; fcc.calling_scope = EG(scope); fcc.object_pp = &return_value; #endif if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { if (params) { efree(params); } if (retval_ptr) { zval_ptr_dtor(&retval_ptr); } MSGPACK_WARNING( "[msgpack] (%s) Invocation of %s's constructor failed", __FUNCTION__, ce->name); return FAILURE; } if (retval_ptr) { zval_ptr_dtor(&retval_ptr); } if (params) { efree(params); } } switch (Z_TYPE_PP(value)) { case IS_ARRAY: { char *key; uint key_len; int key_type; ulong key_index; zval **data; HashPosition pos; HashTable *ht, *ret; HashTable *var = NULL; int num; ht = HASH_OF(*value); ret = HASH_OF(return_value); num = zend_hash_num_elements(ht); if (num <= 0) { zval_ptr_dtor(value); break; } /* string - php_only mode? */ if (ht->nNumOfElements != ht->nNextFreeElement || ht->nNumOfElements != ret->nNumOfElements) { HashTable *properties = NULL; HashPosition prop_pos; ALLOC_HASHTABLE(var); zend_hash_init(var, num, NULL, NULL, 0); zend_hash_internal_pointer_reset_ex(ht, &pos); for (;; zend_hash_move_forward_ex(ht, &pos)) { key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { continue; } if (key_type == HASH_KEY_IS_STRING) { zval *val; MSGPACK_CONVERT_COPY_ZVAL(val, data); if (msgpack_convert_string_to_properties( return_value, key, key_len, val, var) != SUCCESS) { zval_ptr_dtor(&val); MSGPACK_WARNING( "[msgpack] (%s) " "illegal offset type, skip this decoding", __FUNCTION__); } } } /* index */ properties = Z_OBJ_HT_P(return_value)->get_properties( return_value TSRMLS_CC); if (HASH_OF(tpl)) { properties = HASH_OF(tpl); } zend_hash_internal_pointer_reset_ex(properties, &prop_pos); zend_hash_internal_pointer_reset_ex(ht, &pos); for (;; zend_hash_move_forward_ex(ht, &pos)) { key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { continue; } switch (key_type) { case HASH_KEY_IS_LONG: { zval *val; MSGPACK_CONVERT_COPY_ZVAL(val, data); if (msgpack_convert_long_to_properties( ret, &properties, &prop_pos, key_index, val, var) != SUCCESS) { zval_ptr_dtor(&val); MSGPACK_WARNING( "[msgpack] (%s) " "illegal offset type, skip this decoding", __FUNCTION__); } break; } case HASH_KEY_IS_STRING: break; default: MSGPACK_WARNING( "[msgpack] (%s) key is not string nor array", __FUNCTION__); break; } } zend_hash_destroy(var); FREE_HASHTABLE(var); } else { HashPosition valpos; int (*convert_function)(zval *, zval *, zval **) = NULL; zval **arydata, *aryval; /* index */ zend_hash_internal_pointer_reset_ex(ret, &pos); zend_hash_internal_pointer_reset_ex(ht, &valpos); for (;; zend_hash_move_forward_ex(ret, &pos), zend_hash_move_forward_ex(ht, &valpos)) { key_type = zend_hash_get_current_key_ex( ret, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ret, (void *)&data, &pos) != SUCCESS) { continue; } switch (Z_TYPE_PP(data)) { case IS_ARRAY: convert_function = msgpack_convert_array; break; case IS_OBJECT: //case IS_STRING: -- may have default values of // class members, so it's not wise to allow convert_function = msgpack_convert_object; break; default: break; } if (zend_hash_get_current_data_ex( ht, (void *)&arydata, &valpos) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) can't get data value by index", __FUNCTION__); return FAILURE; } MSGPACK_CONVERT_COPY_ZVAL(aryval, arydata); if (convert_function) { zval *rv; ALLOC_INIT_ZVAL(rv); if (convert_function(rv, *data, &aryval) != SUCCESS) { zval_ptr_dtor(&aryval); MSGPACK_WARNING( "[msgpack] (%s) " "convert failure in convert_object", __FUNCTION__); return FAILURE; } zend_symtable_update( ret, key, key_len, &rv, sizeof(rv), NULL); } else { zend_symtable_update( ret, key, key_len, &aryval, sizeof(aryval), NULL); } } } zval_ptr_dtor(value); break; } default: { HashTable *properties = NULL; HashPosition prop_pos; properties = Z_OBJ_HT_P(return_value)->get_properties( return_value TSRMLS_CC); zend_hash_internal_pointer_reset_ex(properties, &prop_pos); if (msgpack_convert_long_to_properties( HASH_OF(return_value), &properties, &prop_pos, 0, *value, NULL) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) illegal offset type, skip this decoding", __FUNCTION__); } break; } } return SUCCESS; }
int msgpack_convert_array(zval *return_value, zval *tpl, zval **value) { TSRMLS_FETCH(); if (Z_TYPE_P(tpl) == IS_ARRAY) { char *key; uint key_len; int key_type; ulong key_index; zval **data, **arydata; HashPosition pos, valpos; HashTable *ht, *htval; int num; ht = HASH_OF(tpl); // TODO: maybe need to release memory? array_init(return_value); num = zend_hash_num_elements(ht); if (num <= 0) { MSGPACK_WARNING( "[msgpack] (%s) template array length is 0", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } /* string */ if (ht->nNumOfElements != ht->nNextFreeElement) { htval = HASH_OF(*value); if (!htval) { MSGPACK_WARNING( "[msgpack] (%s) input data is not array", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } zend_hash_internal_pointer_reset_ex(ht, &pos); zend_hash_internal_pointer_reset_ex(htval, &valpos); for (;; zend_hash_move_forward_ex(ht, &pos), zend_hash_move_forward_ex(htval, &valpos)) { key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { continue; } if (key_type == HASH_KEY_IS_STRING) { int (*convert_function)(zval *, zval *, zval **) = NULL; zval **dataval, *val; switch (Z_TYPE_PP(data)) { case IS_ARRAY: convert_function = msgpack_convert_array; break; case IS_OBJECT: // case IS_STRING: convert_function = msgpack_convert_object; break; default: break; } if (zend_hash_get_current_data_ex( htval, (void *)&dataval, &valpos) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) can't get data", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } MSGPACK_CONVERT_COPY_ZVAL(val, dataval); if (convert_function) { zval *rv; ALLOC_INIT_ZVAL(rv); if (convert_function(rv, *data, &val) != SUCCESS) { zval_ptr_dtor(&val); return FAILURE; } add_assoc_zval_ex(return_value, key, key_len, rv); } else { add_assoc_zval_ex(return_value, key, key_len, val); } } } zval_ptr_dtor(value); return SUCCESS; } else { /* index */ int (*convert_function)(zval *, zval *, zval **) = NULL; if (Z_TYPE_PP(value) != IS_ARRAY) { MSGPACK_WARNING( "[msgpack] (%s) unserialized data must be array.", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } zend_hash_internal_pointer_reset_ex(ht, &pos); key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { MSGPACK_WARNING( "[msgpack] (%s) first element in template array is empty", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) invalid template: empty array?", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } switch (Z_TYPE_PP(data)) { case IS_ARRAY: convert_function = msgpack_convert_array; break; case IS_OBJECT: case IS_STRING: convert_function = msgpack_convert_object; break; default: break; } htval = HASH_OF(*value); num = zend_hash_num_elements(htval); if (num <= 0) { MSGPACK_WARNING( "[msgpack] (%s) array length is 0 in unserialized data", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } zend_hash_internal_pointer_reset_ex(htval, &valpos); for (;; zend_hash_move_forward_ex(htval, &valpos)) { key_type = zend_hash_get_current_key_ex( htval, &key, &key_len, &key_index, 0, &valpos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( htval, (void *)&arydata, &valpos) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) can't get next data in indexed array", __FUNCTION__); continue; } switch (key_type) { case HASH_KEY_IS_LONG: { zval *aryval, *rv; ALLOC_INIT_ZVAL(rv); MSGPACK_CONVERT_COPY_ZVAL(aryval, arydata); if (convert_function) { if (convert_function(rv, *data, &aryval) != SUCCESS) { zval_ptr_dtor(&aryval); MSGPACK_WARNING( "[msgpack] (%s) " "convert failure in HASH_KEY_IS_LONG " "in indexed array", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } add_next_index_zval(return_value, rv); } else { add_next_index_zval(return_value, aryval); } break; } case HASH_KEY_IS_STRING: MSGPACK_WARNING( "[msgpack] (%s) key is string", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; default: MSGPACK_WARNING( "[msgpack] (%s) key is not string nor array", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } } zval_ptr_dtor(value); return SUCCESS; } } else { // shouldn't reach MSGPACK_WARNING( "[msgpack] (%s) template is not array", __FUNCTION__); zval_ptr_dtor(value); return FAILURE; } // shouldn't reach zval_ptr_dtor(value); return FAILURE; }
inline int msgpack_convert_long_to_properties( HashTable *ht, HashTable **properties, HashPosition *prop_pos, uint key_index, zval *val, HashTable *var) { TSRMLS_FETCH(); if (*properties != NULL) { char *prop_key; uint prop_key_len; ulong prop_key_index; zval **data = NULL; zval *tplval = NULL; zval **dataval = NULL; for (;; zend_hash_move_forward_ex(*properties, prop_pos)) { if (zend_hash_get_current_key_ex( *properties, &prop_key, &prop_key_len, &prop_key_index, 0, prop_pos) == HASH_KEY_IS_STRING) { if (var == NULL || !zend_hash_exists(var, prop_key, prop_key_len)) { if (zend_hash_find( ht, prop_key, prop_key_len, (void **)&data) == SUCCESS) { switch (Z_TYPE_PP(data)) { case IS_ARRAY: { HashTable *dataht; dataht = HASH_OF(val); if (zend_hash_index_find( dataht, prop_key_index, (void **)dataval) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) " "can't get data value by index", __FUNCTION__); return FAILURE; } ALLOC_INIT_ZVAL(tplval); if (msgpack_convert_array( tplval, *data, dataval) == SUCCESS) { zend_hash_move_forward_ex( *properties, prop_pos); return zend_symtable_update( ht, prop_key, prop_key_len, &tplval, sizeof(tplval), NULL); } // TODO: de we need to call dtor? return FAILURE; break; } case IS_OBJECT: { ALLOC_INIT_ZVAL(tplval); if (msgpack_convert_object( tplval, *data, &val) == SUCCESS) { zend_hash_move_forward_ex( *properties, prop_pos); return zend_symtable_update( ht, prop_key, prop_key_len, &tplval, sizeof(tplval), NULL); } // TODO: de we need to call dtor? return FAILURE; break; } default: zend_hash_move_forward_ex(*properties, prop_pos); return zend_symtable_update( ht, prop_key, prop_key_len, &val, sizeof(val), NULL); break; } } } } else { break; } } *properties = NULL; } return zend_hash_index_update(ht, key_index, &val, sizeof(val), NULL); }
static inline int msgpack_convert_long_to_properties(HashTable *ht, zval *object, HashTable **properties, HashPosition *prop_pos, uint key_index, zval *val, HashTable *var) /* {{{ */ { zval key_zv; HashTable *props = *properties; if (props != NULL) { zval *data, tplval, *dataval, prop_key_zv; zend_string *prop_key; ulong prop_key_index; const char *class_name, *prop_name; size_t prop_len; for (;; zend_hash_move_forward_ex(props, prop_pos)) { if (zend_hash_get_current_key_ex(props, &prop_key, &prop_key_index, prop_pos) == HASH_KEY_IS_STRING) { zend_unmangle_property_name_ex(prop_key, &class_name, &prop_name, &prop_len); ZVAL_NEW_STR(&prop_key_zv, prop_key); if (var == NULL || !zend_hash_str_exists(var, prop_name, prop_len)) { if ((data = zend_hash_find(ht, prop_key)) != NULL) { switch (Z_TYPE_P(data)) { case IS_ARRAY: { HashTable *dataht; dataht = HASH_OF(val); if ((dataval = zend_hash_index_find(dataht, prop_key_index)) == NULL) { MSGPACK_WARNING("[msgpack] (%s) " "can't get data value by index", __FUNCTION__); return FAILURE; } if (msgpack_convert_array(&tplval, data, dataval) == SUCCESS) { zend_hash_move_forward_ex(props, prop_pos); zend_update_property(Z_OBJCE_P(object), object, prop_name, prop_len, &tplval); return SUCCESS; } return FAILURE; } case IS_OBJECT: { if (msgpack_convert_object(&tplval, data, val) == SUCCESS) { zend_hash_move_forward_ex(props, prop_pos); zend_update_property(Z_OBJCE_P(object), object, prop_name, prop_len, &tplval); return SUCCESS; } return FAILURE; } default: zend_hash_move_forward_ex(props, prop_pos); zend_update_property(Z_OBJCE_P(object), object, prop_name, prop_len, val); return SUCCESS; } } } } else { break; } } *properties = NULL; } ZVAL_LONG(&key_zv, key_index); zend_std_write_property(object, &key_zv, val, NULL); return SUCCESS; }
int msgpack_convert_array(zval *return_value, zval *tpl, zval *value) /* {{{ */ { zend_string *key; int key_type; ulong key_index; zval *data; HashTable *ht, *htval; if (Z_TYPE_P(tpl) != IS_ARRAY) { MSGPACK_WARNING("[msgpack] (%s) template is not array", __FUNCTION__); return FAILURE; } if (Z_TYPE_P(value) == IS_INDIRECT) { value = Z_INDIRECT_P(value); } ht = HASH_OF(tpl); array_init(return_value); if (zend_hash_num_elements(ht) == 0) { MSGPACK_WARNING("[msgpack] (%s) template array length is 0", __FUNCTION__); return FAILURE; } /* string */ if (ht->nNumOfElements != ht->nNextFreeElement) { HashPosition valpos; htval = HASH_OF(value); if (!htval) { MSGPACK_WARNING("[msgpack] (%s) input data is not array", __FUNCTION__); return FAILURE; } zend_hash_internal_pointer_reset_ex(htval, &valpos); ZEND_HASH_FOREACH_KEY_VAL(ht, key_index, key, data) { if (key) { zval *dataval; int (*convert_function)(zval *, zval *, zval *) = NULL; switch (Z_TYPE_P(data)) { case IS_ARRAY: convert_function = msgpack_convert_array; break; case IS_OBJECT: // case IS_STRING: convert_function = msgpack_convert_object; break; default: break; } if ((dataval = zend_hash_get_current_data_ex(htval, &valpos)) == NULL) { MSGPACK_WARNING("[msgpack] (%s) can't get data", __FUNCTION__); return FAILURE; } if (Z_TYPE_P(dataval) == IS_INDIRECT) { dataval = Z_INDIRECT_P(dataval); } if (convert_function) { zval rv; if (convert_function(&rv, data, dataval) != SUCCESS) { return FAILURE; } zend_symtable_update(Z_ARRVAL_P(return_value), key, &rv); } else { Z_TRY_ADDREF_P(dataval); zend_symtable_update(Z_ARRVAL_P(return_value), key, dataval); } } zend_hash_move_forward_ex(htval, &valpos); } ZEND_HASH_FOREACH_END(); return SUCCESS; } else {
int msgpack_unserialize_map_item( msgpack_unserialize_data *unpack, zval **container, zval *key, zval *val) { long deps; TSRMLS_FETCH(); if (MSGPACK_G(php_only)) { zend_class_entry *ce; if (Z_TYPE_P(key) == IS_NULL) { unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; if (Z_TYPE_P(val) == IS_LONG) { switch (Z_LVAL_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; case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE: unpack->type = MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE; break; case MSGPACK_SERIALIZE_TYPE_OBJECT: unpack->type = MSGPACK_SERIALIZE_TYPE_OBJECT; break; default: break; } } else if (Z_TYPE_P(val) == IS_STRING) { ce = msgpack_unserialize_class( container, Z_STRVAL_P(val), Z_STRLEN_P(val)); if (ce == NULL) { MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } } MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } else { switch (unpack->type) { case MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT: unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; ce = msgpack_unserialize_class( container, Z_STRVAL_P(key), Z_STRLEN_P(key)); if (ce == NULL) { MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0) /* implementing Serializable */ if (ce->unserialize == NULL) { MSGPACK_WARNING( "[msgpack] (%s) Class %s has no unserializer", __FUNCTION__, ce->name); MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } ce->unserialize( container, ce, (const unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val) + 1, NULL TSRMLS_CC); #endif MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; case MSGPACK_SERIALIZE_TYPE_RECURSIVE: case MSGPACK_SERIALIZE_TYPE_OBJECT: case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE: { zval **rval; int type = unpack->type; unpack->type = MSGPACK_SERIALIZE_TYPE_NONE; if (msgpack_var_access( unpack->var_hash, Z_LVAL_P(val) - 1, &rval) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) Invalid references value: %ld", __FUNCTION__, Z_LVAL_P(val) - 1); MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } if (container != NULL) { zval_ptr_dtor(container); } *container = *rval; Z_ADDREF_PP(container); if (type == MSGPACK_SERIALIZE_TYPE_OBJECT) { Z_UNSET_ISREF_PP(container); } else if (type == MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE) { Z_SET_ISREF_PP(container); } MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); return 0; } } } } if (Z_TYPE_PP(container) != IS_ARRAY && Z_TYPE_PP(container) != IS_OBJECT) { array_init(*container); } switch (Z_TYPE_P(key)) { case IS_LONG: if (zend_hash_index_update( HASH_OF(*container), Z_LVAL_P(key), &val, sizeof(val), NULL) == FAILURE) { zval_ptr_dtor(&val); MSGPACK_WARNING( "[msgpack] (%s) illegal offset type, skip this decoding", __FUNCTION__); } zval_ptr_dtor(&key); 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); MSGPACK_WARNING( "[msgpack] (%s) illegal offset type, skip this decoding", __FUNCTION__); } zval_ptr_dtor(&key); break; default: MSGPACK_WARNING("[msgpack] (%s) illegal key type", __FUNCTION__); if (MSGPACK_G(illegal_key_insert)) { if (zend_hash_next_index_insert( HASH_OF(*container), &key, sizeof(key), NULL) == FAILURE) { zval_ptr_dtor(&val); } if (zend_hash_next_index_insert( HASH_OF(*container), &val, sizeof(val), NULL) == FAILURE) { zval_ptr_dtor(&val); } } else { convert_to_string(key); 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); } zval_ptr_dtor(&key); } break; } msgpack_stack_pop(unpack->var_hash, 2); deps = unpack->deps - 1; unpack->stack[deps]--; if (unpack->stack[deps] == 0) { 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 0; }
inline static zend_class_entry* msgpack_unserialize_class( zval **container, char *class_name, size_t name_len) { zend_class_entry *ce, **pce; zend_bool incomplete_class = 0; zval *user_func, *retval_ptr, **args[1], *arg_func_name; TSRMLS_FETCH(); do { /* Try to find class directly */ if (zend_lookup_class(class_name, name_len, &pce TSRMLS_CC) == SUCCESS) { ce = *pce; break; } /* Check for unserialize callback */ if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } /* 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) { MSGPACK_WARNING("[msgpack] (%s) defined (%s) but not found", __FUNCTION__, class_name); 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); } /* The callback function may have defined the class */ if (zend_lookup_class(class_name, name_len, &pce TSRMLS_CC) == SUCCESS) { ce = *pce; } else { MSGPACK_WARNING("[msgpack] (%s) Function %s() hasn't defined " "the class it was called for", __FUNCTION__, class_name); incomplete_class = 1; ce = PHP_IC_ENTRY; } zval_ptr_dtor(&user_func); zval_ptr_dtor(&arg_func_name); } while(0); if (EG(exception)) { MSGPACK_WARNING("[msgpack] (%s) Exception error", __FUNCTION__); return NULL; } object_init_ex(*container, ce); /* store incomplete class name */ if (incomplete_class) { php_store_class_name(*container, class_name, name_len); } return ce; }
int msgpack_convert_object(zval *return_value, zval *object, zval **value) { zend_class_entry *ce, **pce; HashTable *properties = NULL; HashPosition prop_pos; TSRMLS_FETCH(); switch (Z_TYPE_P(object)) { case IS_STRING: if (zend_lookup_class( Z_STRVAL_P(object), Z_STRLEN_P(object), &pce TSRMLS_CC) != SUCCESS) { MSGPACK_ERROR("[msgpack] (%s) Class '%s' not found", __FUNCTION__, Z_STRVAL_P(object)); return FAILURE; } ce = *pce; break; case IS_OBJECT: ce = zend_get_class_entry(object TSRMLS_CC); break; default: MSGPACK_ERROR("[msgpack] (%s) Object type is unsupported", __FUNCTION__); return FAILURE; } if (Z_TYPE_PP(value) == IS_OBJECT) { zend_class_entry *vce; vce = zend_get_class_entry(*value TSRMLS_CC); if (strcmp(ce->name, vce->name) == 0) { *return_value = **value; zval_copy_ctor(return_value); zval_ptr_dtor(value); return SUCCESS; } } object_init_ex(return_value, ce); properties = Z_OBJ_HT_P(return_value)->get_properties( return_value TSRMLS_CC); if (HASH_OF(object)) { properties = HASH_OF(object); } zend_hash_internal_pointer_reset_ex(properties, &prop_pos); switch (Z_TYPE_PP(value)) { case IS_ARRAY: { char *key; uint key_len; int key_type; ulong key_index; zval **data; HashPosition pos; HashTable *ht, *ret; HashTable *var = NULL; int num; ht = HASH_OF(*value); ret = HASH_OF(return_value); num = zend_hash_num_elements(ht); if (num <= 0) { zval_ptr_dtor(value); break; } ALLOC_HASHTABLE(var); zend_hash_init(var, num, NULL, NULL, 0); /* string */ if (ht->nNumOfElements != ht->nNextFreeElement) { zend_hash_internal_pointer_reset_ex(ht, &pos); for (;; zend_hash_move_forward_ex(ht, &pos)) { key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { continue; } if (key_type == HASH_KEY_IS_STRING) { zval *val; MSGPACK_CONVERT_COPY_ZVAL(val, data); if (msgpack_convert_string_to_properties( return_value, key, key_len, val, var) != SUCCESS) { zval_ptr_dtor(&val); MSGPACK_WARNING( "[msgpack] (%s) " "illegal offset type, skip this decoding", __FUNCTION__); } } } } /* index */ zend_hash_internal_pointer_reset_ex(ht, &pos); for (;; zend_hash_move_forward_ex(ht, &pos)) { key_type = zend_hash_get_current_key_ex( ht, &key, &key_len, &key_index, 0, &pos); if (key_type == HASH_KEY_NON_EXISTANT) { break; } if (zend_hash_get_current_data_ex( ht, (void *)&data, &pos) != SUCCESS) { continue; } switch (key_type) { case HASH_KEY_IS_LONG: { zval *val; MSGPACK_CONVERT_COPY_ZVAL(val, data); if (msgpack_convert_long_to_properties( ret, &properties, &prop_pos, key_index, val, var) != SUCCESS) { zval_ptr_dtor(&val); MSGPACK_WARNING( "[msgpack] (%s) " "illegal offset type, skip this decoding", __FUNCTION__); } break; } case HASH_KEY_IS_STRING: break; default: MSGPACK_WARNING( "[msgpack] (%s) key is not string nor array", __FUNCTION__); break; } } zend_hash_destroy(var); FREE_HASHTABLE(var); zval_ptr_dtor(value); break; } default: if (msgpack_convert_long_to_properties( HASH_OF(return_value), &properties, &prop_pos, 0, *value, NULL) != SUCCESS) { MSGPACK_WARNING( "[msgpack] (%s) illegal offset type, skip this decoding", __FUNCTION__); } break; } return SUCCESS; }