xref: /PHP-7.0/ext/tidy/tidy.c (revision 478f119a)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2017 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: John Coggeshall <john@php.net>                               |
16   +----------------------------------------------------------------------+
17 */
18 
19 /* $Id: 4e307eec06aa0ac776a415ba4d74290bfd9e0c73 $ */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "php.h"
26 #include "php_tidy.h"
27 
28 #if HAVE_TIDY
29 
30 #include "php_ini.h"
31 #include "ext/standard/info.h"
32 
33 #include "tidy.h"
34 #include "buffio.h"
35 
36 /* compatibility with older versions of libtidy */
37 #ifndef TIDY_CALL
38 #define TIDY_CALL
39 #endif
40 
41 /* {{{ ext/tidy macros
42 */
43 #define FIX_BUFFER(bptr) do { if ((bptr)->size) { (bptr)->bp[(bptr)->size-1] = '\0'; } } while(0)
44 
45 #define TIDY_SET_CONTEXT \
46     zval *object = getThis();
47 
48 #define TIDY_FETCH_OBJECT	\
49 	PHPTidyObj *obj;	\
50 	TIDY_SET_CONTEXT; \
51 	if (object) {	\
52 		if (zend_parse_parameters_none() == FAILURE) {	\
53 			return;	\
54 		}	\
55 	} else {	\
56 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "O", &object, tidy_ce_doc) == FAILURE) {	\
57 			RETURN_FALSE;	\
58 		}	\
59 	}	\
60 	obj = Z_TIDY_P(object);	\
61 
62 #define TIDY_FETCH_ONLY_OBJECT	\
63 	PHPTidyObj *obj;	\
64 	TIDY_SET_CONTEXT; \
65 	if (zend_parse_parameters_none() == FAILURE) {	\
66 		return;	\
67 	}	\
68 	obj = Z_TIDY_P(object);	\
69 
70 #define TIDY_APPLY_CONFIG_ZVAL(_doc, _val) \
71     if(_val) { \
72         if(Z_TYPE_P(_val) == IS_ARRAY) { \
73             _php_tidy_apply_config_array(_doc, Z_ARRVAL_P(_val)); \
74         } else { \
75             convert_to_string_ex(_val); \
76             TIDY_OPEN_BASE_DIR_CHECK(Z_STRVAL_P(_val)); \
77             switch (tidyLoadConfig(_doc, Z_STRVAL_P(_val))) { \
78               case -1: \
79                 php_error_docref(NULL, E_WARNING, "Could not load configuration file '%s'", Z_STRVAL_P(_val)); \
80                 break; \
81               case 1: \
82                 php_error_docref(NULL, E_NOTICE, "There were errors while parsing the configuration file '%s'", Z_STRVAL_P(_val)); \
83                 break; \
84             } \
85         } \
86     }
87 
88 #define REGISTER_TIDY_CLASS(classname, name, parent, __flags) \
89 	{ \
90 		zend_class_entry ce; \
91 		INIT_CLASS_ENTRY(ce, # classname, tidy_funcs_ ## name); \
92 		ce.create_object = tidy_object_new_ ## name; \
93 		tidy_ce_ ## name = zend_register_internal_class_ex(&ce, parent); \
94 		tidy_ce_ ## name->ce_flags |= __flags;  \
95 		memcpy(&tidy_object_handlers_ ## name, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
96 		tidy_object_handlers_ ## name.clone_obj = NULL; \
97 	}
98 
99 #define TIDY_TAG_CONST(tag) REGISTER_LONG_CONSTANT("TIDY_TAG_" #tag, TidyTag_##tag, CONST_CS | CONST_PERSISTENT)
100 #define TIDY_NODE_CONST(name, type) REGISTER_LONG_CONSTANT("TIDY_NODETYPE_" #name, TidyNode_##type, CONST_CS | CONST_PERSISTENT)
101 
102 #ifndef TRUE
103 #define TRUE 1
104 #endif
105 
106 #ifndef FALSE
107 #define FALSE 0
108 #endif
109 
110 #define ADD_PROPERTY_STRING(_table, _key, _string) \
111 	{ \
112 		zval tmp; \
113 		if (_string) { \
114 			ZVAL_STRING(&tmp, (char *)_string); \
115 		} else { \
116 			ZVAL_EMPTY_STRING(&tmp); \
117 		} \
118 		zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
119 	}
120 
121 #define ADD_PROPERTY_STRINGL(_table, _key, _string, _len) \
122    { \
123        zval tmp; \
124        if (_string) { \
125            ZVAL_STRINGL(&tmp, (char *)_string, _len); \
126        } else { \
127            ZVAL_EMPTY_STRING(&tmp); \
128        } \
129        zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
130    }
131 
132 #define ADD_PROPERTY_LONG(_table, _key, _long) \
133 	{ \
134 		zval tmp; \
135 		ZVAL_LONG(&tmp, _long); \
136 		zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
137 	}
138 
139 #define ADD_PROPERTY_NULL(_table, _key) \
140 	{ \
141 		zval tmp; \
142 		ZVAL_NULL(&tmp); \
143 		zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
144 	}
145 
146 #define ADD_PROPERTY_BOOL(_table, _key, _bool) \
147     { \
148 		zval tmp; \
149 		ZVAL_BOOL(&tmp, _bool); \
150 		zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
151 	}
152 
153 #define TIDY_OPEN_BASE_DIR_CHECK(filename) \
154 if (php_check_open_basedir(filename)) { \
155 	RETURN_FALSE; \
156 } \
157 
158 #define TIDY_SET_DEFAULT_CONFIG(_doc) \
159 	if (TG(default_config) && TG(default_config)[0]) { \
160 		if (tidyLoadConfig(_doc, TG(default_config)) < 0) { \
161 			php_error_docref(NULL, E_WARNING, "Unable to load Tidy configuration file at '%s'.", TG(default_config)); \
162 		} \
163 	}
164 /* }}} */
165 
166 /* {{{ ext/tidy structs
167 */
168 typedef struct _PHPTidyDoc PHPTidyDoc;
169 typedef struct _PHPTidyObj PHPTidyObj;
170 
171 typedef enum {
172 	is_node,
173 	is_doc
174 } tidy_obj_type;
175 
176 typedef enum {
177 	is_root_node,
178 	is_html_node,
179 	is_head_node,
180 	is_body_node
181 } tidy_base_nodetypes;
182 
183 struct _PHPTidyDoc {
184 	TidyDoc			doc;
185 	TidyBuffer		*errbuf;
186 	unsigned int	ref_count;
187 	unsigned int    initialized:1;
188 };
189 
190 struct _PHPTidyObj {
191 	TidyNode		node;
192 	tidy_obj_type	type;
193 	PHPTidyDoc		*ptdoc;
194 	zend_object		std;
195 };
196 
php_tidy_fetch_object(zend_object * obj)197 static inline PHPTidyObj *php_tidy_fetch_object(zend_object *obj) {
198 	return (PHPTidyObj *)((char*)(obj) - XtOffsetOf(PHPTidyObj, std));
199 }
200 
201 #define Z_TIDY_P(zv) php_tidy_fetch_object(Z_OBJ_P((zv)))
202 /* }}} */
203 
204 /* {{{ ext/tidy prototypes
205 */
206 static zend_string *php_tidy_file_to_mem(char *, zend_bool);
207 static void tidy_object_free_storage(zend_object *);
208 static zend_object *tidy_object_new_node(zend_class_entry *);
209 static zend_object *tidy_object_new_doc(zend_class_entry *);
210 static zval * tidy_instanciate(zend_class_entry *, zval *);
211 static int tidy_doc_cast_handler(zval *, zval *, int);
212 static int tidy_node_cast_handler(zval *, zval *, int);
213 static void tidy_doc_update_properties(PHPTidyObj *);
214 static void tidy_add_default_properties(PHPTidyObj *, tidy_obj_type);
215 static void *php_tidy_get_opt_val(PHPTidyDoc *, TidyOption, TidyOptionType *);
216 static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetypes);
217 static int _php_tidy_set_tidy_opt(TidyDoc, char *, zval *);
218 static int _php_tidy_apply_config_array(TidyDoc doc, HashTable *ht_options);
219 static void _php_tidy_register_nodetypes(INIT_FUNC_ARGS);
220 static void _php_tidy_register_tags(INIT_FUNC_ARGS);
221 static PHP_INI_MH(php_tidy_set_clean_output);
222 static void php_tidy_clean_output_start(const char *name, size_t name_len);
223 static php_output_handler *php_tidy_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags);
224 static int php_tidy_output_handler(void **nothing, php_output_context *output_context);
225 
226 static PHP_MINIT_FUNCTION(tidy);
227 static PHP_MSHUTDOWN_FUNCTION(tidy);
228 static PHP_RINIT_FUNCTION(tidy);
229 static PHP_MINFO_FUNCTION(tidy);
230 
231 static PHP_FUNCTION(tidy_getopt);
232 static PHP_FUNCTION(tidy_parse_string);
233 static PHP_FUNCTION(tidy_parse_file);
234 static PHP_FUNCTION(tidy_clean_repair);
235 static PHP_FUNCTION(tidy_repair_string);
236 static PHP_FUNCTION(tidy_repair_file);
237 static PHP_FUNCTION(tidy_diagnose);
238 static PHP_FUNCTION(tidy_get_output);
239 static PHP_FUNCTION(tidy_get_error_buffer);
240 static PHP_FUNCTION(tidy_get_release);
241 static PHP_FUNCTION(tidy_get_config);
242 static PHP_FUNCTION(tidy_get_status);
243 static PHP_FUNCTION(tidy_get_html_ver);
244 #if HAVE_TIDYOPTGETDOC
245 static PHP_FUNCTION(tidy_get_opt_doc);
246 #endif
247 static PHP_FUNCTION(tidy_is_xhtml);
248 static PHP_FUNCTION(tidy_is_xml);
249 static PHP_FUNCTION(tidy_error_count);
250 static PHP_FUNCTION(tidy_warning_count);
251 static PHP_FUNCTION(tidy_access_count);
252 static PHP_FUNCTION(tidy_config_count);
253 
254 static PHP_FUNCTION(tidy_get_root);
255 static PHP_FUNCTION(tidy_get_html);
256 static PHP_FUNCTION(tidy_get_head);
257 static PHP_FUNCTION(tidy_get_body);
258 
259 static TIDY_DOC_METHOD(__construct);
260 static TIDY_DOC_METHOD(parseFile);
261 static TIDY_DOC_METHOD(parseString);
262 
263 static TIDY_NODE_METHOD(hasChildren);
264 static TIDY_NODE_METHOD(hasSiblings);
265 static TIDY_NODE_METHOD(isComment);
266 static TIDY_NODE_METHOD(isHtml);
267 static TIDY_NODE_METHOD(isText);
268 static TIDY_NODE_METHOD(isJste);
269 static TIDY_NODE_METHOD(isAsp);
270 static TIDY_NODE_METHOD(isPhp);
271 static TIDY_NODE_METHOD(getParent);
272 static TIDY_NODE_METHOD(__construct);
273 /* }}} */
274 
275 ZEND_DECLARE_MODULE_GLOBALS(tidy)
276 
277 PHP_INI_BEGIN()
278 STD_PHP_INI_ENTRY("tidy.default_config",	"",		PHP_INI_SYSTEM,		OnUpdateString,				default_config,		zend_tidy_globals,	tidy_globals)
279 STD_PHP_INI_ENTRY("tidy.clean_output",		"0",	PHP_INI_USER,		php_tidy_set_clean_output,	clean_output,		zend_tidy_globals,	tidy_globals)
280 PHP_INI_END()
281 
282 /* {{{ arginfo */
283 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_parse_string, 0, 0, 1)
284 	ZEND_ARG_INFO(0, input)
285 	ZEND_ARG_INFO(0, config_options)
286 	ZEND_ARG_INFO(0, encoding)
287 ZEND_END_ARG_INFO()
288 
289 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_error_buffer, 0)
290 ZEND_END_ARG_INFO()
291 
292 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_output, 0)
293 ZEND_END_ARG_INFO()
294 
295 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_parse_file, 0, 0, 1)
296 	ZEND_ARG_INFO(0, file)
297 	ZEND_ARG_INFO(0, config_options)
298 	ZEND_ARG_INFO(0, encoding)
299 	ZEND_ARG_INFO(0, use_include_path)
300 ZEND_END_ARG_INFO()
301 
302 ZEND_BEGIN_ARG_INFO(arginfo_tidy_clean_repair, 0)
303 ZEND_END_ARG_INFO()
304 
305 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_repair_string, 0, 0, 1)
306 	ZEND_ARG_INFO(0, data)
307 	ZEND_ARG_INFO(0, config_file)
308 	ZEND_ARG_INFO(0, encoding)
309 ZEND_END_ARG_INFO()
310 
311 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_repair_file, 0, 0, 1)
312 	ZEND_ARG_INFO(0, filename)
313 	ZEND_ARG_INFO(0, config_file)
314 	ZEND_ARG_INFO(0, encoding)
315 	ZEND_ARG_INFO(0, use_include_path)
316 ZEND_END_ARG_INFO()
317 
318 ZEND_BEGIN_ARG_INFO(arginfo_tidy_diagnose, 0)
319 ZEND_END_ARG_INFO()
320 
321 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_release, 0)
322 ZEND_END_ARG_INFO()
323 
324 #if HAVE_TIDYOPTGETDOC
325 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_opt_doc, 0, 0, 2)
326 	ZEND_ARG_INFO(0, resource)
327 	ZEND_ARG_INFO(0, optname)
328 ZEND_END_ARG_INFO()
329 #endif
330 
331 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_config, 0)
332 ZEND_END_ARG_INFO()
333 
334 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_status, 0)
335 ZEND_END_ARG_INFO()
336 
337 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_html_ver, 0)
338 ZEND_END_ARG_INFO()
339 
340 ZEND_BEGIN_ARG_INFO(arginfo_tidy_is_xhtml, 0)
341 ZEND_END_ARG_INFO()
342 
343 ZEND_BEGIN_ARG_INFO(arginfo_tidy_is_xml, 0)
344 ZEND_END_ARG_INFO()
345 
346 ZEND_BEGIN_ARG_INFO(arginfo_tidy_error_count, 0)
347 ZEND_END_ARG_INFO()
348 
349 ZEND_BEGIN_ARG_INFO(arginfo_tidy_warning_count, 0)
350 ZEND_END_ARG_INFO()
351 
352 ZEND_BEGIN_ARG_INFO(arginfo_tidy_access_count, 0)
353 ZEND_END_ARG_INFO()
354 
355 ZEND_BEGIN_ARG_INFO(arginfo_tidy_config_count, 0)
356 ZEND_END_ARG_INFO()
357 
358 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_getopt, 0, 0, 1)
359 	ZEND_ARG_INFO(0, option)
360 ZEND_END_ARG_INFO()
361 
362 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_root, 0)
363 ZEND_END_ARG_INFO()
364 
365 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_html, 0)
366 ZEND_END_ARG_INFO()
367 
368 ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_head, 0)
369 ZEND_END_ARG_INFO()
370 
371 ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_body, 0, 0, 1)
372 	ZEND_ARG_INFO(0, tidy)
373 ZEND_END_ARG_INFO()
374 /* }}} */
375 
376 static const zend_function_entry tidy_functions[] = {
377 	PHP_FE(tidy_getopt,             arginfo_tidy_getopt)
378 	PHP_FE(tidy_parse_string,       arginfo_tidy_parse_string)
379 	PHP_FE(tidy_parse_file,         arginfo_tidy_parse_file)
380 	PHP_FE(tidy_get_output,         arginfo_tidy_get_output)
381 	PHP_FE(tidy_get_error_buffer,   arginfo_tidy_get_error_buffer)
382 	PHP_FE(tidy_clean_repair,       arginfo_tidy_clean_repair)
383 	PHP_FE(tidy_repair_string,	arginfo_tidy_repair_string)
384 	PHP_FE(tidy_repair_file,	arginfo_tidy_repair_file)
385 	PHP_FE(tidy_diagnose,           arginfo_tidy_diagnose)
386 	PHP_FE(tidy_get_release,	arginfo_tidy_get_release)
387 	PHP_FE(tidy_get_config,		arginfo_tidy_get_config)
388 	PHP_FE(tidy_get_status,		arginfo_tidy_get_status)
389 	PHP_FE(tidy_get_html_ver,	arginfo_tidy_get_html_ver)
390 	PHP_FE(tidy_is_xhtml,		arginfo_tidy_is_xhtml)
391 	PHP_FE(tidy_is_xml,		arginfo_tidy_is_xml)
392 	PHP_FE(tidy_error_count,	arginfo_tidy_error_count)
393 	PHP_FE(tidy_warning_count,	arginfo_tidy_warning_count)
394 	PHP_FE(tidy_access_count,	arginfo_tidy_access_count)
395 	PHP_FE(tidy_config_count,	arginfo_tidy_config_count)
396 #if HAVE_TIDYOPTGETDOC
397 	PHP_FE(tidy_get_opt_doc,	arginfo_tidy_get_opt_doc)
398 #endif
399 	PHP_FE(tidy_get_root,		arginfo_tidy_get_root)
400 	PHP_FE(tidy_get_head,		arginfo_tidy_get_head)
401 	PHP_FE(tidy_get_html,		arginfo_tidy_get_html)
402 	PHP_FE(tidy_get_body,		arginfo_tidy_get_body)
403 	PHP_FE_END
404 };
405 
406 static const zend_function_entry tidy_funcs_doc[] = {
407 	TIDY_METHOD_MAP(getOpt, tidy_getopt, NULL)
408 	TIDY_METHOD_MAP(cleanRepair, tidy_clean_repair, NULL)
409 	TIDY_DOC_ME(parseFile, NULL)
410 	TIDY_DOC_ME(parseString, NULL)
411 	TIDY_METHOD_MAP(repairString, tidy_repair_string, NULL)
412 	TIDY_METHOD_MAP(repairFile, tidy_repair_file, NULL)
413 	TIDY_METHOD_MAP(diagnose, tidy_diagnose, NULL)
414 	TIDY_METHOD_MAP(getRelease, tidy_get_release, NULL)
415 	TIDY_METHOD_MAP(getConfig, tidy_get_config, NULL)
416 	TIDY_METHOD_MAP(getStatus, tidy_get_status, NULL)
417 	TIDY_METHOD_MAP(getHtmlVer, tidy_get_html_ver, NULL)
418 #if HAVE_TIDYOPTGETDOC
419 	TIDY_METHOD_MAP(getOptDoc, tidy_get_opt_doc, NULL)
420 #endif
421 	TIDY_METHOD_MAP(isXhtml, tidy_is_xhtml, NULL)
422 	TIDY_METHOD_MAP(isXml, tidy_is_xml, NULL)
423 	TIDY_METHOD_MAP(root, tidy_get_root, NULL)
424 	TIDY_METHOD_MAP(head, tidy_get_head, NULL)
425 	TIDY_METHOD_MAP(html, tidy_get_html, NULL)
426 	TIDY_METHOD_MAP(body, tidy_get_body, NULL)
427 	TIDY_DOC_ME(__construct, NULL)
428 	PHP_FE_END
429 };
430 
431 static const zend_function_entry tidy_funcs_node[] = {
432 	TIDY_NODE_ME(hasChildren, NULL)
433 	TIDY_NODE_ME(hasSiblings, NULL)
434 	TIDY_NODE_ME(isComment, NULL)
435 	TIDY_NODE_ME(isHtml, NULL)
436 	TIDY_NODE_ME(isText, NULL)
437 	TIDY_NODE_ME(isJste, NULL)
438 	TIDY_NODE_ME(isAsp, NULL)
439 	TIDY_NODE_ME(isPhp, NULL)
440 	TIDY_NODE_ME(getParent, NULL)
441 	TIDY_NODE_PRIVATE_ME(__construct, NULL)
442 	PHP_FE_END
443 };
444 
445 static zend_class_entry *tidy_ce_doc, *tidy_ce_node;
446 
447 static zend_object_handlers tidy_object_handlers_doc;
448 static zend_object_handlers tidy_object_handlers_node;
449 
450 zend_module_entry tidy_module_entry = {
451 	STANDARD_MODULE_HEADER,
452 	"tidy",
453 	tidy_functions,
454 	PHP_MINIT(tidy),
455 	PHP_MSHUTDOWN(tidy),
456 	PHP_RINIT(tidy),
457 	NULL,
458 	PHP_MINFO(tidy),
459 	PHP_TIDY_VERSION,
460 	PHP_MODULE_GLOBALS(tidy),
461 	NULL,
462 	NULL,
463 	NULL,
464 	STANDARD_MODULE_PROPERTIES_EX
465 };
466 
467 #ifdef COMPILE_DL_TIDY
468 #ifdef ZTS
469 ZEND_TSRMLS_CACHE_DEFINE()
470 #endif
ZEND_GET_MODULE(tidy)471 ZEND_GET_MODULE(tidy)
472 #endif
473 
474 static void* TIDY_CALL php_tidy_malloc(size_t len)
475 {
476 	return emalloc(len);
477 }
478 
php_tidy_realloc(void * buf,size_t len)479 static void* TIDY_CALL php_tidy_realloc(void *buf, size_t len)
480 {
481 	return erealloc(buf, len);
482 }
483 
php_tidy_free(void * buf)484 static void TIDY_CALL php_tidy_free(void *buf)
485 {
486 	efree(buf);
487 }
488 
php_tidy_panic(ctmbstr msg)489 static void TIDY_CALL php_tidy_panic(ctmbstr msg)
490 {
491 	php_error_docref(NULL, E_ERROR, "Could not allocate memory for tidy! (Reason: %s)", (char *)msg);
492 }
493 
_php_tidy_set_tidy_opt(TidyDoc doc,char * optname,zval * value)494 static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value)
495 {
496 	TidyOption opt = tidyGetOptionByName(doc, optname);
497 	zval conv;
498 
499 	ZVAL_COPY_VALUE(&conv, value);
500 
501 	if (!opt) {
502 		php_error_docref(NULL, E_NOTICE, "Unknown Tidy Configuration Option '%s'", optname);
503 		return FAILURE;
504 	}
505 
506 	if (tidyOptIsReadOnly(opt)) {
507 		php_error_docref(NULL, E_NOTICE, "Attempting to set read-only option '%s'", optname);
508 		return FAILURE;
509 	}
510 
511 	switch(tidyOptGetType(opt)) {
512 		case TidyString:
513 			if (Z_TYPE(conv) != IS_STRING) {
514 				zval_copy_ctor(&conv);
515 				convert_to_string(&conv);
516 			}
517 			if (tidyOptSetValue(doc, tidyOptGetId(opt), Z_STRVAL(conv))) {
518 				if (Z_TYPE(conv) != Z_TYPE_P(value)) {
519 					zval_dtor(&conv);
520 				}
521 				return SUCCESS;
522 			}
523 			if (Z_TYPE(conv) != Z_TYPE_P(value)) {
524 				zval_dtor(&conv);
525 			}
526 			break;
527 
528 		case TidyInteger:
529 			if (Z_TYPE(conv) != IS_LONG) {
530 				zval_copy_ctor(&conv);
531 				convert_to_long(&conv);
532 			}
533 			if (tidyOptSetInt(doc, tidyOptGetId(opt), Z_LVAL(conv))) {
534 				return SUCCESS;
535 			}
536 			break;
537 
538 		case TidyBoolean:
539 			if (Z_TYPE(conv) != IS_LONG) {
540 				zval_copy_ctor(&conv);
541 				convert_to_long(&conv);
542 			}
543 			if (tidyOptSetBool(doc, tidyOptGetId(opt), Z_LVAL(conv))) {
544 				return SUCCESS;
545 			}
546 			break;
547 
548 		default:
549 			php_error_docref(NULL, E_WARNING, "Unable to determine type of configuration option");
550 			break;
551 	}
552 
553 	return FAILURE;
554 }
555 
php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS,zend_bool is_file)556 static void php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_file)
557 {
558 	char *enc = NULL;
559 	size_t enc_len = 0;
560 	zend_bool use_include_path = 0;
561 	TidyDoc doc;
562 	TidyBuffer *errbuf;
563 	zend_string *data, *arg1;
564 	zval *config = NULL;
565 
566 	if (is_file) {
567 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &arg1, &config, &enc, &enc_len, &use_include_path) == FAILURE) {
568 			RETURN_FALSE;
569 		}
570 		if (!(data = php_tidy_file_to_mem(ZSTR_VAL(arg1), use_include_path))) {
571 			RETURN_FALSE;
572 		}
573 	} else {
574 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zsb", &arg1, &config, &enc, &enc_len, &use_include_path) == FAILURE) {
575 			RETURN_FALSE;
576 		}
577 		data = arg1;
578 	}
579 
580 	if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(data))) {
581 		php_error_docref(NULL, E_WARNING, "Input string is too long");
582 		RETURN_FALSE;
583 	}
584 
585 	doc = tidyCreate();
586 	errbuf = emalloc(sizeof(TidyBuffer));
587 	tidyBufInit(errbuf);
588 
589 	if (tidySetErrorBuffer(doc, errbuf) != 0) {
590 		tidyBufFree(errbuf);
591 		efree(errbuf);
592 		tidyRelease(doc);
593 		php_error_docref(NULL, E_ERROR, "Could not set Tidy error buffer");
594 	}
595 
596 	tidyOptSetBool(doc, TidyForceOutput, yes);
597 	tidyOptSetBool(doc, TidyMark, no);
598 
599 	TIDY_SET_DEFAULT_CONFIG(doc);
600 
601 	if (config) {
602 		TIDY_APPLY_CONFIG_ZVAL(doc, config);
603 	}
604 
605 	if(enc_len) {
606 		if (tidySetCharEncoding(doc, enc) < 0) {
607 			php_error_docref(NULL, E_WARNING, "Could not set encoding '%s'", enc);
608 			RETVAL_FALSE;
609 		}
610 	}
611 
612 	if (data) {
613 		TidyBuffer buf;
614 
615 		tidyBufInit(&buf);
616 		tidyBufAttach(&buf, (byte *) ZSTR_VAL(data), (uint)ZSTR_LEN(data));
617 
618 		if (tidyParseBuffer(doc, &buf) < 0) {
619 			php_error_docref(NULL, E_WARNING, "%s", errbuf->bp);
620 			RETVAL_FALSE;
621 		} else {
622 			if (tidyCleanAndRepair(doc) >= 0) {
623 				TidyBuffer output;
624 				tidyBufInit(&output);
625 
626 				tidySaveBuffer (doc, &output);
627 				FIX_BUFFER(&output);
628 				RETVAL_STRINGL((char *) output.bp, output.size ? output.size-1 : 0);
629 				tidyBufFree(&output);
630 			} else {
631 				RETVAL_FALSE;
632 			}
633 		}
634 	}
635 
636 	if (is_file) {
637 		zend_string_release(data);
638 	}
639 
640 	tidyBufFree(errbuf);
641 	efree(errbuf);
642 	tidyRelease(doc);
643 }
644 
php_tidy_file_to_mem(char * filename,zend_bool use_include_path)645 static zend_string *php_tidy_file_to_mem(char *filename, zend_bool use_include_path)
646 {
647 	php_stream *stream;
648 	zend_string *data = NULL;
649 
650 	if (!(stream = php_stream_open_wrapper(filename, "rb", (use_include_path ? USE_PATH : 0), NULL))) {
651 		return NULL;
652 	}
653 	if ((data = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0)) == NULL) {
654 		data = ZSTR_EMPTY_ALLOC();
655 	}
656 	php_stream_close(stream);
657 
658 	return data;
659 }
660 
tidy_object_free_storage(zend_object * object)661 static void tidy_object_free_storage(zend_object *object)
662 {
663 	PHPTidyObj *intern = php_tidy_fetch_object(object);
664 
665 	zend_object_std_dtor(&intern->std);
666 
667 	if (intern->ptdoc) {
668 		intern->ptdoc->ref_count--;
669 
670 		if (intern->ptdoc->ref_count <= 0) {
671 			tidyBufFree(intern->ptdoc->errbuf);
672 			efree(intern->ptdoc->errbuf);
673 			tidyRelease(intern->ptdoc->doc);
674 			efree(intern->ptdoc);
675 		}
676 	}
677 }
678 
tidy_object_new(zend_class_entry * class_type,zend_object_handlers * handlers,tidy_obj_type objtype)679 static zend_object *tidy_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, tidy_obj_type objtype)
680 {
681 	PHPTidyObj *intern;
682 
683 	intern = ecalloc(1, sizeof(PHPTidyObj) + zend_object_properties_size(class_type));
684 	zend_object_std_init(&intern->std, class_type);
685 	object_properties_init(&intern->std, class_type);
686 
687 	switch(objtype) {
688 		case is_node:
689 			break;
690 
691 		case is_doc:
692 			intern->ptdoc = emalloc(sizeof(PHPTidyDoc));
693 			intern->ptdoc->doc = tidyCreate();
694 			intern->ptdoc->ref_count = 1;
695 			intern->ptdoc->initialized = 0;
696 			intern->ptdoc->errbuf = emalloc(sizeof(TidyBuffer));
697 			tidyBufInit(intern->ptdoc->errbuf);
698 
699 			if (tidySetErrorBuffer(intern->ptdoc->doc, intern->ptdoc->errbuf) != 0) {
700 				tidyBufFree(intern->ptdoc->errbuf);
701 				efree(intern->ptdoc->errbuf);
702 				tidyRelease(intern->ptdoc->doc);
703 				efree(intern->ptdoc);
704 				efree(intern);
705 				php_error_docref(NULL, E_ERROR, "Could not set Tidy error buffer");
706 			}
707 
708 			tidyOptSetBool(intern->ptdoc->doc, TidyForceOutput, yes);
709 			tidyOptSetBool(intern->ptdoc->doc, TidyMark, no);
710 
711 			TIDY_SET_DEFAULT_CONFIG(intern->ptdoc->doc);
712 
713 			tidy_add_default_properties(intern, is_doc);
714 			break;
715 	}
716 
717 	intern->std.handlers = handlers;
718 
719 	return &intern->std;
720 }
721 
tidy_object_new_node(zend_class_entry * class_type)722 static zend_object *tidy_object_new_node(zend_class_entry *class_type)
723 {
724 	return tidy_object_new(class_type, &tidy_object_handlers_node, is_node);
725 }
726 
tidy_object_new_doc(zend_class_entry * class_type)727 static zend_object *tidy_object_new_doc(zend_class_entry *class_type)
728 {
729 	return tidy_object_new(class_type, &tidy_object_handlers_doc, is_doc);
730 }
731 
tidy_instanciate(zend_class_entry * pce,zval * object)732 static zval * tidy_instanciate(zend_class_entry *pce, zval *object)
733 {
734 	object_init_ex(object, pce);
735 	return object;
736 }
737 
tidy_doc_cast_handler(zval * in,zval * out,int type)738 static int tidy_doc_cast_handler(zval *in, zval *out, int type)
739 {
740 	TidyBuffer output;
741 	PHPTidyObj *obj;
742 
743 	switch (type) {
744 		case IS_LONG:
745 			ZVAL_LONG(out, 0);
746 			break;
747 
748 		case IS_DOUBLE:
749 			ZVAL_DOUBLE(out, 0);
750 			break;
751 
752 		case _IS_BOOL:
753 			ZVAL_TRUE(out);
754 			break;
755 
756 		case IS_STRING:
757 			obj = Z_TIDY_P(in);
758 			tidyBufInit(&output);
759 			tidySaveBuffer (obj->ptdoc->doc, &output);
760 			ZVAL_STRINGL(out, (char *) output.bp, output.size ? output.size-1 : 0);
761 			tidyBufFree(&output);
762 			break;
763 
764 		default:
765 			return FAILURE;
766 	}
767 
768 	return SUCCESS;
769 }
770 
tidy_node_cast_handler(zval * in,zval * out,int type)771 static int tidy_node_cast_handler(zval *in, zval *out, int type)
772 {
773 	TidyBuffer buf;
774 	PHPTidyObj *obj;
775 
776 	switch(type) {
777 		case IS_LONG:
778 			ZVAL_LONG(out, 0);
779 			break;
780 
781 		case IS_DOUBLE:
782 			ZVAL_DOUBLE(out, 0);
783 			break;
784 
785 		case _IS_BOOL:
786 			ZVAL_TRUE(out);
787 			break;
788 
789 		case IS_STRING:
790 			obj = Z_TIDY_P(in);
791 			tidyBufInit(&buf);
792 			if (obj->ptdoc) {
793 				tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf);
794 				ZVAL_STRINGL(out, (char *) buf.bp, buf.size-1);
795 			} else {
796 				ZVAL_EMPTY_STRING(out);
797 			}
798 			tidyBufFree(&buf);
799 			break;
800 
801 		default:
802 			return FAILURE;
803 	}
804 
805 	return SUCCESS;
806 }
807 
tidy_doc_update_properties(PHPTidyObj * obj)808 static void tidy_doc_update_properties(PHPTidyObj *obj)
809 {
810 
811 	TidyBuffer output;
812 	zval temp;
813 
814 	tidyBufInit(&output);
815 	tidySaveBuffer (obj->ptdoc->doc, &output);
816 
817 	if (output.size) {
818 		if (!obj->std.properties) {
819 			rebuild_object_properties(&obj->std);
820 		}
821 		ZVAL_STRINGL(&temp, (char*)output.bp, output.size-1);
822 		zend_hash_str_update(obj->std.properties, "value", sizeof("value") - 1, &temp);
823 	}
824 
825 	tidyBufFree(&output);
826 
827 	if (obj->ptdoc->errbuf->size) {
828 		if (!obj->std.properties) {
829 			rebuild_object_properties(&obj->std);
830 		}
831 		ZVAL_STRINGL(&temp, (char*)obj->ptdoc->errbuf->bp, obj->ptdoc->errbuf->size-1);
832 		zend_hash_str_update(obj->std.properties, "errorBuffer", sizeof("errorBuffer") - 1, &temp);
833 	}
834 }
835 
tidy_add_default_properties(PHPTidyObj * obj,tidy_obj_type type)836 static void tidy_add_default_properties(PHPTidyObj *obj, tidy_obj_type type)
837 {
838 
839 	TidyBuffer buf;
840 	TidyAttr	tempattr;
841 	TidyNode	tempnode;
842 	zval attribute, children, temp;
843 	PHPTidyObj *newobj;
844 
845 	switch(type) {
846 
847 		case is_node:
848 			if (!obj->std.properties) {
849 				rebuild_object_properties(&obj->std);
850 			}
851 			tidyBufInit(&buf);
852 			tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf);
853 			ADD_PROPERTY_STRINGL(obj->std.properties, value, buf.bp, buf.size ? buf.size-1 : 0);
854 			tidyBufFree(&buf);
855 
856 			ADD_PROPERTY_STRING(obj->std.properties, name, tidyNodeGetName(obj->node));
857 			ADD_PROPERTY_LONG(obj->std.properties, type, tidyNodeGetType(obj->node));
858 			ADD_PROPERTY_LONG(obj->std.properties, line, tidyNodeLine(obj->node));
859 			ADD_PROPERTY_LONG(obj->std.properties, column, tidyNodeColumn(obj->node));
860 			ADD_PROPERTY_BOOL(obj->std.properties, proprietary, tidyNodeIsProp(obj->ptdoc->doc, obj->node));
861 
862 			switch(tidyNodeGetType(obj->node)) {
863 				case TidyNode_Root:
864 				case TidyNode_DocType:
865 				case TidyNode_Text:
866 				case TidyNode_Comment:
867 					break;
868 
869 				default:
870 					ADD_PROPERTY_LONG(obj->std.properties, id, tidyNodeGetId(obj->node));
871 			}
872 
873 			tempattr = tidyAttrFirst(obj->node);
874 
875 			if (tempattr) {
876 				char *name, *val;
877 				array_init(&attribute);
878 
879 				do {
880 					name = (char *)tidyAttrName(tempattr);
881 					val = (char *)tidyAttrValue(tempattr);
882 					if (name && val) {
883 						add_assoc_string(&attribute, name, val);
884 					}
885 				} while((tempattr = tidyAttrNext(tempattr)));
886 			} else {
887 				ZVAL_NULL(&attribute);
888 			}
889 			zend_hash_str_update(obj->std.properties, "attribute", sizeof("attribute") - 1, &attribute);
890 
891 			tempnode = tidyGetChild(obj->node);
892 
893 			if (tempnode) {
894 				array_init(&children);
895 				do {
896 					tidy_instanciate(tidy_ce_node, &temp);
897 					newobj = Z_TIDY_P(&temp);
898 					newobj->node = tempnode;
899 					newobj->type = is_node;
900 					newobj->ptdoc = obj->ptdoc;
901 					newobj->ptdoc->ref_count++;
902 
903 					tidy_add_default_properties(newobj, is_node);
904 					add_next_index_zval(&children, &temp);
905 
906 				} while((tempnode = tidyGetNext(tempnode)));
907 
908 			} else {
909 				ZVAL_NULL(&children);
910 			}
911 
912 			zend_hash_str_update(obj->std.properties, "child", sizeof("child") - 1, &children);
913 
914 			break;
915 
916 		case is_doc:
917 			if (!obj->std.properties) {
918 				rebuild_object_properties(&obj->std);
919 			}
920 			ADD_PROPERTY_NULL(obj->std.properties, errorBuffer);
921 			ADD_PROPERTY_NULL(obj->std.properties, value);
922 			break;
923 	}
924 }
925 
php_tidy_get_opt_val(PHPTidyDoc * ptdoc,TidyOption opt,TidyOptionType * type)926 static void *php_tidy_get_opt_val(PHPTidyDoc *ptdoc, TidyOption opt, TidyOptionType *type)
927 {
928 	*type = tidyOptGetType(opt);
929 
930 	switch (*type) {
931 		case TidyString: {
932 			char *val = (char *) tidyOptGetValue(ptdoc->doc, tidyOptGetId(opt));
933 			if (val) {
934 				return (void *) zend_string_init(val, strlen(val), 0);
935 			} else {
936 				return (void *) ZSTR_EMPTY_ALLOC();
937 			}
938 		}
939 			break;
940 
941 		case TidyInteger:
942 			return (void *) (uintptr_t) tidyOptGetInt(ptdoc->doc, tidyOptGetId(opt));
943 			break;
944 
945 		case TidyBoolean:
946 			return (void *) tidyOptGetBool(ptdoc->doc, tidyOptGetId(opt));
947 			break;
948 	}
949 
950 	/* should not happen */
951 	return NULL;
952 }
953 
php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS,tidy_base_nodetypes node_type)954 static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetypes node_type)
955 {
956 	PHPTidyObj *newobj;
957 	TidyNode node;
958 	TIDY_FETCH_OBJECT;
959 
960 	switch (node_type) {
961 		case is_root_node:
962 			node = tidyGetRoot(obj->ptdoc->doc);
963 			break;
964 
965 		case is_html_node:
966 			node = tidyGetHtml(obj->ptdoc->doc);
967 			break;
968 
969 		case is_head_node:
970 			node = tidyGetHead(obj->ptdoc->doc);
971 			break;
972 
973 		case is_body_node:
974 			node = tidyGetBody(obj->ptdoc->doc);
975 			break;
976 
977 		default:
978 			RETURN_NULL();
979 			break;
980 	}
981 
982 	if (!node) {
983 		RETURN_NULL();
984 	}
985 
986 	tidy_instanciate(tidy_ce_node, return_value);
987 	newobj = Z_TIDY_P(return_value);
988 	newobj->type  = is_node;
989 	newobj->ptdoc = obj->ptdoc;
990 	newobj->node  = node;
991 	newobj->ptdoc->ref_count++;
992 
993 	tidy_add_default_properties(newobj, is_node);
994 }
995 
_php_tidy_apply_config_array(TidyDoc doc,HashTable * ht_options)996 static int _php_tidy_apply_config_array(TidyDoc doc, HashTable *ht_options)
997 {
998 	zval *opt_val;
999 	zend_string *opt_name;
1000 
1001 	ZEND_HASH_FOREACH_STR_KEY_VAL(ht_options, opt_name, opt_val) {
1002 		if (opt_name == NULL) {
1003 			continue;
1004 		}
1005 		_php_tidy_set_tidy_opt(doc, ZSTR_VAL(opt_name), opt_val);
1006 	} ZEND_HASH_FOREACH_END();
1007 
1008 	return SUCCESS;
1009 }
1010 
php_tidy_parse_string(PHPTidyObj * obj,char * string,uint len,char * enc)1011 static int php_tidy_parse_string(PHPTidyObj *obj, char *string, uint len, char *enc)
1012 {
1013 	TidyBuffer buf;
1014 
1015 	if(enc) {
1016 		if (tidySetCharEncoding(obj->ptdoc->doc, enc) < 0) {
1017 			php_error_docref(NULL, E_WARNING, "Could not set encoding '%s'", enc);
1018 			return FAILURE;
1019 		}
1020 	}
1021 
1022 	obj->ptdoc->initialized = 1;
1023 
1024 	tidyBufInit(&buf);
1025 	tidyBufAttach(&buf, (byte *) string, len);
1026 	if (tidyParseBuffer(obj->ptdoc->doc, &buf) < 0) {
1027 		php_error_docref(NULL, E_WARNING, "%s", obj->ptdoc->errbuf->bp);
1028 		return FAILURE;
1029 	}
1030 	tidy_doc_update_properties(obj);
1031 
1032 	return SUCCESS;
1033 }
1034 
PHP_MINIT_FUNCTION(tidy)1035 static PHP_MINIT_FUNCTION(tidy)
1036 {
1037 	tidySetMallocCall(php_tidy_malloc);
1038 	tidySetReallocCall(php_tidy_realloc);
1039 	tidySetFreeCall(php_tidy_free);
1040 	tidySetPanicCall(php_tidy_panic);
1041 
1042 	REGISTER_INI_ENTRIES();
1043 	REGISTER_TIDY_CLASS(tidy, doc,	NULL, 0);
1044 	REGISTER_TIDY_CLASS(tidyNode, node,	NULL, ZEND_ACC_FINAL);
1045 
1046 	tidy_object_handlers_doc.cast_object = tidy_doc_cast_handler;
1047 	tidy_object_handlers_node.cast_object = tidy_node_cast_handler;
1048 
1049 	tidy_object_handlers_node.offset = tidy_object_handlers_doc.offset = XtOffsetOf(PHPTidyObj, std);
1050 	tidy_object_handlers_node.free_obj = tidy_object_handlers_doc.free_obj = tidy_object_free_storage;
1051 
1052 	_php_tidy_register_tags(INIT_FUNC_ARGS_PASSTHRU);
1053 	_php_tidy_register_nodetypes(INIT_FUNC_ARGS_PASSTHRU);
1054 
1055 	php_output_handler_alias_register(ZEND_STRL("ob_tidyhandler"), php_tidy_output_handler_init);
1056 
1057 	return SUCCESS;
1058 }
1059 
PHP_RINIT_FUNCTION(tidy)1060 static PHP_RINIT_FUNCTION(tidy)
1061 {
1062 #if defined(COMPILE_DL_TIDY) && defined(ZTS)
1063 	ZEND_TSRMLS_CACHE_UPDATE();
1064 #endif
1065 
1066 	php_tidy_clean_output_start(ZEND_STRL("ob_tidyhandler"));
1067 
1068 	return SUCCESS;
1069 }
1070 
PHP_MSHUTDOWN_FUNCTION(tidy)1071 static PHP_MSHUTDOWN_FUNCTION(tidy)
1072 {
1073 	UNREGISTER_INI_ENTRIES();
1074 	return SUCCESS;
1075 }
1076 
PHP_MINFO_FUNCTION(tidy)1077 static PHP_MINFO_FUNCTION(tidy)
1078 {
1079 	php_info_print_table_start();
1080 	php_info_print_table_header(2, "Tidy support", "enabled");
1081 	php_info_print_table_row(2, "libTidy Release", (char *)tidyReleaseDate());
1082 	php_info_print_table_row(2, "Extension Version", PHP_TIDY_VERSION " ($Id: 4e307eec06aa0ac776a415ba4d74290bfd9e0c73 $)");
1083 	php_info_print_table_end();
1084 
1085 	DISPLAY_INI_ENTRIES();
1086 }
1087 
PHP_INI_MH(php_tidy_set_clean_output)1088 static PHP_INI_MH(php_tidy_set_clean_output)
1089 {
1090 	int status;
1091 	zend_bool value;
1092 
1093 	if (ZSTR_LEN(new_value)==2 && strcasecmp("on", ZSTR_VAL(new_value))==0) {
1094 		value = (zend_bool) 1;
1095 	} else if (ZSTR_LEN(new_value)==3 && strcasecmp("yes", ZSTR_VAL(new_value))==0) {
1096 		value = (zend_bool) 1;
1097 	} else if (ZSTR_LEN(new_value)==4 && strcasecmp("true", ZSTR_VAL(new_value))==0) {
1098 		value = (zend_bool) 1;
1099 	} else {
1100 		value = (zend_bool) atoi(ZSTR_VAL(new_value));
1101 	}
1102 
1103 	if (stage == PHP_INI_STAGE_RUNTIME) {
1104 		status = php_output_get_status();
1105 
1106 		if (value && (status & PHP_OUTPUT_WRITTEN)) {
1107 			php_error_docref(NULL, E_WARNING, "Cannot enable tidy.clean_output - there has already been output");
1108 			return FAILURE;
1109 		}
1110 		if (status & PHP_OUTPUT_SENT) {
1111 			php_error_docref(NULL, E_WARNING, "Cannot change tidy.clean_output - headers already sent");
1112 			return FAILURE;
1113 		}
1114 	}
1115 
1116 	status = OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
1117 
1118 	if (stage == PHP_INI_STAGE_RUNTIME && value) {
1119 		if (!php_output_handler_started(ZEND_STRL("ob_tidyhandler"))) {
1120 			php_tidy_clean_output_start(ZEND_STRL("ob_tidyhandler"));
1121 		}
1122 	}
1123 
1124 	return status;
1125 }
1126 
1127 /*
1128  * NOTE: tidy does not support iterative/cumulative parsing, so chunk-sized output handler is not possible
1129  */
1130 
php_tidy_clean_output_start(const char * name,size_t name_len)1131 static void php_tidy_clean_output_start(const char *name, size_t name_len)
1132 {
1133 	php_output_handler *h;
1134 
1135 	if (TG(clean_output) && (h = php_tidy_output_handler_init(name, name_len, 0, PHP_OUTPUT_HANDLER_STDFLAGS))) {
1136 		php_output_handler_start(h);
1137 	}
1138 }
1139 
php_tidy_output_handler_init(const char * handler_name,size_t handler_name_len,size_t chunk_size,int flags)1140 static php_output_handler *php_tidy_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags)
1141 {
1142 	if (chunk_size) {
1143 		php_error_docref(NULL, E_WARNING, "Cannot use a chunk size for ob_tidyhandler");
1144 		return NULL;
1145 	}
1146 	if (!TG(clean_output)) {
1147 		TG(clean_output) = 1;
1148 	}
1149 	return php_output_handler_create_internal(handler_name, handler_name_len, php_tidy_output_handler, chunk_size, flags);
1150 }
1151 
php_tidy_output_handler(void ** nothing,php_output_context * output_context)1152 static int php_tidy_output_handler(void **nothing, php_output_context *output_context)
1153 {
1154 	int status = FAILURE;
1155 	TidyDoc doc;
1156 	TidyBuffer inbuf, outbuf, errbuf;
1157 
1158 	if (TG(clean_output) && (output_context->op & PHP_OUTPUT_HANDLER_START) && (output_context->op & PHP_OUTPUT_HANDLER_FINAL)) {
1159 		doc = tidyCreate();
1160 		tidyBufInit(&errbuf);
1161 
1162 		if (0 == tidySetErrorBuffer(doc, &errbuf)) {
1163 			tidyOptSetBool(doc, TidyForceOutput, yes);
1164 			tidyOptSetBool(doc, TidyMark, no);
1165 
1166 			if (ZEND_SIZE_T_UINT_OVFL(output_context->in.used)) {
1167 				php_error_docref(NULL, E_WARNING, "Input string is too long");
1168 				return status;
1169 			}
1170 
1171 			TIDY_SET_DEFAULT_CONFIG(doc);
1172 
1173 			tidyBufInit(&inbuf);
1174 			tidyBufAttach(&inbuf, (byte *) output_context->in.data, (uint)output_context->in.used);
1175 
1176 			if (0 <= tidyParseBuffer(doc, &inbuf) && 0 <= tidyCleanAndRepair(doc)) {
1177 				tidyBufInit(&outbuf);
1178 				tidySaveBuffer(doc, &outbuf);
1179 				FIX_BUFFER(&outbuf);
1180 				output_context->out.data = (char *) outbuf.bp;
1181 				output_context->out.used = outbuf.size ? outbuf.size-1 : 0;
1182 				output_context->out.free = 1;
1183 				status = SUCCESS;
1184 			}
1185 		}
1186 
1187 		tidyRelease(doc);
1188 		tidyBufFree(&errbuf);
1189 	}
1190 
1191 	return status;
1192 }
1193 
1194 /* {{{ proto bool tidy_parse_string(string input [, mixed config_options [, string encoding]])
1195    Parse a document stored in a string */
PHP_FUNCTION(tidy_parse_string)1196 static PHP_FUNCTION(tidy_parse_string)
1197 {
1198 	char *enc = NULL;
1199 	size_t enc_len = 0;
1200 	zend_string *input;
1201 	zval *options = NULL;
1202 	PHPTidyObj *obj;
1203 
1204 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zs", &input, &options, &enc, &enc_len) == FAILURE) {
1205 		RETURN_FALSE;
1206 	}
1207 
1208 	if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(input))) {
1209 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1210 		RETURN_FALSE;
1211 	}
1212 
1213 	tidy_instanciate(tidy_ce_doc, return_value);
1214 	obj = Z_TIDY_P(return_value);
1215 
1216 	TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
1217 
1218 	if (php_tidy_parse_string(obj, ZSTR_VAL(input), (uint)ZSTR_LEN(input), enc) == FAILURE) {
1219 		zval_ptr_dtor(return_value);
1220 		RETURN_FALSE;
1221 	}
1222 }
1223 /* }}} */
1224 
1225 /* {{{ proto string tidy_get_error_buffer()
1226    Return warnings and errors which occurred parsing the specified document*/
PHP_FUNCTION(tidy_get_error_buffer)1227 static PHP_FUNCTION(tidy_get_error_buffer)
1228 {
1229 	TIDY_FETCH_OBJECT;
1230 
1231 	if (obj->ptdoc->errbuf && obj->ptdoc->errbuf->bp) {
1232 		RETURN_STRINGL((char*)obj->ptdoc->errbuf->bp, obj->ptdoc->errbuf->size-1);
1233 	} else {
1234 		RETURN_FALSE;
1235 	}
1236 }
1237 /* }}} */
1238 
1239 /* {{{ proto string tidy_get_output()
1240    Return a string representing the parsed tidy markup */
PHP_FUNCTION(tidy_get_output)1241 static PHP_FUNCTION(tidy_get_output)
1242 {
1243 	TidyBuffer output;
1244 	TIDY_FETCH_OBJECT;
1245 
1246 	tidyBufInit(&output);
1247 	tidySaveBuffer(obj->ptdoc->doc, &output);
1248 	FIX_BUFFER(&output);
1249 	RETVAL_STRINGL((char *) output.bp, output.size ? output.size-1 : 0);
1250 	tidyBufFree(&output);
1251 }
1252 /* }}} */
1253 
1254 /* {{{ proto boolean tidy_parse_file(string file [, mixed config_options [, string encoding [, bool use_include_path]]])
1255    Parse markup in file or URI */
PHP_FUNCTION(tidy_parse_file)1256 static PHP_FUNCTION(tidy_parse_file)
1257 {
1258 	char *enc = NULL;
1259 	size_t enc_len = 0;
1260 	zend_bool use_include_path = 0;
1261 	zend_string *inputfile, *contents;
1262 	zval *options = NULL;
1263 
1264 	PHPTidyObj *obj;
1265 
1266 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &inputfile,
1267 							  &options, &enc, &enc_len, &use_include_path) == FAILURE) {
1268 		RETURN_FALSE;
1269 	}
1270 
1271 	tidy_instanciate(tidy_ce_doc, return_value);
1272 	obj = Z_TIDY_P(return_value);
1273 
1274 	if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
1275 		php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
1276 		RETURN_FALSE;
1277 	}
1278 
1279 	if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
1280 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1281 		RETURN_FALSE;
1282 	}
1283 
1284 	TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
1285 
1286 	if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint)ZSTR_LEN(contents), enc) == FAILURE) {
1287 		zval_ptr_dtor(return_value);
1288 		RETVAL_FALSE;
1289 	}
1290 
1291 	zend_string_release(contents);
1292 }
1293 /* }}} */
1294 
1295 /* {{{ proto boolean tidy_clean_repair()
1296    Execute configured cleanup and repair operations on parsed markup */
PHP_FUNCTION(tidy_clean_repair)1297 static PHP_FUNCTION(tidy_clean_repair)
1298 {
1299 	TIDY_FETCH_OBJECT;
1300 
1301 	if (tidyCleanAndRepair(obj->ptdoc->doc) >= 0) {
1302 		tidy_doc_update_properties(obj);
1303 		RETURN_TRUE;
1304 	}
1305 
1306 	RETURN_FALSE;
1307 }
1308 /* }}} */
1309 
1310 /* {{{ proto boolean tidy_repair_string(string data [, mixed config_file [, string encoding]])
1311    Repair a string using an optionally provided configuration file */
PHP_FUNCTION(tidy_repair_string)1312 static PHP_FUNCTION(tidy_repair_string)
1313 {
1314 	php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE);
1315 }
1316 /* }}} */
1317 
1318 /* {{{ proto boolean tidy_repair_file(string filename [, mixed config_file [, string encoding [, bool use_include_path]]])
1319    Repair a file using an optionally provided configuration file */
PHP_FUNCTION(tidy_repair_file)1320 static PHP_FUNCTION(tidy_repair_file)
1321 {
1322 	php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE);
1323 }
1324 /* }}} */
1325 
1326 /* {{{ proto boolean tidy_diagnose()
1327    Run configured diagnostics on parsed and repaired markup. */
PHP_FUNCTION(tidy_diagnose)1328 static PHP_FUNCTION(tidy_diagnose)
1329 {
1330 	TIDY_FETCH_OBJECT;
1331 
1332 	if (obj->ptdoc->initialized && tidyRunDiagnostics(obj->ptdoc->doc) >= 0) {
1333 		tidy_doc_update_properties(obj);
1334 		RETURN_TRUE;
1335 	}
1336 
1337 	RETURN_FALSE;
1338 }
1339 /* }}} */
1340 
1341 /* {{{ proto string tidy_get_release()
1342    Get release date (version) for Tidy library */
PHP_FUNCTION(tidy_get_release)1343 static PHP_FUNCTION(tidy_get_release)
1344 {
1345 	if (zend_parse_parameters_none() == FAILURE) {
1346 		return;
1347 	}
1348 
1349 	RETURN_STRING((char *)tidyReleaseDate());
1350 }
1351 /* }}} */
1352 
1353 
1354 #if HAVE_TIDYOPTGETDOC
1355 /* {{{ proto string tidy_get_opt_doc(tidy resource, string optname)
1356    Returns the documentation for the given option name */
PHP_FUNCTION(tidy_get_opt_doc)1357 static PHP_FUNCTION(tidy_get_opt_doc)
1358 {
1359 	PHPTidyObj *obj;
1360 	char *optval, *optname;
1361 	size_t optname_len;
1362 	TidyOption opt;
1363 
1364 	TIDY_SET_CONTEXT;
1365 
1366 	if (object) {
1367 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &optname, &optname_len) == FAILURE) {
1368 			RETURN_FALSE;
1369 		}
1370 	} else {
1371 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "Os", &object, tidy_ce_doc, &optname, &optname_len) == FAILURE) {
1372 			RETURN_FALSE;
1373 		}
1374 	}
1375 
1376 	obj = Z_TIDY_P(object);
1377 
1378 	opt = tidyGetOptionByName(obj->ptdoc->doc, optname);
1379 
1380 	if (!opt) {
1381 		php_error_docref(NULL, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
1382 		RETURN_FALSE;
1383 	}
1384 
1385 	if ( (optval = (char *) tidyOptGetDoc(obj->ptdoc->doc, opt)) ) {
1386 		RETURN_STRING(optval);
1387 	}
1388 
1389 	RETURN_FALSE;
1390 }
1391 /* }}} */
1392 #endif
1393 
1394 
1395 /* {{{ proto array tidy_get_config()
1396    Get current Tidy configuration */
PHP_FUNCTION(tidy_get_config)1397 static PHP_FUNCTION(tidy_get_config)
1398 {
1399 	TidyIterator itOpt;
1400 	char *opt_name;
1401 	void *opt_value;
1402 	TidyOptionType optt;
1403 
1404 	TIDY_FETCH_OBJECT;
1405 
1406 	itOpt = tidyGetOptionList(obj->ptdoc->doc);
1407 
1408 	array_init(return_value);
1409 
1410 	while (itOpt) {
1411 		TidyOption opt = tidyGetNextOption(obj->ptdoc->doc, &itOpt);
1412 
1413 		opt_name = (char *)tidyOptGetName(opt);
1414 		opt_value = php_tidy_get_opt_val(obj->ptdoc, opt, &optt);
1415 		switch (optt) {
1416 			case TidyString:
1417 				add_assoc_str(return_value, opt_name, (zend_string*)opt_value);
1418 				break;
1419 
1420 			case TidyInteger:
1421 				add_assoc_long(return_value, opt_name, (zend_long)opt_value);
1422 				break;
1423 
1424 			case TidyBoolean:
1425 				add_assoc_bool(return_value, opt_name, opt_value ? 1 : 0);
1426 				break;
1427 		}
1428 	}
1429 
1430 	return;
1431 }
1432 /* }}} */
1433 
1434 /* {{{ proto int tidy_get_status()
1435    Get status of specified document. */
PHP_FUNCTION(tidy_get_status)1436 static PHP_FUNCTION(tidy_get_status)
1437 {
1438 	TIDY_FETCH_OBJECT;
1439 
1440 	RETURN_LONG(tidyStatus(obj->ptdoc->doc));
1441 }
1442 /* }}} */
1443 
1444 /* {{{ proto int tidy_get_html_ver()
1445    Get the Detected HTML version for the specified document. */
PHP_FUNCTION(tidy_get_html_ver)1446 static PHP_FUNCTION(tidy_get_html_ver)
1447 {
1448 	TIDY_FETCH_OBJECT;
1449 
1450 	RETURN_LONG(tidyDetectedHtmlVersion(obj->ptdoc->doc));
1451 }
1452 /* }}} */
1453 
1454 /* {{{ proto boolean tidy_is_xhtml()
1455    Indicates if the document is a XHTML document. */
PHP_FUNCTION(tidy_is_xhtml)1456 static PHP_FUNCTION(tidy_is_xhtml)
1457 {
1458 	TIDY_FETCH_OBJECT;
1459 
1460 	RETURN_BOOL(tidyDetectedXhtml(obj->ptdoc->doc));
1461 }
1462 /* }}} */
1463 
1464 /* {{{ proto boolean tidy_is_xml()
1465    Indicates if the document is a generic (non HTML/XHTML) XML document. */
PHP_FUNCTION(tidy_is_xml)1466 static PHP_FUNCTION(tidy_is_xml)
1467 {
1468 	TIDY_FETCH_OBJECT;
1469 
1470 	RETURN_BOOL(tidyDetectedGenericXml(obj->ptdoc->doc));
1471 }
1472 /* }}} */
1473 
1474 /* {{{ proto int tidy_error_count()
1475    Returns the Number of Tidy errors encountered for specified document. */
PHP_FUNCTION(tidy_error_count)1476 static PHP_FUNCTION(tidy_error_count)
1477 {
1478 	TIDY_FETCH_OBJECT;
1479 
1480 	RETURN_LONG(tidyErrorCount(obj->ptdoc->doc));
1481 }
1482 /* }}} */
1483 
1484 /* {{{ proto int tidy_warning_count()
1485    Returns the Number of Tidy warnings encountered for specified document. */
PHP_FUNCTION(tidy_warning_count)1486 static PHP_FUNCTION(tidy_warning_count)
1487 {
1488 	TIDY_FETCH_OBJECT;
1489 
1490 	RETURN_LONG(tidyWarningCount(obj->ptdoc->doc));
1491 }
1492 /* }}} */
1493 
1494 /* {{{ proto int tidy_access_count()
1495    Returns the Number of Tidy accessibility warnings encountered for specified document. */
PHP_FUNCTION(tidy_access_count)1496 static PHP_FUNCTION(tidy_access_count)
1497 {
1498 	TIDY_FETCH_OBJECT;
1499 
1500 	RETURN_LONG(tidyAccessWarningCount(obj->ptdoc->doc));
1501 }
1502 /* }}} */
1503 
1504 /* {{{ proto int tidy_config_count()
1505    Returns the Number of Tidy configuration errors encountered for specified document. */
PHP_FUNCTION(tidy_config_count)1506 static PHP_FUNCTION(tidy_config_count)
1507 {
1508 	TIDY_FETCH_OBJECT;
1509 
1510 	RETURN_LONG(tidyConfigErrorCount(obj->ptdoc->doc));
1511 }
1512 /* }}} */
1513 
1514 /* {{{ proto mixed tidy_getopt(string option)
1515    Returns the value of the specified configuration option for the tidy document. */
PHP_FUNCTION(tidy_getopt)1516 static PHP_FUNCTION(tidy_getopt)
1517 {
1518 	PHPTidyObj *obj;
1519 	char *optname;
1520 	void *optval;
1521 	size_t optname_len;
1522 	TidyOption opt;
1523 	TidyOptionType optt;
1524 
1525 	TIDY_SET_CONTEXT;
1526 
1527 	if (object) {
1528 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &optname, &optname_len) == FAILURE) {
1529 			RETURN_FALSE;
1530 		}
1531 	} else {
1532 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "Os", &object, tidy_ce_doc, &optname, &optname_len) == FAILURE) {
1533 			RETURN_FALSE;
1534 		}
1535 	}
1536 
1537 	obj = Z_TIDY_P(object);
1538 
1539 	opt = tidyGetOptionByName(obj->ptdoc->doc, optname);
1540 
1541 	if (!opt) {
1542 		php_error_docref(NULL, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
1543 		RETURN_FALSE;
1544 	}
1545 
1546 	optval = php_tidy_get_opt_val(obj->ptdoc, opt, &optt);
1547 	switch (optt) {
1548 		case TidyString:
1549 			RETVAL_STR((zend_string*)optval);
1550 			return;
1551 
1552 		case TidyInteger:
1553 			RETURN_LONG((zend_long)optval);
1554 			break;
1555 
1556 		case TidyBoolean:
1557 			if (optval) {
1558 				RETURN_TRUE;
1559 			} else {
1560 				RETURN_FALSE;
1561 			}
1562 			break;
1563 
1564 		default:
1565 			php_error_docref(NULL, E_WARNING, "Unable to determine type of configuration option");
1566 			break;
1567 	}
1568 
1569 	RETURN_FALSE;
1570 }
1571 /* }}} */
1572 
TIDY_DOC_METHOD(__construct)1573 static TIDY_DOC_METHOD(__construct)
1574 {
1575 	char *enc = NULL;
1576 	size_t enc_len = 0;
1577 	zend_bool use_include_path = 0;
1578 	zval *options = NULL;
1579 	zend_string *contents, *inputfile = NULL;
1580 
1581 	PHPTidyObj *obj;
1582 	TIDY_SET_CONTEXT;
1583 
1584 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Pzsb", &inputfile,
1585 							  &options, &enc, &enc_len, &use_include_path) == FAILURE) {
1586 		RETURN_FALSE;
1587 	}
1588 
1589 	obj = Z_TIDY_P(object);
1590 
1591 	if (inputfile) {
1592 		if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
1593 			php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
1594 			return;
1595 		}
1596 
1597 		if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
1598 			php_error_docref(NULL, E_WARNING, "Input string is too long");
1599 			RETURN_FALSE;
1600 		}
1601 
1602 		TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
1603 
1604 		php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint)ZSTR_LEN(contents), enc);
1605 
1606 		zend_string_release(contents);
1607 	}
1608 }
1609 
TIDY_DOC_METHOD(parseFile)1610 static TIDY_DOC_METHOD(parseFile)
1611 {
1612 	char *enc = NULL;
1613 	size_t enc_len = 0;
1614 	zend_bool use_include_path = 0;
1615 	zval *options = NULL;
1616 	zend_string *inputfile, *contents;
1617 	PHPTidyObj *obj;
1618 
1619 	TIDY_SET_CONTEXT;
1620 
1621 	obj = Z_TIDY_P(object);
1622 
1623 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &inputfile,
1624 							  &options, &enc, &enc_len, &use_include_path) == FAILURE) {
1625 		RETURN_FALSE;
1626 	}
1627 
1628 	if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
1629 		php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
1630 		RETURN_FALSE;
1631 	}
1632 
1633 	if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
1634 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1635 		RETURN_FALSE;
1636 	}
1637 
1638 	TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
1639 
1640 	if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint)ZSTR_LEN(contents), enc) == FAILURE) {
1641 		RETVAL_FALSE;
1642 	} else {
1643 		RETVAL_TRUE;
1644 	}
1645 
1646 	zend_string_release(contents);
1647 }
1648 
TIDY_DOC_METHOD(parseString)1649 static TIDY_DOC_METHOD(parseString)
1650 {
1651 	char *enc = NULL;
1652 	size_t enc_len = 0;
1653 	zval *options = NULL;
1654 	PHPTidyObj *obj;
1655 	zend_string *input;
1656 
1657 	TIDY_SET_CONTEXT;
1658 
1659 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zs", &input, &options, &enc, &enc_len) == FAILURE) {
1660 		RETURN_FALSE;
1661 	}
1662 
1663 	if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(input))) {
1664 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1665 		RETURN_FALSE;
1666 	}
1667 
1668 	obj = Z_TIDY_P(object);
1669 
1670 	TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
1671 
1672 	if(php_tidy_parse_string(obj, ZSTR_VAL(input), (uint)ZSTR_LEN(input), enc) == SUCCESS) {
1673 		RETURN_TRUE;
1674 	}
1675 
1676 	RETURN_FALSE;
1677 }
1678 
1679 
1680 /* {{{ proto TidyNode tidy_get_root()
1681    Returns a TidyNode Object representing the root of the tidy parse tree */
PHP_FUNCTION(tidy_get_root)1682 static PHP_FUNCTION(tidy_get_root)
1683 {
1684 	php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_root_node);
1685 }
1686 /* }}} */
1687 
1688 /* {{{ proto TidyNode tidy_get_html()
1689    Returns a TidyNode Object starting from the <HTML> tag of the tidy parse tree */
PHP_FUNCTION(tidy_get_html)1690 static PHP_FUNCTION(tidy_get_html)
1691 {
1692 	php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_html_node);
1693 }
1694 /* }}} */
1695 
1696 /* {{{ proto TidyNode tidy_get_head()
1697    Returns a TidyNode Object starting from the <HEAD> tag of the tidy parse tree */
PHP_FUNCTION(tidy_get_head)1698 static PHP_FUNCTION(tidy_get_head)
1699 {
1700 	php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_head_node);
1701 }
1702 /* }}} */
1703 
1704 /* {{{ proto TidyNode tidy_get_body(resource tidy)
1705    Returns a TidyNode Object starting from the <BODY> tag of the tidy parse tree */
PHP_FUNCTION(tidy_get_body)1706 static PHP_FUNCTION(tidy_get_body)
1707 {
1708 	php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_body_node);
1709 }
1710 /* }}} */
1711 
1712 /* {{{ proto boolean tidyNode::hasChildren()
1713    Returns true if this node has children */
TIDY_NODE_METHOD(hasChildren)1714 static TIDY_NODE_METHOD(hasChildren)
1715 {
1716 	TIDY_FETCH_ONLY_OBJECT;
1717 
1718 	if (tidyGetChild(obj->node)) {
1719 		RETURN_TRUE;
1720 	} else {
1721 		RETURN_FALSE;
1722 	}
1723 }
1724 /* }}} */
1725 
1726 /* {{{ proto boolean tidyNode::hasSiblings()
1727    Returns true if this node has siblings */
TIDY_NODE_METHOD(hasSiblings)1728 static TIDY_NODE_METHOD(hasSiblings)
1729 {
1730 	TIDY_FETCH_ONLY_OBJECT;
1731 
1732 	if (obj->node && tidyGetNext(obj->node)) {
1733 		RETURN_TRUE;
1734 	} else {
1735 		RETURN_FALSE;
1736 	}
1737 }
1738 /* }}} */
1739 
1740 /* {{{ proto boolean tidyNode::isComment()
1741    Returns true if this node represents a comment */
TIDY_NODE_METHOD(isComment)1742 static TIDY_NODE_METHOD(isComment)
1743 {
1744 	TIDY_FETCH_ONLY_OBJECT;
1745 
1746 	if (tidyNodeGetType(obj->node) == TidyNode_Comment) {
1747 		RETURN_TRUE;
1748 	} else {
1749 		RETURN_FALSE;
1750 	}
1751 }
1752 /* }}} */
1753 
1754 /* {{{ proto boolean tidyNode::isHtml()
1755    Returns true if this node is part of a HTML document */
TIDY_NODE_METHOD(isHtml)1756 static TIDY_NODE_METHOD(isHtml)
1757 {
1758 	TIDY_FETCH_ONLY_OBJECT;
1759 
1760 	if (tidyNodeGetType(obj->node) & (TidyNode_Start | TidyNode_End | TidyNode_StartEnd)) {
1761 		RETURN_TRUE;
1762 	}
1763 
1764 	RETURN_FALSE;
1765 }
1766 /* }}} */
1767 
1768 /* {{{ proto boolean tidyNode::isText()
1769    Returns true if this node represents text (no markup) */
TIDY_NODE_METHOD(isText)1770 static TIDY_NODE_METHOD(isText)
1771 {
1772 	TIDY_FETCH_ONLY_OBJECT;
1773 
1774 	if (tidyNodeGetType(obj->node) == TidyNode_Text) {
1775 		RETURN_TRUE;
1776 	} else {
1777 		RETURN_FALSE;
1778 	}
1779 }
1780 /* }}} */
1781 
1782 /* {{{ proto boolean tidyNode::isJste()
1783    Returns true if this node is JSTE */
TIDY_NODE_METHOD(isJste)1784 static TIDY_NODE_METHOD(isJste)
1785 {
1786 	TIDY_FETCH_ONLY_OBJECT;
1787 
1788 	if (tidyNodeGetType(obj->node) == TidyNode_Jste) {
1789 		RETURN_TRUE;
1790 	} else {
1791 		RETURN_FALSE;
1792 	}
1793 }
1794 /* }}} */
1795 
1796 /* {{{ proto boolean tidyNode::isAsp()
1797    Returns true if this node is ASP */
TIDY_NODE_METHOD(isAsp)1798 static TIDY_NODE_METHOD(isAsp)
1799 {
1800 	TIDY_FETCH_ONLY_OBJECT;
1801 
1802 	if (tidyNodeGetType(obj->node) == TidyNode_Asp) {
1803 		RETURN_TRUE;
1804 	} else {
1805 		RETURN_FALSE;
1806 	}
1807 }
1808 /* }}} */
1809 
1810 /* {{{ proto boolean tidyNode::isPhp()
1811    Returns true if this node is PHP */
TIDY_NODE_METHOD(isPhp)1812 static TIDY_NODE_METHOD(isPhp)
1813 {
1814 	TIDY_FETCH_ONLY_OBJECT;
1815 
1816 	if (tidyNodeGetType(obj->node) == TidyNode_Php) {
1817 		RETURN_TRUE;
1818 	} else {
1819 		RETURN_FALSE;
1820 	}
1821 }
1822 /* }}} */
1823 
1824 /* {{{ proto tidyNode tidyNode::getParent()
1825    Returns the parent node if available or NULL */
TIDY_NODE_METHOD(getParent)1826 static TIDY_NODE_METHOD(getParent)
1827 {
1828 	TidyNode	parent_node;
1829 	PHPTidyObj *newobj;
1830 	TIDY_FETCH_ONLY_OBJECT;
1831 
1832 	parent_node = tidyGetParent(obj->node);
1833 	if(parent_node) {
1834 		tidy_instanciate(tidy_ce_node, return_value);
1835 		newobj = Z_TIDY_P(return_value);
1836 		newobj->node = parent_node;
1837 		newobj->type = is_node;
1838 		newobj->ptdoc = obj->ptdoc;
1839 		newobj->ptdoc->ref_count++;
1840 		tidy_add_default_properties(newobj, is_node);
1841 	} else {
1842 		ZVAL_NULL(return_value);
1843 	}
1844 }
1845 /* }}} */
1846 
1847 
1848 /* {{{ proto void tidyNode::__construct()
1849          __constructor for tidyNode. */
TIDY_NODE_METHOD(__construct)1850 static TIDY_NODE_METHOD(__construct)
1851 {
1852 	php_error_docref(NULL, E_ERROR, "You should not create a tidyNode manually");
1853 }
1854 /* }}} */
1855 
_php_tidy_register_nodetypes(INIT_FUNC_ARGS)1856 static void _php_tidy_register_nodetypes(INIT_FUNC_ARGS)
1857 {
1858 	TIDY_NODE_CONST(ROOT, Root);
1859 	TIDY_NODE_CONST(DOCTYPE, DocType);
1860 	TIDY_NODE_CONST(COMMENT, Comment);
1861 	TIDY_NODE_CONST(PROCINS, ProcIns);
1862 	TIDY_NODE_CONST(TEXT, Text);
1863 	TIDY_NODE_CONST(START, Start);
1864 	TIDY_NODE_CONST(END, End);
1865 	TIDY_NODE_CONST(STARTEND, StartEnd);
1866 	TIDY_NODE_CONST(CDATA, CDATA);
1867 	TIDY_NODE_CONST(SECTION, Section);
1868 	TIDY_NODE_CONST(ASP, Asp);
1869 	TIDY_NODE_CONST(JSTE, Jste);
1870 	TIDY_NODE_CONST(PHP, Php);
1871 	TIDY_NODE_CONST(XMLDECL, XmlDecl);
1872 }
1873 
_php_tidy_register_tags(INIT_FUNC_ARGS)1874 static void _php_tidy_register_tags(INIT_FUNC_ARGS)
1875 {
1876 	TIDY_TAG_CONST(UNKNOWN);
1877 	TIDY_TAG_CONST(A);
1878 	TIDY_TAG_CONST(ABBR);
1879 	TIDY_TAG_CONST(ACRONYM);
1880 	TIDY_TAG_CONST(ADDRESS);
1881 	TIDY_TAG_CONST(ALIGN);
1882 	TIDY_TAG_CONST(APPLET);
1883 	TIDY_TAG_CONST(AREA);
1884 	TIDY_TAG_CONST(B);
1885 	TIDY_TAG_CONST(BASE);
1886 	TIDY_TAG_CONST(BASEFONT);
1887 	TIDY_TAG_CONST(BDO);
1888 	TIDY_TAG_CONST(BGSOUND);
1889 	TIDY_TAG_CONST(BIG);
1890 	TIDY_TAG_CONST(BLINK);
1891 	TIDY_TAG_CONST(BLOCKQUOTE);
1892 	TIDY_TAG_CONST(BODY);
1893 	TIDY_TAG_CONST(BR);
1894 	TIDY_TAG_CONST(BUTTON);
1895 	TIDY_TAG_CONST(CAPTION);
1896 	TIDY_TAG_CONST(CENTER);
1897 	TIDY_TAG_CONST(CITE);
1898 	TIDY_TAG_CONST(CODE);
1899 	TIDY_TAG_CONST(COL);
1900 	TIDY_TAG_CONST(COLGROUP);
1901 	TIDY_TAG_CONST(COMMENT);
1902 	TIDY_TAG_CONST(DD);
1903 	TIDY_TAG_CONST(DEL);
1904 	TIDY_TAG_CONST(DFN);
1905 	TIDY_TAG_CONST(DIR);
1906 	TIDY_TAG_CONST(DIV);
1907 	TIDY_TAG_CONST(DL);
1908 	TIDY_TAG_CONST(DT);
1909 	TIDY_TAG_CONST(EM);
1910 	TIDY_TAG_CONST(EMBED);
1911 	TIDY_TAG_CONST(FIELDSET);
1912 	TIDY_TAG_CONST(FONT);
1913 	TIDY_TAG_CONST(FORM);
1914 	TIDY_TAG_CONST(FRAME);
1915 	TIDY_TAG_CONST(FRAMESET);
1916 	TIDY_TAG_CONST(H1);
1917 	TIDY_TAG_CONST(H2);
1918 	TIDY_TAG_CONST(H3);
1919 	TIDY_TAG_CONST(H4);
1920 	TIDY_TAG_CONST(H5);
1921 	TIDY_TAG_CONST(H6);
1922 	TIDY_TAG_CONST(HEAD);
1923 	TIDY_TAG_CONST(HR);
1924 	TIDY_TAG_CONST(HTML);
1925 	TIDY_TAG_CONST(I);
1926 	TIDY_TAG_CONST(IFRAME);
1927 	TIDY_TAG_CONST(ILAYER);
1928 	TIDY_TAG_CONST(IMG);
1929 	TIDY_TAG_CONST(INPUT);
1930 	TIDY_TAG_CONST(INS);
1931 	TIDY_TAG_CONST(ISINDEX);
1932 	TIDY_TAG_CONST(KBD);
1933 	TIDY_TAG_CONST(KEYGEN);
1934 	TIDY_TAG_CONST(LABEL);
1935 	TIDY_TAG_CONST(LAYER);
1936 	TIDY_TAG_CONST(LEGEND);
1937 	TIDY_TAG_CONST(LI);
1938 	TIDY_TAG_CONST(LINK);
1939 	TIDY_TAG_CONST(LISTING);
1940 	TIDY_TAG_CONST(MAP);
1941 	TIDY_TAG_CONST(MARQUEE);
1942 	TIDY_TAG_CONST(MENU);
1943 	TIDY_TAG_CONST(META);
1944 	TIDY_TAG_CONST(MULTICOL);
1945 	TIDY_TAG_CONST(NOBR);
1946 	TIDY_TAG_CONST(NOEMBED);
1947 	TIDY_TAG_CONST(NOFRAMES);
1948 	TIDY_TAG_CONST(NOLAYER);
1949 	TIDY_TAG_CONST(NOSAVE);
1950 	TIDY_TAG_CONST(NOSCRIPT);
1951 	TIDY_TAG_CONST(OBJECT);
1952 	TIDY_TAG_CONST(OL);
1953 	TIDY_TAG_CONST(OPTGROUP);
1954 	TIDY_TAG_CONST(OPTION);
1955 	TIDY_TAG_CONST(P);
1956 	TIDY_TAG_CONST(PARAM);
1957 	TIDY_TAG_CONST(PLAINTEXT);
1958 	TIDY_TAG_CONST(PRE);
1959 	TIDY_TAG_CONST(Q);
1960 	TIDY_TAG_CONST(RB);
1961 	TIDY_TAG_CONST(RBC);
1962 	TIDY_TAG_CONST(RP);
1963 	TIDY_TAG_CONST(RT);
1964 	TIDY_TAG_CONST(RTC);
1965 	TIDY_TAG_CONST(RUBY);
1966 	TIDY_TAG_CONST(S);
1967 	TIDY_TAG_CONST(SAMP);
1968 	TIDY_TAG_CONST(SCRIPT);
1969 	TIDY_TAG_CONST(SELECT);
1970 	TIDY_TAG_CONST(SERVER);
1971 	TIDY_TAG_CONST(SERVLET);
1972 	TIDY_TAG_CONST(SMALL);
1973 	TIDY_TAG_CONST(SPACER);
1974 	TIDY_TAG_CONST(SPAN);
1975 	TIDY_TAG_CONST(STRIKE);
1976 	TIDY_TAG_CONST(STRONG);
1977 	TIDY_TAG_CONST(STYLE);
1978 	TIDY_TAG_CONST(SUB);
1979 	TIDY_TAG_CONST(SUP);
1980 	TIDY_TAG_CONST(TABLE);
1981 	TIDY_TAG_CONST(TBODY);
1982 	TIDY_TAG_CONST(TD);
1983 	TIDY_TAG_CONST(TEXTAREA);
1984 	TIDY_TAG_CONST(TFOOT);
1985 	TIDY_TAG_CONST(TH);
1986 	TIDY_TAG_CONST(THEAD);
1987 	TIDY_TAG_CONST(TITLE);
1988 	TIDY_TAG_CONST(TR);
1989 	TIDY_TAG_CONST(TT);
1990 	TIDY_TAG_CONST(U);
1991 	TIDY_TAG_CONST(UL);
1992 	TIDY_TAG_CONST(VAR);
1993 	TIDY_TAG_CONST(WBR);
1994 	TIDY_TAG_CONST(XMP);
1995 }
1996 
1997 #endif
1998 
1999 /*
2000  * Local variables:
2001  * tab-width: 4
2002  * c-basic-offset: 4
2003  * End:
2004  * vim600: noet sw=4 ts=4 fdm=marker
2005  * vim<600: noet sw=4 ts=4
2006  */
2007