mirror of
https://github.com/php/php-src.git
synced 2026-04-01 05:02:27 +02:00
It's indeed possible this is NULL. When you create a new text-like node in libxml and pass NULL as content, you do get NULL in the content field instead of the empty string. You can hit this by creating DOMText or DOMComment directly and not passing any argument. This could also be created internally. We refactor the code such that this detail is hidden and we add a test to check that it correctly throws an exception.
400 lines
10 KiB
C
400 lines
10 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| https://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Christian Stocker <chregu@php.net> |
|
|
| Rob Richards <rrichards@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
|
#include "php_dom.h"
|
|
#include "dom_properties.h"
|
|
|
|
/*
|
|
* class DOMCharacterData extends DOMNode
|
|
*
|
|
* URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-FF21A306
|
|
* Since:
|
|
*/
|
|
|
|
/* For some peculiar reason, many of these methods operate on unsigned numbers.
|
|
* Unfortunately, "old DOM" doesn't, so we have to conditionally convert...
|
|
* And the reason we're using "unsigned int" instead of "unsigned zend_long" is because libxml2 internally works with ints. */
|
|
static bool dom_convert_number_unsigned(dom_object *intern, zend_long input, unsigned int *output)
|
|
{
|
|
if (input < 0) {
|
|
if (php_dom_follow_spec_intern(intern)) {
|
|
*output = (unsigned int) input;
|
|
} else {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
return false;
|
|
}
|
|
} else {
|
|
*output = input;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* {{{ data string
|
|
readonly=no
|
|
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-72AB8359
|
|
Since:
|
|
*/
|
|
zend_result dom_characterdata_data_read(dom_object *obj, zval *retval)
|
|
{
|
|
DOM_PROP_NODE(xmlNodePtr, nodep, obj);
|
|
php_dom_get_content_into_zval(nodep, retval, false);
|
|
return SUCCESS;
|
|
}
|
|
|
|
zend_result dom_characterdata_data_write(dom_object *obj, zval *newval)
|
|
{
|
|
DOM_PROP_NODE(xmlNodePtr, nodep, obj);
|
|
|
|
/* Typed property, this is already a string */
|
|
ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING);
|
|
zend_string *str = Z_STR_P(newval);
|
|
|
|
xmlNodeSetContentLen(nodep, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ length long
|
|
readonly=yes
|
|
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7D61178C
|
|
Since:
|
|
*/
|
|
zend_result dom_characterdata_length_read(dom_object *obj, zval *retval)
|
|
{
|
|
DOM_PROP_NODE(xmlNodePtr, nodep, obj);
|
|
|
|
long length = 0;
|
|
if (nodep->content) {
|
|
length = xmlUTF8Strlen(nodep->content);
|
|
}
|
|
|
|
ZVAL_LONG(retval, length);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6531BCCF
|
|
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-substringdata
|
|
Since:
|
|
*/
|
|
PHP_METHOD(DOMCharacterData, substringData)
|
|
{
|
|
zval *id;
|
|
xmlChar *substring;
|
|
xmlNodePtr node;
|
|
zend_long offset_input, count_input;
|
|
unsigned int count, offset;
|
|
int length;
|
|
dom_object *intern;
|
|
|
|
id = ZEND_THIS;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset_input, &count_input) == FAILURE) {
|
|
RETURN_THROWS();
|
|
}
|
|
|
|
DOM_GET_OBJ(node, id, xmlNodePtr, intern);
|
|
|
|
const xmlChar *cur = php_dom_get_content_or_empty(node);
|
|
|
|
length = xmlUTF8Strlen(cur);
|
|
if (ZEND_LONG_INT_OVFL(offset_input) || ZEND_LONG_INT_OVFL(count_input)) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (!dom_convert_number_unsigned(intern, offset_input, &offset) || !dom_convert_number_unsigned(intern, count_input, &count)) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (offset > (unsigned int)length) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (count > length - offset) {
|
|
count = length - offset;
|
|
}
|
|
|
|
substring = xmlUTF8Strsub(cur, (int)offset, (int)count);
|
|
|
|
if (substring) {
|
|
RETVAL_STRING((char *) substring);
|
|
xmlFree(substring);
|
|
} else {
|
|
RETVAL_EMPTY_STRING();
|
|
}
|
|
}
|
|
/* }}} end dom_characterdata_substring_data */
|
|
|
|
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-32791A2F
|
|
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-appenddata
|
|
Since:
|
|
*/
|
|
static void dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
|
{
|
|
zval *id;
|
|
xmlNode *nodep;
|
|
dom_object *intern;
|
|
char *arg;
|
|
size_t arg_len;
|
|
|
|
id = ZEND_THIS;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
|
|
RETURN_THROWS();
|
|
}
|
|
|
|
DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
|
|
xmlTextConcat(nodep, BAD_CAST arg, arg_len);
|
|
if (return_true) {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
|
|
PHP_METHOD(DOMCharacterData, appendData)
|
|
{
|
|
dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
|
}
|
|
|
|
PHP_METHOD(Dom_CharacterData, appendData)
|
|
{
|
|
dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
|
}
|
|
/* }}} end dom_characterdata_append_data */
|
|
|
|
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3EDB695F
|
|
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-insertdata
|
|
Since:
|
|
*/
|
|
static void dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
|
{
|
|
zval *id;
|
|
xmlChar *first, *second;
|
|
xmlNodePtr node;
|
|
char *arg;
|
|
zend_long offset_input;
|
|
unsigned int offset;
|
|
int length;
|
|
size_t arg_len;
|
|
dom_object *intern;
|
|
|
|
id = ZEND_THIS;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &offset_input, &arg, &arg_len) == FAILURE) {
|
|
RETURN_THROWS();
|
|
}
|
|
|
|
DOM_GET_OBJ(node, id, xmlNodePtr, intern);
|
|
|
|
const xmlChar *cur = php_dom_get_content_or_empty(node);
|
|
|
|
length = xmlUTF8Strlen(cur);
|
|
|
|
if (ZEND_LONG_INT_OVFL(offset_input)) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (!dom_convert_number_unsigned(intern, offset_input, &offset)) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (offset > (unsigned int)length) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
first = xmlUTF8Strndup(cur, (int)offset);
|
|
second = xmlUTF8Strsub(cur, (int)offset, length - (int)offset);
|
|
|
|
xmlNodeSetContent(node, first);
|
|
xmlNodeAddContent(node, BAD_CAST arg);
|
|
xmlNodeAddContent(node, second);
|
|
|
|
xmlFree(first);
|
|
xmlFree(second);
|
|
|
|
if (return_true) {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
|
|
PHP_METHOD(DOMCharacterData, insertData)
|
|
{
|
|
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
|
}
|
|
|
|
PHP_METHOD(Dom_CharacterData, insertData)
|
|
{
|
|
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
|
}
|
|
/* }}} end dom_characterdata_insert_data */
|
|
|
|
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7C603781
|
|
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-deletedata
|
|
Since:
|
|
*/
|
|
static void dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
|
{
|
|
zval *id;
|
|
xmlChar *substring, *second;
|
|
xmlNodePtr node;
|
|
zend_long offset, count_input;
|
|
unsigned int count;
|
|
int length;
|
|
dom_object *intern;
|
|
|
|
id = ZEND_THIS;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count_input) == FAILURE) {
|
|
RETURN_THROWS();
|
|
}
|
|
|
|
DOM_GET_OBJ(node, id, xmlNodePtr, intern);
|
|
|
|
const xmlChar *cur = php_dom_get_content_or_empty(node);
|
|
|
|
length = xmlUTF8Strlen(cur);
|
|
|
|
if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (!dom_convert_number_unsigned(intern, count_input, &count)) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (offset > 0) {
|
|
substring = xmlUTF8Strsub(cur, 0, (int)offset);
|
|
} else {
|
|
substring = NULL;
|
|
}
|
|
|
|
if (count > length - offset) {
|
|
count = length - offset;
|
|
}
|
|
|
|
second = xmlUTF8Strsub(cur, (int)offset + (int)count, length - (int)offset);
|
|
substring = xmlStrcat(substring, second);
|
|
|
|
xmlNodeSetContent(node, substring);
|
|
|
|
xmlFree(second);
|
|
xmlFree(substring);
|
|
|
|
if (return_true) {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
|
|
PHP_METHOD(DOMCharacterData, deleteData)
|
|
{
|
|
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
|
}
|
|
|
|
PHP_METHOD(Dom_CharacterData, deleteData)
|
|
{
|
|
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
|
}
|
|
/* }}} end dom_characterdata_delete_data */
|
|
|
|
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-E5CBA7FB
|
|
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-replacedata
|
|
Since:
|
|
*/
|
|
static void dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
|
{
|
|
zval *id;
|
|
xmlChar *substring, *second = NULL;
|
|
xmlNodePtr node;
|
|
char *arg;
|
|
zend_long offset, count_input;
|
|
unsigned int count;
|
|
int length;
|
|
size_t arg_len;
|
|
dom_object *intern;
|
|
|
|
id = ZEND_THIS;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lls", &offset, &count_input, &arg, &arg_len) == FAILURE) {
|
|
RETURN_THROWS();
|
|
}
|
|
|
|
DOM_GET_OBJ(node, id, xmlNodePtr, intern);
|
|
|
|
const xmlChar *cur = php_dom_get_content_or_empty(node);
|
|
|
|
length = xmlUTF8Strlen(cur);
|
|
|
|
if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
|
|
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (!dom_convert_number_unsigned(intern, count_input, &count)) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (offset > 0) {
|
|
substring = xmlUTF8Strsub(cur, 0, (int)offset);
|
|
} else {
|
|
substring = NULL;
|
|
}
|
|
|
|
if (count > length - offset) {
|
|
count = length - offset;
|
|
}
|
|
|
|
if (offset < length) {
|
|
second = xmlUTF8Strsub(cur, (int)offset + count, length - (int)offset);
|
|
}
|
|
|
|
substring = xmlStrcat(substring, BAD_CAST arg);
|
|
substring = xmlStrcat(substring, second);
|
|
|
|
xmlNodeSetContent(node, substring);
|
|
|
|
if (second) {
|
|
xmlFree(second);
|
|
}
|
|
xmlFree(substring);
|
|
|
|
if (return_true) {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
|
|
PHP_METHOD(DOMCharacterData, replaceData)
|
|
{
|
|
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
|
}
|
|
|
|
PHP_METHOD(Dom_CharacterData, replaceData)
|
|
{
|
|
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
|
}
|
|
/* }}} end dom_characterdata_replace_data */
|
|
|
|
#endif
|