1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 #include "dom_properties.h"
26
27 /*
28 * class DOMCharacterData extends DOMNode
29 *
30 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-FF21A306
31 * Since:
32 */
33
34 /* For some peculiar reason, many of these methods operate on unsigned numbers.
35 * Unfortunately, "old DOM" doesn't, so we have to conditionally convert...
36 * And the reason we're using "unsigned int" instead of "unsigned zend_long" is because libxml2 internally works with ints. */
dom_convert_number_unsigned(dom_object * intern,zend_long input,unsigned int * output)37 static bool dom_convert_number_unsigned(dom_object *intern, zend_long input, unsigned int *output)
38 {
39 if (input < 0) {
40 if (php_dom_follow_spec_intern(intern)) {
41 *output = (unsigned int) input;
42 } else {
43 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
44 return false;
45 }
46 } else {
47 *output = input;
48 }
49 return true;
50 }
51
52 /* {{{ data string
53 readonly=no
54 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-72AB8359
55 Since:
56 */
dom_characterdata_data_read(dom_object * obj,zval * retval)57 zend_result dom_characterdata_data_read(dom_object *obj, zval *retval)
58 {
59 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
60 php_dom_get_content_into_zval(nodep, retval, false);
61 return SUCCESS;
62 }
63
dom_characterdata_data_write(dom_object * obj,zval * newval)64 zend_result dom_characterdata_data_write(dom_object *obj, zval *newval)
65 {
66 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
67
68 /* Typed property, this is already a string */
69 ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING);
70 zend_string *str = Z_STR_P(newval);
71
72 xmlNodeSetContentLen(nodep, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
73
74 return SUCCESS;
75 }
76
77 /* }}} */
78
79 /* {{{ length long
80 readonly=yes
81 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7D61178C
82 Since:
83 */
dom_characterdata_length_read(dom_object * obj,zval * retval)84 zend_result dom_characterdata_length_read(dom_object *obj, zval *retval)
85 {
86 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
87
88 long length = 0;
89 if (nodep->content) {
90 length = xmlUTF8Strlen(nodep->content);
91 }
92
93 ZVAL_LONG(retval, length);
94
95 return SUCCESS;
96 }
97
98 /* }}} */
99
100 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6531BCCF
101 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-substringdata
102 Since:
103 */
PHP_METHOD(DOMCharacterData,substringData)104 PHP_METHOD(DOMCharacterData, substringData)
105 {
106 zval *id;
107 xmlChar *substring;
108 xmlNodePtr node;
109 zend_long offset_input, count_input;
110 unsigned int count, offset;
111 int length;
112 dom_object *intern;
113
114 id = ZEND_THIS;
115 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset_input, &count_input) == FAILURE) {
116 RETURN_THROWS();
117 }
118
119 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
120
121 const xmlChar *cur = php_dom_get_content_or_empty(node);
122
123 length = xmlUTF8Strlen(cur);
124 if (ZEND_LONG_INT_OVFL(offset_input) || ZEND_LONG_INT_OVFL(count_input)) {
125 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
126 RETURN_FALSE;
127 }
128
129 if (!dom_convert_number_unsigned(intern, offset_input, &offset) || !dom_convert_number_unsigned(intern, count_input, &count)) {
130 RETURN_FALSE;
131 }
132
133 if (offset > (unsigned int)length) {
134 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
135 RETURN_FALSE;
136 }
137
138 if (count > length - offset) {
139 count = length - offset;
140 }
141
142 substring = xmlUTF8Strsub(cur, (int)offset, (int)count);
143
144 if (substring) {
145 RETVAL_STRING((char *) substring);
146 xmlFree(substring);
147 } else {
148 RETVAL_EMPTY_STRING();
149 }
150 }
151 /* }}} end dom_characterdata_substring_data */
152
153 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-32791A2F
154 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-appenddata
155 Since:
156 */
dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS)157 static void dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS)
158 {
159 xmlNode *nodep;
160 dom_object *intern;
161 char *arg;
162 size_t arg_len;
163
164 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
165 RETURN_THROWS();
166 }
167
168 DOM_GET_OBJ(nodep, ZEND_THIS, xmlNodePtr, intern);
169 xmlTextConcat(nodep, BAD_CAST arg, arg_len);
170 }
171
PHP_METHOD(DOMCharacterData,appendData)172 PHP_METHOD(DOMCharacterData, appendData)
173 {
174 dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU);
175 RETURN_TRUE;
176 }
177
PHP_METHOD(Dom_CharacterData,appendData)178 PHP_METHOD(Dom_CharacterData, appendData)
179 {
180 dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU);
181 }
182 /* }}} end dom_characterdata_append_data */
183
184 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3EDB695F
185 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-insertdata
186 Since:
187 */
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)188 static void dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
189 {
190 zval *id;
191 xmlChar *first, *second;
192 xmlNodePtr node;
193 char *arg;
194 zend_long offset_input;
195 unsigned int offset;
196 int length;
197 size_t arg_len;
198 dom_object *intern;
199
200 id = ZEND_THIS;
201 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &offset_input, &arg, &arg_len) == FAILURE) {
202 RETURN_THROWS();
203 }
204
205 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
206
207 const xmlChar *cur = php_dom_get_content_or_empty(node);
208
209 length = xmlUTF8Strlen(cur);
210
211 if (ZEND_LONG_INT_OVFL(offset_input)) {
212 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
213 RETURN_FALSE;
214 }
215
216 if (!dom_convert_number_unsigned(intern, offset_input, &offset)) {
217 RETURN_FALSE;
218 }
219
220 if (offset > (unsigned int)length) {
221 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
222 RETURN_FALSE;
223 }
224
225 first = xmlUTF8Strndup(cur, (int)offset);
226 second = xmlUTF8Strsub(cur, (int)offset, length - (int)offset);
227
228 xmlNodeSetContent(node, first);
229 xmlNodeAddContent(node, BAD_CAST arg);
230 xmlNodeAddContent(node, second);
231
232 xmlFree(first);
233 xmlFree(second);
234
235 if (return_true) {
236 RETURN_TRUE;
237 }
238 }
239
PHP_METHOD(DOMCharacterData,insertData)240 PHP_METHOD(DOMCharacterData, insertData)
241 {
242 dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
243 }
244
PHP_METHOD(Dom_CharacterData,insertData)245 PHP_METHOD(Dom_CharacterData, insertData)
246 {
247 dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
248 }
249 /* }}} end dom_characterdata_insert_data */
250
251 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7C603781
252 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-deletedata
253 Since:
254 */
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)255 static void dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
256 {
257 zval *id;
258 xmlChar *substring, *second;
259 xmlNodePtr node;
260 zend_long offset, count_input;
261 unsigned int count;
262 int length;
263 dom_object *intern;
264
265 id = ZEND_THIS;
266 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count_input) == FAILURE) {
267 RETURN_THROWS();
268 }
269
270 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
271
272 const xmlChar *cur = php_dom_get_content_or_empty(node);
273
274 length = xmlUTF8Strlen(cur);
275
276 if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
277 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
278 RETURN_FALSE;
279 }
280
281 if (!dom_convert_number_unsigned(intern, count_input, &count)) {
282 RETURN_FALSE;
283 }
284
285 if (offset > 0) {
286 substring = xmlUTF8Strsub(cur, 0, (int)offset);
287 } else {
288 substring = NULL;
289 }
290
291 if (count > length - offset) {
292 count = length - offset;
293 }
294
295 second = xmlUTF8Strsub(cur, (int)offset + (int)count, length - (int)offset);
296 substring = xmlStrcat(substring, second);
297
298 xmlNodeSetContent(node, substring);
299
300 xmlFree(second);
301 xmlFree(substring);
302
303 if (return_true) {
304 RETURN_TRUE;
305 }
306 }
307
PHP_METHOD(DOMCharacterData,deleteData)308 PHP_METHOD(DOMCharacterData, deleteData)
309 {
310 dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
311 }
312
PHP_METHOD(Dom_CharacterData,deleteData)313 PHP_METHOD(Dom_CharacterData, deleteData)
314 {
315 dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
316 }
317 /* }}} end dom_characterdata_delete_data */
318
319 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-E5CBA7FB
320 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-replacedata
321 Since:
322 */
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)323 static void dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
324 {
325 zval *id;
326 xmlChar *substring, *second = NULL;
327 xmlNodePtr node;
328 char *arg;
329 zend_long offset, count_input;
330 unsigned int count;
331 int length;
332 size_t arg_len;
333 dom_object *intern;
334
335 id = ZEND_THIS;
336 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lls", &offset, &count_input, &arg, &arg_len) == FAILURE) {
337 RETURN_THROWS();
338 }
339
340 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
341
342 const xmlChar *cur = php_dom_get_content_or_empty(node);
343
344 length = xmlUTF8Strlen(cur);
345
346 if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
347 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
348 RETURN_FALSE;
349 }
350
351 if (!dom_convert_number_unsigned(intern, count_input, &count)) {
352 RETURN_FALSE;
353 }
354
355 if (offset > 0) {
356 substring = xmlUTF8Strsub(cur, 0, (int)offset);
357 } else {
358 substring = NULL;
359 }
360
361 if (count > length - offset) {
362 count = length - offset;
363 }
364
365 if (offset < length) {
366 second = xmlUTF8Strsub(cur, (int)offset + count, length - (int)offset);
367 }
368
369 substring = xmlStrcat(substring, BAD_CAST arg);
370 substring = xmlStrcat(substring, second);
371
372 xmlNodeSetContent(node, substring);
373
374 if (second) {
375 xmlFree(second);
376 }
377 xmlFree(substring);
378
379 if (return_true) {
380 RETURN_TRUE;
381 }
382 }
383
PHP_METHOD(DOMCharacterData,replaceData)384 PHP_METHOD(DOMCharacterData, replaceData)
385 {
386 dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
387 }
388
PHP_METHOD(Dom_CharacterData,replaceData)389 PHP_METHOD(Dom_CharacterData, replaceData)
390 {
391 dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
392 }
393 /* }}} end dom_characterdata_replace_data */
394
395 #endif
396