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 *cur;
108 xmlChar *substring;
109 xmlNodePtr node;
110 zend_long offset_input, count_input;
111 unsigned int count, offset;
112 int length;
113 dom_object *intern;
114
115 id = ZEND_THIS;
116 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset_input, &count_input) == FAILURE) {
117 RETURN_THROWS();
118 }
119
120 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
121
122 cur = node->content;
123 if (cur == NULL) {
124 /* TODO: is this even possible? */
125 cur = BAD_CAST "";
126 }
127
128 length = xmlUTF8Strlen(cur);
129 if (ZEND_LONG_INT_OVFL(offset_input) || ZEND_LONG_INT_OVFL(count_input)) {
130 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
131 RETURN_FALSE;
132 }
133
134 if (!dom_convert_number_unsigned(intern, offset_input, &offset) || !dom_convert_number_unsigned(intern, count_input, &count)) {
135 RETURN_FALSE;
136 }
137
138 if (offset > length) {
139 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
140 RETURN_FALSE;
141 }
142
143 if (count > length - offset) {
144 count = length - offset;
145 }
146
147 substring = xmlUTF8Strsub(cur, (int)offset, (int)count);
148
149 if (substring) {
150 RETVAL_STRING((char *) substring);
151 xmlFree(substring);
152 } else {
153 RETVAL_EMPTY_STRING();
154 }
155 }
156 /* }}} end dom_characterdata_substring_data */
157
158 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-32791A2F
159 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-appenddata
160 Since:
161 */
dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)162 static void dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
163 {
164 zval *id;
165 xmlNode *nodep;
166 dom_object *intern;
167 char *arg;
168 size_t arg_len;
169
170 id = ZEND_THIS;
171 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
172 RETURN_THROWS();
173 }
174
175 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
176 xmlTextConcat(nodep, BAD_CAST arg, arg_len);
177 if (return_true) {
178 RETURN_TRUE;
179 }
180 }
181
PHP_METHOD(DOMCharacterData,appendData)182 PHP_METHOD(DOMCharacterData, appendData)
183 {
184 dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
185 }
186
PHP_METHOD(DOM_CharacterData,appendData)187 PHP_METHOD(DOM_CharacterData, appendData)
188 {
189 dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
190 }
191 /* }}} end dom_characterdata_append_data */
192
193 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3EDB695F
194 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-insertdata
195 Since:
196 */
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)197 static void dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
198 {
199 zval *id;
200 xmlChar *cur, *first, *second;
201 xmlNodePtr node;
202 char *arg;
203 zend_long offset_input;
204 unsigned int offset;
205 int length;
206 size_t arg_len;
207 dom_object *intern;
208
209 id = ZEND_THIS;
210 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &offset_input, &arg, &arg_len) == FAILURE) {
211 RETURN_THROWS();
212 }
213
214 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
215
216 cur = node->content;
217 if (cur == NULL) {
218 /* TODO: is this even possible? */
219 cur = BAD_CAST "";
220 }
221
222 length = xmlUTF8Strlen(cur);
223
224 if (ZEND_LONG_INT_OVFL(offset_input)) {
225 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
226 RETURN_FALSE;
227 }
228
229 if (!dom_convert_number_unsigned(intern, offset_input, &offset)) {
230 RETURN_FALSE;
231 }
232
233 if (offset > length) {
234 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
235 RETURN_FALSE;
236 }
237
238 first = xmlUTF8Strndup(cur, (int)offset);
239 second = xmlUTF8Strsub(cur, (int)offset, length - (int)offset);
240
241 xmlNodeSetContent(node, first);
242 xmlNodeAddContent(node, BAD_CAST arg);
243 xmlNodeAddContent(node, second);
244
245 xmlFree(first);
246 xmlFree(second);
247
248 if (return_true) {
249 RETURN_TRUE;
250 }
251 }
252
PHP_METHOD(DOMCharacterData,insertData)253 PHP_METHOD(DOMCharacterData, insertData)
254 {
255 dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
256 }
257
PHP_METHOD(DOM_CharacterData,insertData)258 PHP_METHOD(DOM_CharacterData, insertData)
259 {
260 dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
261 }
262 /* }}} end dom_characterdata_insert_data */
263
264 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7C603781
265 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-deletedata
266 Since:
267 */
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)268 static void dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
269 {
270 zval *id;
271 xmlChar *cur, *substring, *second;
272 xmlNodePtr node;
273 zend_long offset, count_input;
274 unsigned int count;
275 int length;
276 dom_object *intern;
277
278 id = ZEND_THIS;
279 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count_input) == FAILURE) {
280 RETURN_THROWS();
281 }
282
283 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
284
285 cur = node->content;
286 if (cur == NULL) {
287 /* TODO: is this even possible? */
288 cur = BAD_CAST "";
289 }
290
291 length = xmlUTF8Strlen(cur);
292
293 if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
294 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
295 RETURN_FALSE;
296 }
297
298 if (!dom_convert_number_unsigned(intern, count_input, &count)) {
299 RETURN_FALSE;
300 }
301
302 if (offset > 0) {
303 substring = xmlUTF8Strsub(cur, 0, (int)offset);
304 } else {
305 substring = NULL;
306 }
307
308 if (count > length - offset) {
309 count = length - offset;
310 }
311
312 second = xmlUTF8Strsub(cur, (int)offset + (int)count, length - (int)offset);
313 substring = xmlStrcat(substring, second);
314
315 xmlNodeSetContent(node, substring);
316
317 xmlFree(second);
318 xmlFree(substring);
319
320 if (return_true) {
321 RETURN_TRUE;
322 }
323 }
324
PHP_METHOD(DOMCharacterData,deleteData)325 PHP_METHOD(DOMCharacterData, deleteData)
326 {
327 dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
328 }
329
PHP_METHOD(DOM_CharacterData,deleteData)330 PHP_METHOD(DOM_CharacterData, deleteData)
331 {
332 dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
333 }
334 /* }}} end dom_characterdata_delete_data */
335
336 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-E5CBA7FB
337 Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-replacedata
338 Since:
339 */
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS,bool return_true)340 static void dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
341 {
342 zval *id;
343 xmlChar *cur, *substring, *second = NULL;
344 xmlNodePtr node;
345 char *arg;
346 zend_long offset, count_input;
347 unsigned int count;
348 int length;
349 size_t arg_len;
350 dom_object *intern;
351
352 id = ZEND_THIS;
353 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lls", &offset, &count_input, &arg, &arg_len) == FAILURE) {
354 RETURN_THROWS();
355 }
356
357 DOM_GET_OBJ(node, id, xmlNodePtr, intern);
358
359 cur = node->content;
360 if (cur == NULL) {
361 /* TODO: is this even possible? */
362 cur = BAD_CAST "";
363 }
364
365 length = xmlUTF8Strlen(cur);
366
367 if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
368 php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
369 RETURN_FALSE;
370 }
371
372 if (!dom_convert_number_unsigned(intern, count_input, &count)) {
373 RETURN_FALSE;
374 }
375
376 if (offset > 0) {
377 substring = xmlUTF8Strsub(cur, 0, (int)offset);
378 } else {
379 substring = NULL;
380 }
381
382 if (count > length - offset) {
383 count = length - offset;
384 }
385
386 if (offset < length) {
387 second = xmlUTF8Strsub(cur, (int)offset + count, length - (int)offset);
388 }
389
390 substring = xmlStrcat(substring, BAD_CAST arg);
391 substring = xmlStrcat(substring, second);
392
393 xmlNodeSetContent(node, substring);
394
395 if (second) {
396 xmlFree(second);
397 }
398 xmlFree(substring);
399
400 if (return_true) {
401 RETURN_TRUE;
402 }
403 }
404
PHP_METHOD(DOMCharacterData,replaceData)405 PHP_METHOD(DOMCharacterData, replaceData)
406 {
407 dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
408 }
409
PHP_METHOD(DOM_CharacterData,replaceData)410 PHP_METHOD(DOM_CharacterData, replaceData)
411 {
412 dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
413 }
414 /* }}} end dom_characterdata_replace_data */
415
416 #endif
417