xref: /PHP-8.0/ext/dom/domimplementation.c (revision f15f8fc5)
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    | Authors: Christian Stocker <chregu@php.net>                          |
14    |          Rob Richards <rrichards@php.net>                            |
15    +----------------------------------------------------------------------+
16 */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 
26 /*
27 * class DOMImplementation
28 *
29 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-102161490
30 * Since:
31 */
32 
33 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-5CED94D7
34 Since:
35 */
PHP_METHOD(DOMImplementation,hasFeature)36 PHP_METHOD(DOMImplementation, hasFeature)
37 {
38 	size_t feature_len, version_len;
39 	char *feature, *version;
40 
41 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &feature, &feature_len, &version, &version_len) == FAILURE) {
42 		RETURN_THROWS();
43 	}
44 
45 	if (dom_has_feature(feature, version)) {
46 		RETURN_TRUE;
47 	} else {
48 		RETURN_FALSE;
49 	}
50 }
51 /* }}} end dom_domimplementation_has_feature */
52 
53 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocType
54 Since: DOM Level 2
55 */
PHP_METHOD(DOMImplementation,createDocumentType)56 PHP_METHOD(DOMImplementation, createDocumentType)
57 {
58 	xmlDtd *doctype;
59 	int ret;
60 	size_t name_len = 0, publicid_len = 0, systemid_len = 0;
61 	char *name = NULL, *publicid = NULL, *systemid = NULL;
62 	xmlChar *pch1 = NULL, *pch2 = NULL, *localname = NULL;
63 	xmlURIPtr uri;
64 
65 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", &name, &name_len, &publicid, &publicid_len, &systemid, &systemid_len) == FAILURE) {
66 		RETURN_THROWS();
67 	}
68 
69 	if (name_len == 0) {
70 		zend_argument_value_error(1, "cannot be empty");
71 		RETURN_THROWS();
72 	}
73 
74 	if (publicid_len > 0) {
75 		pch1 = (xmlChar *) publicid;
76 	}
77 	if (systemid_len > 0) {
78 		pch2 = (xmlChar *) systemid;
79 	}
80 
81 	if (strstr(name, "%00")) {
82 		php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
83 		RETURN_FALSE;
84 	}
85 
86 	uri = xmlParseURI(name);
87 	if (uri != NULL && uri->opaque != NULL) {
88 		localname = xmlStrdup((xmlChar *) uri->opaque);
89 		if (xmlStrchr(localname, (xmlChar) ':') != NULL) {
90 			php_dom_throw_error(NAMESPACE_ERR, 1);
91 			xmlFreeURI(uri);
92 			xmlFree(localname);
93 			RETURN_FALSE;
94 		}
95 	} else {
96 		localname = xmlStrdup((xmlChar *) name);
97 	}
98 
99 	/* TODO: Test that localname has no invalid chars
100 	php_dom_throw_error(INVALID_CHARACTER_ERR,);
101 	*/
102 
103 	if (uri) {
104 		xmlFreeURI(uri);
105 	}
106 
107 	doctype = xmlCreateIntSubset(NULL, localname, pch1, pch2);
108 	xmlFree(localname);
109 
110 	if (doctype == NULL) {
111 		php_error_docref(NULL, E_WARNING, "Unable to create DocumentType");
112 		RETURN_FALSE;
113 	}
114 
115 	DOM_RET_OBJ((xmlNodePtr) doctype, &ret, NULL);
116 }
117 /* }}} end dom_domimplementation_create_document_type */
118 
119 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocument
120 Since: DOM Level 2
121 */
PHP_METHOD(DOMImplementation,createDocument)122 PHP_METHOD(DOMImplementation, createDocument)
123 {
124 	zval *node = NULL;
125 	xmlDoc *docp;
126 	xmlNode *nodep;
127 	xmlDtdPtr doctype = NULL;
128 	xmlNsPtr nsptr = NULL;
129 	int ret, errorcode = 0;
130 	size_t uri_len = 0, name_len = 0;
131 	char *uri = NULL, *name = NULL;
132 	char *prefix = NULL, *localname = NULL;
133 	dom_object *doctobj;
134 
135 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!sO!", &uri, &uri_len, &name, &name_len, &node, dom_documenttype_class_entry) == FAILURE) {
136 		RETURN_THROWS();
137 	}
138 
139 	if (node != NULL) {
140 		DOM_GET_OBJ(doctype, node, xmlDtdPtr, doctobj);
141 		if (doctype->type == XML_DOCUMENT_TYPE_NODE) {
142 			zend_argument_value_error(3, "is an invalid DocumentType object");
143 			RETURN_THROWS();
144 		}
145 		if (doctype->doc != NULL) {
146 			php_dom_throw_error(WRONG_DOCUMENT_ERR, 1);
147 			RETURN_THROWS();
148 		}
149 	} else {
150 		doctobj = NULL;
151 	}
152 
153 	if (name_len > 0) {
154 		errorcode = dom_check_qname(name, &localname, &prefix, 1, name_len);
155 		if (errorcode == 0 && uri_len > 0
156 			&& ((nsptr = xmlNewNs(NULL, (xmlChar *) uri, (xmlChar *) prefix)) == NULL)
157 		) {
158 			errorcode = NAMESPACE_ERR;
159 		}
160 	}
161 
162 	if (prefix != NULL) {
163 		xmlFree(prefix);
164 	}
165 
166 	if (errorcode != 0) {
167 		if (localname != NULL) {
168 			xmlFree(localname);
169 		}
170 		php_dom_throw_error(errorcode, 1);
171 		RETURN_THROWS();
172 	}
173 
174 	/* currently letting libxml2 set the version string */
175 	docp = xmlNewDoc(NULL);
176 	if (!docp) {
177 		if (localname != NULL) {
178 			xmlFree(localname);
179 		}
180 		RETURN_FALSE;
181 	}
182 
183 	if (doctype != NULL) {
184 		docp->intSubset = doctype;
185 		doctype->parent = docp;
186 		doctype->doc = docp;
187 		docp->children = (xmlNodePtr) doctype;
188 		docp->last = (xmlNodePtr) doctype;
189 	}
190 
191 	if (localname != NULL) {
192 		nodep = xmlNewDocNode(docp, nsptr, (xmlChar *) localname, NULL);
193 		if (!nodep) {
194 			if (doctype != NULL) {
195 				docp->intSubset = NULL;
196 				doctype->parent = NULL;
197 				doctype->doc = NULL;
198 				docp->children = NULL;
199 				docp->last = NULL;
200 			}
201 			xmlFreeDoc(docp);
202 			xmlFree(localname);
203 			/* Need some better type of error here */
204 			php_dom_throw_error(PHP_ERR, 1);
205 			RETURN_THROWS();
206 		}
207 
208 		nodep->nsDef = nsptr;
209 
210 		xmlDocSetRootElement(docp, nodep);
211 		xmlFree(localname);
212 	}
213 
214 	DOM_RET_OBJ((xmlNodePtr) docp, &ret, NULL);
215 
216 	if (doctobj != NULL) {
217 		doctobj->document = ((dom_object *)((php_libxml_node_ptr *)docp->_private)->_private)->document;
218 		php_libxml_increment_doc_ref((php_libxml_node_object *)doctobj, docp);
219 	}
220 }
221 /* }}} end dom_domimplementation_create_document */
222 
223 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#DOMImplementation3-getFeature
224 Since: DOM Level 3
225 */
PHP_METHOD(DOMImplementation,getFeature)226 PHP_METHOD(DOMImplementation, getFeature)
227 {
228 	size_t feature_len, version_len;
229 	char *feature, *version;
230 
231 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &feature, &feature_len, &version, &version_len) == FAILURE) {
232 		RETURN_THROWS();
233 	}
234 
235 	DOM_NOT_IMPLEMENTED();
236 }
237 /* }}} end dom_domimplementation_get_feature */
238 
239 #endif
240