Implement request #30622: make $namespace parameter functional

This parameter never actually did anything and was forgotten about.
We solve this by detecting when we have a $namespace argument
(that won't conflict with the name argument) and creating a Clark
notation name out of it.

Closes GH-16123.
This commit is contained in:
Niels Dossche 2024-09-29 21:45:55 +02:00
parent f5e81fe182
commit daa94cf279
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
5 changed files with 218 additions and 18 deletions

View file

@ -549,6 +549,32 @@ PHP_METHOD(XSLTProcessor, transformToXml)
}
/* }}} end XSLTProcessor::transformToXml */
static zend_string *xsl_create_parameter_key(uint32_t arg_num, const zend_string *namespace, zend_string *name)
{
if (ZSTR_LEN(namespace) == 0) {
return zend_string_copy(name);
}
/* Clark notation already sets the namespace and we cannot have a double namespace declaration. */
if (ZSTR_VAL(name)[0] == '{') {
zend_argument_value_error(arg_num, "must not use clark notation when argument #1 ($namespace) is not empty");
return NULL;
}
/* Cannot be a QName as that would cause a namespace lookup in the document. */
if (ZSTR_VAL(name)[0] != ':' && strchr(ZSTR_VAL(name), ':')) {
zend_argument_value_error(arg_num, "must not be a QName when argument #1 ($namespace) is not empty");
return NULL;
}
zend_string *clark_str = zend_string_safe_alloc(1, ZSTR_LEN(name), 2 + ZSTR_LEN(namespace), false);
ZSTR_VAL(clark_str)[0] = '{';
memcpy(ZSTR_VAL(clark_str) + 1, ZSTR_VAL(namespace), ZSTR_LEN(namespace));
ZSTR_VAL(clark_str)[ZSTR_LEN(namespace) + 1] = '}';
memcpy(ZSTR_VAL(clark_str) + 2 + ZSTR_LEN(namespace), ZSTR_VAL(name), ZSTR_LEN(name) + 1 /* include '\0' */);
return clark_str;
}
/* {{{ */
PHP_METHOD(XSLTProcessor, setParameter)
{
@ -557,12 +583,10 @@ PHP_METHOD(XSLTProcessor, setParameter)
zval *entry, new_string;
HashTable *array_value;
xsl_object *intern;
char *namespace;
size_t namespace_len;
zend_string *string_key, *name, *value = NULL;
zend_string *namespace, *string_key, *name, *value = NULL;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STRING(namespace, namespace_len)
Z_PARAM_PATH_STR(namespace)
Z_PARAM_ARRAY_HT_OR_STR(array_value, name)
Z_PARAM_OPTIONAL
Z_PARAM_PATH_STR_OR_NULL(value)
@ -590,19 +614,27 @@ PHP_METHOD(XSLTProcessor, setParameter)
RETURN_THROWS();
}
zend_string *ht_key = xsl_create_parameter_key(2, namespace, string_key);
if (!ht_key) {
RETURN_THROWS();
}
str = zval_try_get_string(entry);
if (UNEXPECTED(!str)) {
zend_string_release_ex(ht_key, false);
RETURN_THROWS();
}
if (UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(str), ZSTR_LEN(str)))) {
zend_string_release(str);
zend_string_release_ex(ht_key, false);
zend_argument_value_error(3, "must not contain values with any null bytes");
RETURN_THROWS();
}
ZVAL_STR(&tmp, str);
zend_hash_update(intern->parameter, string_key, &tmp);
zend_hash_update(intern->parameter, ht_key, &tmp);
zend_string_release_ex(ht_key, false);
} ZEND_HASH_FOREACH_END();
RETURN_TRUE;
} else {
@ -616,9 +648,15 @@ PHP_METHOD(XSLTProcessor, setParameter)
RETURN_THROWS();
}
zend_string *key = xsl_create_parameter_key(2, namespace, name);
if (!key) {
RETURN_THROWS();
}
ZVAL_STR_COPY(&new_string, value);
zend_hash_update(intern->parameter, name, &new_string);
zend_hash_update(intern->parameter, key, &new_string);
zend_string_release_ex(key, false);
RETURN_TRUE;
}
}
@ -628,17 +666,21 @@ PHP_METHOD(XSLTProcessor, setParameter)
PHP_METHOD(XSLTProcessor, getParameter)
{
zval *id = ZEND_THIS;
char *namespace;
size_t namespace_len = 0;
zval *value;
zend_string *name;
zend_string *namespace, *name;
xsl_object *intern;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "PP", &namespace, &name) == FAILURE) {
RETURN_THROWS();
}
zend_string *key = xsl_create_parameter_key(2, namespace, name);
if (!key) {
RETURN_THROWS();
}
intern = Z_XSL_P(id);
if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
value = zend_hash_find(intern->parameter, key);
zend_string_release_ex(key, false);
if (value != NULL) {
RETURN_STR_COPY(Z_STR_P(value));
} else {
RETURN_FALSE;
@ -650,20 +692,23 @@ PHP_METHOD(XSLTProcessor, getParameter)
PHP_METHOD(XSLTProcessor, removeParameter)
{
zval *id = ZEND_THIS;
size_t namespace_len = 0;
char *namespace;
zend_string *name;
zend_string *namespace, *name;
xsl_object *intern;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "PP", &namespace, &name) == FAILURE) {
RETURN_THROWS();
}
zend_string *key = xsl_create_parameter_key(2, namespace, name);
if (!key) {
RETURN_THROWS();
}
intern = Z_XSL_P(id);
if (zend_hash_del(intern->parameter, name) == SUCCESS) {
RETURN_TRUE;
if (zend_hash_del(intern->parameter, key) == SUCCESS) {
RETVAL_TRUE;
} else {
RETURN_FALSE;
RETVAL_FALSE;
}
zend_string_release_ex(key, false);
}
/* }}} end XSLTProcessor::removeParameter */