xref: /PHP-8.2/ext/xmlwriter/php_xmlwriter.c (revision 4fe82131)
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   | Author: Rob Richards <rrichards@php.net>                             |
14   |         Pierre-A. Joye <pajoye@php.net>                              |
15   +----------------------------------------------------------------------+
16 */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 
23 #include "php.h"
24 #include "php_ini.h"
25 #include "ext/standard/info.h"
26 #include "php_xmlwriter.h"
27 #include "php_xmlwriter_arginfo.h"
28 #include "ext/standard/php_string.h"
29 
30 static zend_class_entry *xmlwriter_class_entry_ce;
31 
32 typedef int (*xmlwriter_read_one_char_t)(xmlTextWriterPtr writer, const xmlChar *content);
33 typedef int (*xmlwriter_read_int_t)(xmlTextWriterPtr writer);
34 
35 /* {{{ XMLWRITER_FROM_OBJECT */
36 #define XMLWRITER_FROM_OBJECT(ptr, object) \
37 	{ \
38 		ze_xmlwriter_object *obj = Z_XMLWRITER_P(object); \
39 		ptr = obj->ptr; \
40 		if (!ptr) { \
41 			zend_throw_error(NULL, "Invalid or uninitialized XMLWriter object"); \
42 			RETURN_THROWS(); \
43 		} \
44 	}
45 /* }}} */
46 
47 static zend_object_handlers xmlwriter_object_handlers;
48 
49 /* {{{{ xmlwriter_object_dtor */
xmlwriter_object_dtor(zend_object * object)50 static void xmlwriter_object_dtor(zend_object *object)
51 {
52 	ze_xmlwriter_object *intern = php_xmlwriter_fetch_object(object);
53 
54 	/* freeing the resource here may leak, but otherwise we may use it after it has been freed */
55 	if (intern->ptr) {
56 		xmlFreeTextWriter(intern->ptr);
57 		intern->ptr = NULL;
58 	}
59 	if (intern->output) {
60 		xmlBufferFree(intern->output);
61 		intern->output = NULL;
62 	}
63 	zend_objects_destroy_object(object);
64 }
65 /* }}} */
66 
67 /* {{{ xmlwriter_object_free_storage */
xmlwriter_object_free_storage(zend_object * object)68 static void xmlwriter_object_free_storage(zend_object *object)
69 {
70 	ze_xmlwriter_object *intern = php_xmlwriter_fetch_object(object);
71 
72 	zend_object_std_dtor(&intern->std);
73 }
74 /* }}} */
75 
76 
77 /* {{{ xmlwriter_object_new */
xmlwriter_object_new(zend_class_entry * class_type)78 static zend_object *xmlwriter_object_new(zend_class_entry *class_type)
79 {
80 	ze_xmlwriter_object *intern;
81 
82 	intern = zend_object_alloc(sizeof(ze_xmlwriter_object), class_type);
83 	zend_object_std_init(&intern->std, class_type);
84 	object_properties_init(&intern->std, class_type);
85 	intern->std.handlers = &xmlwriter_object_handlers;
86 
87 	return &intern->std;
88 }
89 /* }}} */
90 
91 #define XMLW_NAME_CHK(__arg_no, __subject) \
92 	if (xmlValidateName((xmlChar *) name, 0) != 0) {	\
93 		zend_argument_value_error(__arg_no, "must be a valid %s, \"%s\" given", __subject, name);	\
94 		RETURN_THROWS();	\
95 	}	\
96 
97 /* {{{ function prototypes */
98 static PHP_MINIT_FUNCTION(xmlwriter);
99 static PHP_MSHUTDOWN_FUNCTION(xmlwriter);
100 static PHP_MINFO_FUNCTION(xmlwriter);
101 /* }}} */
102 
103 /* _xmlwriter_get_valid_file_path should be made a
104 	common function in libxml extension as code is common to a few xml extensions */
105 /* {{{ _xmlwriter_get_valid_file_path */
_xmlwriter_get_valid_file_path(char * source,char * resolved_path,int resolved_path_len)106 static char *_xmlwriter_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len ) {
107 	xmlURI *uri;
108 	xmlChar *escsource;
109 	char *file_dest;
110 	int isFileUri = 0;
111 
112 	uri = xmlCreateURI();
113 	if (uri == NULL) {
114 		return NULL;
115 	}
116 	escsource = xmlURIEscapeStr((xmlChar *)source, (xmlChar *) ":");
117 	xmlParseURIReference(uri, (char *)escsource);
118 	xmlFree(escsource);
119 
120 	if (uri->scheme != NULL) {
121 		/* absolute file uris - libxml only supports localhost or empty host */
122 		if (strncasecmp(source, "file:///", 8) == 0) {
123 			if (source[sizeof("file:///") - 1] == '\0') {
124 				xmlFreeURI(uri);
125 				return NULL;
126 			}
127 			isFileUri = 1;
128 #ifdef PHP_WIN32
129 			source += 8;
130 #else
131 			source += 7;
132 #endif
133 		} else if (strncasecmp(source, "file://localhost/",17) == 0) {
134 			if (source[sizeof("file://localhost/") - 1] == '\0') {
135 				xmlFreeURI(uri);
136 				return NULL;
137 			}
138 
139 			isFileUri = 1;
140 #ifdef PHP_WIN32
141 			source += 17;
142 #else
143 			source += 16;
144 #endif
145 		}
146 	}
147 
148 	if ((uri->scheme == NULL || isFileUri)) {
149 		char file_dirname[MAXPATHLEN];
150 		size_t dir_len;
151 
152 		if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path)) {
153 			xmlFreeURI(uri);
154 			return NULL;
155 		}
156 
157 		memcpy(file_dirname, source, strlen(source));
158 		dir_len = php_dirname(file_dirname, strlen(source));
159 
160 		if (dir_len > 0) {
161 			zend_stat_t buf = {0};
162 			if (php_sys_stat(file_dirname, &buf) != 0) {
163 				xmlFreeURI(uri);
164 				return NULL;
165 			}
166 		}
167 
168 		file_dest = resolved_path;
169 	} else {
170 		file_dest = source;
171 	}
172 
173 	xmlFreeURI(uri);
174 
175 	return file_dest;
176 }
177 /* }}} */
178 
179 /* {{{ xmlwriter_module_entry */
180 zend_module_entry xmlwriter_module_entry = {
181 	STANDARD_MODULE_HEADER,
182 	"xmlwriter",
183 	ext_functions,
184 	PHP_MINIT(xmlwriter),
185 	PHP_MSHUTDOWN(xmlwriter),
186 	NULL,
187 	NULL,
188 	PHP_MINFO(xmlwriter),
189 	PHP_XMLWRITER_VERSION,
190 	STANDARD_MODULE_PROPERTIES
191 };
192 /* }}} */
193 
194 #ifdef COMPILE_DL_XMLWRITER
ZEND_GET_MODULE(xmlwriter)195 ZEND_GET_MODULE(xmlwriter)
196 #endif
197 
198 /* {{{ xmlwriter_objects_clone
199 static void xmlwriter_objects_clone(void *object, void **object_clone)
200 {
201 	TODO
202 }
203 }}} */
204 
205 static void php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAMETERS, xmlwriter_read_one_char_t internal_function, char *subject_name)
206 {
207 	xmlTextWriterPtr ptr;
208 	char *name;
209 	size_t name_len;
210 	int retval;
211 	zval *self;
212 
213 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &self, xmlwriter_class_entry_ce, &name, &name_len) == FAILURE) {
214 		RETURN_THROWS();
215 	}
216 	XMLWRITER_FROM_OBJECT(ptr, self);
217 
218 	if (subject_name != NULL) {
219 		XMLW_NAME_CHK(2, subject_name);
220 	}
221 
222 	if (ptr) {
223 		retval = internal_function(ptr, (xmlChar *) name);
224 		if (retval != -1) {
225 			RETURN_TRUE;
226 		}
227 	}
228 
229 	RETURN_FALSE;
230 }
231 
php_xmlwriter_end(INTERNAL_FUNCTION_PARAMETERS,xmlwriter_read_int_t internal_function)232 static void php_xmlwriter_end(INTERNAL_FUNCTION_PARAMETERS, xmlwriter_read_int_t internal_function)
233 {
234 	xmlTextWriterPtr ptr;
235 	int retval;
236 	zval *self;
237 
238 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &self, xmlwriter_class_entry_ce) == FAILURE) {
239 		RETURN_THROWS();
240 	}
241 	XMLWRITER_FROM_OBJECT(ptr, self);
242 
243 	if (ptr) {
244 		retval = internal_function(ptr);
245 		if (retval != -1) {
246 			RETURN_TRUE;
247 		}
248 	}
249 
250 	RETURN_FALSE;
251 }
252 
253 /* {{{ Toggle indentation on/off - returns FALSE on error */
PHP_FUNCTION(xmlwriter_set_indent)254 PHP_FUNCTION(xmlwriter_set_indent)
255 {
256 	xmlTextWriterPtr ptr;
257 	int retval;
258 	bool indent;
259 	zval *self;
260 
261 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ob", &self, xmlwriter_class_entry_ce, &indent) == FAILURE) {
262 		RETURN_THROWS();
263 	}
264 	XMLWRITER_FROM_OBJECT(ptr, self);
265 
266 	if (ptr) {
267 		retval = xmlTextWriterSetIndent(ptr, indent);
268 		if (retval == 0) {
269 			RETURN_TRUE;
270 		}
271 	}
272 
273 	RETURN_FALSE;
274 }
275 /* }}} */
276 
277 /* {{{ Set string used for indenting - returns FALSE on error */
PHP_FUNCTION(xmlwriter_set_indent_string)278 PHP_FUNCTION(xmlwriter_set_indent_string)
279 {
280 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterSetIndentString, NULL);
281 }
282 /* }}} */
283 
284 /* {{{ Create start attribute - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_attribute)285 PHP_FUNCTION(xmlwriter_start_attribute)
286 {
287 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterStartAttribute, "attribute name");
288 }
289 /* }}} */
290 
291 /* {{{ End attribute - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_attribute)292 PHP_FUNCTION(xmlwriter_end_attribute)
293 {
294 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndAttribute);
295 }
296 /* }}} */
297 
298 /* {{{ Create start namespaced attribute - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_attribute_ns)299 PHP_FUNCTION(xmlwriter_start_attribute_ns)
300 {
301 	xmlTextWriterPtr ptr;
302 	char *name, *prefix, *uri;
303 	size_t name_len, prefix_len, uri_len;
304 	int retval;
305 	zval *self;
306 
307 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os!ss!", &self, xmlwriter_class_entry_ce,
308 		&prefix, &prefix_len, &name, &name_len, &uri, &uri_len) == FAILURE) {
309 		RETURN_THROWS();
310 	}
311 	XMLWRITER_FROM_OBJECT(ptr, self);
312 
313 	XMLW_NAME_CHK(3, "attribute name");
314 
315 	if (ptr) {
316 		retval = xmlTextWriterStartAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri);
317 		if (retval != -1) {
318 			RETURN_TRUE;
319 		}
320 	}
321 
322 	RETURN_FALSE;
323 }
324 /* }}} */
325 
326 /* {{{ Write full attribute - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_attribute)327 PHP_FUNCTION(xmlwriter_write_attribute)
328 {
329 	xmlTextWriterPtr ptr;
330 	char *name, *content;
331 	size_t name_len, content_len;
332 	int retval;
333 	zval *self;
334 
335 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &self, xmlwriter_class_entry_ce,
336 		&name, &name_len, &content, &content_len) == FAILURE) {
337 		RETURN_THROWS();
338 	}
339 	XMLWRITER_FROM_OBJECT(ptr, self);
340 
341 	XMLW_NAME_CHK(2, "attribute name");
342 
343 	if (ptr) {
344 		retval = xmlTextWriterWriteAttribute(ptr, (xmlChar *)name, (xmlChar *)content);
345 		if (retval != -1) {
346 			RETURN_TRUE;
347 		}
348 	}
349 
350 	RETURN_FALSE;
351 }
352 /* }}} */
353 
354 /* {{{ Write full namespaced attribute - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_attribute_ns)355 PHP_FUNCTION(xmlwriter_write_attribute_ns)
356 {
357 	xmlTextWriterPtr ptr;
358 	char *name, *prefix, *uri, *content;
359 	size_t name_len, prefix_len, uri_len, content_len;
360 	int retval;
361 	zval *self;
362 
363 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os!ss!s", &self, xmlwriter_class_entry_ce,
364 		&prefix, &prefix_len, &name, &name_len, &uri, &uri_len, &content, &content_len) == FAILURE) {
365 		RETURN_THROWS();
366 	}
367 	XMLWRITER_FROM_OBJECT(ptr, self);
368 
369 	XMLW_NAME_CHK(3, "attribute name");
370 
371 	if (ptr) {
372 		retval = xmlTextWriterWriteAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content);
373 		if (retval != -1) {
374 			RETURN_TRUE;
375 		}
376 	}
377 
378 	RETURN_FALSE;
379 }
380 /* }}} */
381 
382 /* {{{ Create start element tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_element)383 PHP_FUNCTION(xmlwriter_start_element)
384 {
385 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterStartElement, "element name");
386 }
387 /* }}} */
388 
389 /* {{{ Create start namespaced element tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_element_ns)390 PHP_FUNCTION(xmlwriter_start_element_ns)
391 {
392 	xmlTextWriterPtr ptr;
393 	char *name, *prefix, *uri;
394 	size_t name_len, prefix_len, uri_len;
395 	int retval;
396 	zval *self;
397 
398 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os!ss!", &self, xmlwriter_class_entry_ce,
399 		&prefix, &prefix_len, &name, &name_len, &uri, &uri_len) == FAILURE) {
400 		RETURN_THROWS();
401 	}
402 	XMLWRITER_FROM_OBJECT(ptr, self);
403 
404 	XMLW_NAME_CHK(3, "element name");
405 
406 	if (ptr) {
407 		retval = xmlTextWriterStartElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri);
408 		if (retval != -1) {
409 			RETURN_TRUE;
410 		}
411 
412 	}
413 
414 	RETURN_FALSE;
415 }
416 /* }}} */
417 
418 /* {{{ End current element - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_element)419 PHP_FUNCTION(xmlwriter_end_element)
420 {
421 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndElement);
422 }
423 /* }}} */
424 
425 /* {{{ End current element - returns FALSE on error */
PHP_FUNCTION(xmlwriter_full_end_element)426 PHP_FUNCTION(xmlwriter_full_end_element)
427 {
428 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterFullEndElement);
429 }
430 /* }}} */
431 
432 /* {{{ Write full element tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_element)433 PHP_FUNCTION(xmlwriter_write_element)
434 {
435 	xmlTextWriterPtr ptr;
436 	char *name, *content = NULL;
437 	size_t name_len, content_len;
438 	int retval;
439 	zval *self;
440 
441 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|s!", &self, xmlwriter_class_entry_ce,
442 		&name, &name_len, &content, &content_len) == FAILURE) {
443 		RETURN_THROWS();
444 	}
445 	XMLWRITER_FROM_OBJECT(ptr, self);
446 
447 	XMLW_NAME_CHK(2, "element name");
448 
449 	if (ptr) {
450 		if (!content) {
451 			retval = xmlTextWriterStartElement(ptr, (xmlChar *)name);
452 			if (retval == -1) {
453 				RETURN_FALSE;
454 			}
455 			retval = xmlTextWriterEndElement(ptr);
456 			if (retval == -1) {
457 				RETURN_FALSE;
458 			}
459 		} else {
460 			retval = xmlTextWriterWriteElement(ptr, (xmlChar *)name, (xmlChar *)content);
461 		}
462 		if (retval != -1) {
463 			RETURN_TRUE;
464 		}
465 	}
466 
467 	RETURN_FALSE;
468 }
469 /* }}} */
470 
471 /* {{{ Write full namesapced element tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_element_ns)472 PHP_FUNCTION(xmlwriter_write_element_ns)
473 {
474 	xmlTextWriterPtr ptr;
475 	char *name, *prefix, *uri, *content = NULL;
476 	size_t name_len, prefix_len, uri_len, content_len;
477 	int retval;
478 	zval *self;
479 
480 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os!ss!|s!", &self, xmlwriter_class_entry_ce,
481 		&prefix, &prefix_len, &name, &name_len, &uri, &uri_len, &content, &content_len) == FAILURE) {
482 		RETURN_THROWS();
483 	}
484 	XMLWRITER_FROM_OBJECT(ptr, self);
485 
486 	XMLW_NAME_CHK(3, "element name");
487 
488 	if (ptr) {
489 		if (!content) {
490 			retval = xmlTextWriterStartElementNS(ptr,(xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri);
491             if (retval == -1) {
492                 RETURN_FALSE;
493             }
494 			retval = xmlTextWriterEndElement(ptr);
495             if (retval == -1) {
496                 RETURN_FALSE;
497             }
498 		} else {
499 			retval = xmlTextWriterWriteElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content);
500 		}
501 		if (retval != -1) {
502 			RETURN_TRUE;
503 		}
504 	}
505 
506 	RETURN_FALSE;
507 }
508 /* }}} */
509 
510 /* {{{ Create start PI tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_pi)511 PHP_FUNCTION(xmlwriter_start_pi)
512 {
513 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterStartPI, "PI target");
514 }
515 /* }}} */
516 
517 /* {{{ End current PI - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_pi)518 PHP_FUNCTION(xmlwriter_end_pi)
519 {
520 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndPI);
521 }
522 /* }}} */
523 
524 /* {{{ Write full PI tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_pi)525 PHP_FUNCTION(xmlwriter_write_pi)
526 {
527 	xmlTextWriterPtr ptr;
528 	char *name, *content;
529 	size_t name_len, content_len;
530 	int retval;
531 	zval *self;
532 
533 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &self, xmlwriter_class_entry_ce,
534 		&name, &name_len, &content, &content_len) == FAILURE) {
535 		RETURN_THROWS();
536 	}
537 	XMLWRITER_FROM_OBJECT(ptr, self);
538 
539 	XMLW_NAME_CHK(2, "PI target");
540 
541 	if (ptr) {
542 		retval = xmlTextWriterWritePI(ptr, (xmlChar *)name, (xmlChar *)content);
543 		if (retval != -1) {
544 			RETURN_TRUE;
545 		}
546 	}
547 
548 	RETURN_FALSE;
549 }
550 /* }}} */
551 
552 /* {{{ Create start CDATA tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_cdata)553 PHP_FUNCTION(xmlwriter_start_cdata)
554 {
555 	xmlTextWriterPtr ptr;
556 	int retval;
557 	zval *self;
558 
559 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &self, xmlwriter_class_entry_ce) == FAILURE) {
560 		RETURN_THROWS();
561 	}
562 	XMLWRITER_FROM_OBJECT(ptr, self);
563 
564 	if (ptr) {
565 		retval = xmlTextWriterStartCDATA(ptr);
566 		if (retval != -1) {
567 			RETURN_TRUE;
568 		}
569 	}
570 
571 	RETURN_FALSE;
572 }
573 /* }}} */
574 
575 /* {{{ End current CDATA - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_cdata)576 PHP_FUNCTION(xmlwriter_end_cdata)
577 {
578 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndCDATA);
579 }
580 /* }}} */
581 
582 /* {{{ Write full CDATA tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_cdata)583 PHP_FUNCTION(xmlwriter_write_cdata)
584 {
585 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterWriteCDATA, NULL);
586 }
587 /* }}} */
588 
589 /* {{{ Write text - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_raw)590 PHP_FUNCTION(xmlwriter_write_raw)
591 {
592 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterWriteRaw, NULL);
593 }
594 /* }}} */
595 
596 /* {{{ Write text - returns FALSE on error */
PHP_FUNCTION(xmlwriter_text)597 PHP_FUNCTION(xmlwriter_text)
598 {
599 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterWriteString, NULL);
600 }
601 /* }}} */
602 
603 /* {{{ Create start comment - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_comment)604 PHP_FUNCTION(xmlwriter_start_comment)
605 {
606 	xmlTextWriterPtr ptr;
607 	int retval;
608 	zval *self;
609 
610 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &self, xmlwriter_class_entry_ce) == FAILURE) {
611 		RETURN_THROWS();
612 	}
613 	XMLWRITER_FROM_OBJECT(ptr, self);
614 
615 	if (ptr) {
616 		retval = xmlTextWriterStartComment(ptr);
617 		if (retval != -1) {
618 			RETURN_TRUE;
619 		}
620 	}
621 
622 	RETURN_FALSE;
623 }
624 /* }}} */
625 
626 /* {{{ Create end comment - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_comment)627 PHP_FUNCTION(xmlwriter_end_comment)
628 {
629 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndComment);
630 }
631 /* }}} */
632 
633 /* {{{ Write full comment tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_comment)634 PHP_FUNCTION(xmlwriter_write_comment)
635 {
636 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterWriteComment, NULL);
637 }
638 /* }}} */
639 
640 /* {{{ Create document tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_document)641 PHP_FUNCTION(xmlwriter_start_document)
642 {
643 	xmlTextWriterPtr ptr;
644 	char *version = NULL, *enc = NULL, *alone = NULL;
645 	size_t version_len, enc_len, alone_len;
646 	int retval;
647 	zval *self;
648 
649 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|s!s!s!", &self, xmlwriter_class_entry_ce, &version, &version_len, &enc, &enc_len, &alone, &alone_len) == FAILURE) {
650 		RETURN_THROWS();
651 	}
652 	XMLWRITER_FROM_OBJECT(ptr, self);
653 
654 	if (ptr) {
655 		retval = xmlTextWriterStartDocument(ptr, version, enc, alone);
656 		if (retval != -1) {
657 			RETURN_TRUE;
658 		}
659 	}
660 
661 	RETURN_FALSE;
662 }
663 /* }}} */
664 
665 /* {{{ End current document - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_document)666 PHP_FUNCTION(xmlwriter_end_document)
667 {
668 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndDocument);
669 }
670 /* }}} */
671 
672 /* {{{ Create start DTD tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_dtd)673 PHP_FUNCTION(xmlwriter_start_dtd)
674 {
675 	xmlTextWriterPtr ptr;
676 	char *name, *pubid = NULL, *sysid = NULL;
677 	size_t name_len, pubid_len, sysid_len;
678 	int retval;
679 	zval *self;
680 
681 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|s!s!", &self, xmlwriter_class_entry_ce, &name, &name_len, &pubid, &pubid_len, &sysid, &sysid_len) == FAILURE) {
682 		RETURN_THROWS();
683 	}
684 	XMLWRITER_FROM_OBJECT(ptr, self);
685 
686 	if (ptr) {
687 		retval = xmlTextWriterStartDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid);
688 		if (retval != -1) {
689 			RETURN_TRUE;
690 		}
691 	}
692 
693 	RETURN_FALSE;
694 }
695 /* }}} */
696 
697 /* {{{ End current DTD - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_dtd)698 PHP_FUNCTION(xmlwriter_end_dtd)
699 {
700 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndDTD);
701 }
702 /* }}} */
703 
704 /* {{{ Write full DTD tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_dtd)705 PHP_FUNCTION(xmlwriter_write_dtd)
706 {
707 	xmlTextWriterPtr ptr;
708 	char *name, *pubid = NULL, *sysid = NULL, *subset = NULL;
709 	size_t name_len, pubid_len, sysid_len, subset_len;
710 	int retval;
711 	zval *self;
712 
713 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|s!s!s!", &self, xmlwriter_class_entry_ce, &name, &name_len, &pubid, &pubid_len, &sysid, &sysid_len, &subset, &subset_len) == FAILURE) {
714 		RETURN_THROWS();
715 	}
716 	XMLWRITER_FROM_OBJECT(ptr, self);
717 
718 	if (ptr) {
719 		retval = xmlTextWriterWriteDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)subset);
720 		if (retval != -1) {
721 			RETURN_TRUE;
722 		}
723 	}
724 
725 	RETURN_FALSE;
726 }
727 /* }}} */
728 
729 /* {{{ Create start DTD element - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_dtd_element)730 PHP_FUNCTION(xmlwriter_start_dtd_element)
731 {
732 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterStartDTDElement, "element name");
733 }
734 /* }}} */
735 
736 /* {{{ End current DTD element - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_dtd_element)737 PHP_FUNCTION(xmlwriter_end_dtd_element)
738 {
739 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndDTDElement);
740 }
741 /* }}} */
742 
743 /* {{{ Write full DTD element tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_dtd_element)744 PHP_FUNCTION(xmlwriter_write_dtd_element)
745 {
746 	xmlTextWriterPtr ptr;
747 	char *name, *content;
748 	size_t name_len, content_len;
749 	int retval;
750 	zval *self;
751 
752 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &self, xmlwriter_class_entry_ce,
753 		&name, &name_len, &content, &content_len) == FAILURE) {
754 		RETURN_THROWS();
755 	}
756 	XMLWRITER_FROM_OBJECT(ptr, self);
757 
758 	XMLW_NAME_CHK(2, "element name");
759 
760 	if (ptr) {
761 		retval = xmlTextWriterWriteDTDElement(ptr, (xmlChar *)name, (xmlChar *)content);
762 		if (retval != -1) {
763 			RETURN_TRUE;
764 		}
765 	}
766 
767 	RETURN_FALSE;
768 }
769 /* }}} */
770 
771 /* {{{ Create start DTD AttList - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_dtd_attlist)772 PHP_FUNCTION(xmlwriter_start_dtd_attlist)
773 {
774 	php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterStartDTDAttlist, "element name");
775 }
776 /* }}} */
777 
778 /* {{{ End current DTD AttList - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_dtd_attlist)779 PHP_FUNCTION(xmlwriter_end_dtd_attlist)
780 {
781 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndDTDAttlist);
782 }
783 /* }}} */
784 
785 /* {{{ Write full DTD AttList tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_dtd_attlist)786 PHP_FUNCTION(xmlwriter_write_dtd_attlist)
787 {
788 	xmlTextWriterPtr ptr;
789 	char *name, *content;
790 	size_t name_len, content_len;
791 	int retval;
792 	zval *self;
793 
794 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &self, xmlwriter_class_entry_ce,
795 		&name, &name_len, &content, &content_len) == FAILURE) {
796 		RETURN_THROWS();
797 	}
798 	XMLWRITER_FROM_OBJECT(ptr, self);
799 
800 	XMLW_NAME_CHK(2, "element name");
801 
802 	if (ptr) {
803 		retval = xmlTextWriterWriteDTDAttlist(ptr, (xmlChar *)name, (xmlChar *)content);
804 		if (retval != -1) {
805 			RETURN_TRUE;
806 		}
807 	}
808 
809 	RETURN_FALSE;
810 }
811 /* }}} */
812 
813 /* {{{ Create start DTD Entity - returns FALSE on error */
PHP_FUNCTION(xmlwriter_start_dtd_entity)814 PHP_FUNCTION(xmlwriter_start_dtd_entity)
815 {
816 	xmlTextWriterPtr ptr;
817 	char *name;
818 	size_t name_len;
819 	int retval;
820 	bool isparm;
821 	zval *self;
822 
823 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Osb", &self, xmlwriter_class_entry_ce, &name, &name_len, &isparm) == FAILURE) {
824 		RETURN_THROWS();
825 	}
826 	XMLWRITER_FROM_OBJECT(ptr, self);
827 
828 	XMLW_NAME_CHK(2, "attribute name");
829 
830 	if (ptr) {
831 		retval = xmlTextWriterStartDTDEntity(ptr, isparm, (xmlChar *)name);
832 		if (retval != -1) {
833 			RETURN_TRUE;
834 		}
835 	}
836 
837 	RETURN_FALSE;
838 }
839 /* }}} */
840 
841 /* {{{ End current DTD Entity - returns FALSE on error */
PHP_FUNCTION(xmlwriter_end_dtd_entity)842 PHP_FUNCTION(xmlwriter_end_dtd_entity)
843 {
844 	php_xmlwriter_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextWriterEndDTDEntity);
845 }
846 /* }}} */
847 
848 /* {{{ Write full DTD Entity tag - returns FALSE on error */
PHP_FUNCTION(xmlwriter_write_dtd_entity)849 PHP_FUNCTION(xmlwriter_write_dtd_entity)
850 {
851 	xmlTextWriterPtr ptr;
852 	char *name, *content;
853 	size_t name_len, content_len;
854 	int retval;
855 	/* Optional parameters */
856 	char *pubid = NULL, *sysid = NULL, *ndataid = NULL;
857 	bool pe = 0;
858 	size_t pubid_len, sysid_len, ndataid_len;
859 	zval *self;
860 
861 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss|bs!s!s!", &self, xmlwriter_class_entry_ce,
862 		&name, &name_len, &content, &content_len, &pe, &pubid, &pubid_len,
863 		&sysid, &sysid_len, &ndataid, &ndataid_len) == FAILURE) {
864 		RETURN_THROWS();
865 	}
866 	XMLWRITER_FROM_OBJECT(ptr, self);
867 
868 	XMLW_NAME_CHK(2, "element name");
869 
870 	if (ptr) {
871 		retval = xmlTextWriterWriteDTDEntity(ptr, pe, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)ndataid, (xmlChar *)content);
872 		if (retval != -1) {
873 			RETURN_TRUE;
874 		}
875 	}
876 
877 	RETURN_FALSE;
878 }
879 /* }}} */
880 
881 /* {{{ Create new xmlwriter using source uri for output */
PHP_FUNCTION(xmlwriter_open_uri)882 PHP_FUNCTION(xmlwriter_open_uri)
883 {
884 	char *valid_file = NULL;
885 	xmlTextWriterPtr ptr;
886 	char *source;
887 	char resolved_path[MAXPATHLEN + 1];
888 	size_t source_len;
889 	zval *self = getThis();
890 	ze_xmlwriter_object *ze_obj = NULL;
891 
892 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &source, &source_len) == FAILURE) {
893 		RETURN_THROWS();
894 	}
895 
896 	if (self) {
897 		/* We do not use XMLWRITER_FROM_OBJECT, xmlwriter init function here */
898 		ze_obj = Z_XMLWRITER_P(self);
899 	}
900 
901 	if (source_len == 0) {
902 		zend_argument_value_error(1, "cannot be empty");
903 		RETURN_THROWS();
904 	}
905 
906 	valid_file = _xmlwriter_get_valid_file_path(source, resolved_path, MAXPATHLEN);
907 	if (!valid_file) {
908 		php_error_docref(NULL, E_WARNING, "Unable to resolve file path");
909 		RETURN_FALSE;
910 	}
911 
912 	ptr = xmlNewTextWriterFilename(valid_file, 0);
913 
914 	if (!ptr) {
915 		RETURN_FALSE;
916 	}
917 
918 	if (self) {
919 		if (ze_obj->ptr) {
920 			xmlFreeTextWriter(ze_obj->ptr);
921 		}
922 		if (ze_obj->output) {
923 			xmlBufferFree(ze_obj->output);
924 		}
925 		ze_obj->ptr = ptr;
926 		ze_obj->output = NULL;
927 		RETURN_TRUE;
928 	} else {
929 		ze_obj = php_xmlwriter_fetch_object(xmlwriter_object_new(xmlwriter_class_entry_ce));
930 		ze_obj->ptr = ptr;
931 		ze_obj->output = NULL;
932 		RETURN_OBJ(&ze_obj->std);
933 	}
934 }
935 /* }}} */
936 
937 /* {{{ Create new xmlwriter using memory for string output */
PHP_FUNCTION(xmlwriter_open_memory)938 PHP_FUNCTION(xmlwriter_open_memory)
939 {
940 	xmlTextWriterPtr ptr;
941 	xmlBufferPtr buffer;
942 	zval *self = getThis();
943 	ze_xmlwriter_object *ze_obj = NULL;
944 
945 	if (zend_parse_parameters_none() == FAILURE) {
946 		RETURN_THROWS();
947 	}
948 
949 	if (self) {
950 		/* We do not use XMLWRITER_FROM_OBJECT, xmlwriter init function here */
951 		ze_obj = Z_XMLWRITER_P(self);
952 	}
953 
954 	buffer = xmlBufferCreate();
955 
956 	if (buffer == NULL) {
957 		php_error_docref(NULL, E_WARNING, "Unable to create output buffer");
958 		RETURN_FALSE;
959 	}
960 
961 	ptr = xmlNewTextWriterMemory(buffer, 0);
962 	if (! ptr) {
963 		xmlBufferFree(buffer);
964 		RETURN_FALSE;
965 	}
966 
967 	if (self) {
968 		if (ze_obj->ptr) {
969 			xmlFreeTextWriter(ze_obj->ptr);
970 		}
971 		if (ze_obj->output) {
972 			xmlBufferFree(ze_obj->output);
973 		}
974 		ze_obj->ptr = ptr;
975 		ze_obj->output = buffer;
976 		RETURN_TRUE;
977 	} else {
978 		ze_obj = php_xmlwriter_fetch_object(xmlwriter_object_new(xmlwriter_class_entry_ce));
979 		ze_obj->ptr = ptr;
980 		ze_obj->output = buffer;
981 		RETURN_OBJ(&ze_obj->std);
982 	}
983 
984 }
985 /* }}} */
986 
987 /* {{{ php_xmlwriter_flush */
php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS,int force_string)988 static void php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS, int force_string) {
989 	xmlTextWriterPtr ptr;
990 	xmlBufferPtr buffer;
991 	bool empty = 1;
992 	int output_bytes;
993 	zval *self;
994 
995 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|b", &self, xmlwriter_class_entry_ce, &empty) == FAILURE) {
996 		RETURN_THROWS();
997 	}
998 	XMLWRITER_FROM_OBJECT(ptr, self);
999 
1000 	if (ptr) {
1001 		buffer = Z_XMLWRITER_P(self)->output;
1002 		if (force_string == 1 && buffer == NULL) {
1003 			RETURN_EMPTY_STRING();
1004 		}
1005 		output_bytes = xmlTextWriterFlush(ptr);
1006 		if (buffer) {
1007 			const xmlChar *content = xmlBufferContent(buffer);
1008 			RETVAL_STRING((const char *) content);
1009 			if (empty) {
1010 				xmlBufferEmpty(buffer);
1011 			}
1012 		} else {
1013 			RETVAL_LONG(output_bytes);
1014 		}
1015 		return;
1016 	}
1017 
1018 	RETURN_EMPTY_STRING();
1019 }
1020 /* }}} */
1021 
1022 /* {{{ Output current buffer as string */
PHP_FUNCTION(xmlwriter_output_memory)1023 PHP_FUNCTION(xmlwriter_output_memory)
1024 {
1025 	php_xmlwriter_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1026 }
1027 /* }}} */
1028 
1029 /* {{{ Output current buffer */
PHP_FUNCTION(xmlwriter_flush)1030 PHP_FUNCTION(xmlwriter_flush)
1031 {
1032 	php_xmlwriter_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1033 }
1034 /* }}} */
1035 
1036 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(xmlwriter)1037 static PHP_MINIT_FUNCTION(xmlwriter)
1038 {
1039 	memcpy(&xmlwriter_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1040 	xmlwriter_object_handlers.offset = XtOffsetOf(ze_xmlwriter_object, std);
1041 	xmlwriter_object_handlers.dtor_obj = xmlwriter_object_dtor;
1042 	xmlwriter_object_handlers.free_obj = xmlwriter_object_free_storage;
1043 	xmlwriter_object_handlers.clone_obj = NULL;
1044 	xmlwriter_class_entry_ce = register_class_XMLWriter();
1045 	xmlwriter_class_entry_ce->create_object = xmlwriter_object_new;
1046 
1047 	return SUCCESS;
1048 }
1049 /* }}} */
1050 
1051 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(xmlwriter)1052 static PHP_MSHUTDOWN_FUNCTION(xmlwriter)
1053 {
1054 	return SUCCESS;
1055 }
1056 /* }}} */
1057 
1058 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(xmlwriter)1059 static PHP_MINFO_FUNCTION(xmlwriter)
1060 {
1061 	php_info_print_table_start();
1062 	{
1063 		php_info_print_table_row(2, "XMLWriter", "enabled");
1064 	}
1065 	php_info_print_table_end();
1066 }
1067 /* }}} */
1068