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);
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #8
0
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;
}