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