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