1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | 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
24 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
25
26 #include "php_dom.h"
27 #include "dom_properties.h"
28
29 /*
30 * class DOMAttr extends DOMNode
31 *
32 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-637646024
33 * Since:
34 */
35
36 /* {{{ */
PHP_METHOD(DOMAttr,__construct)37 PHP_METHOD(DOMAttr, __construct)
38 {
39 xmlAttrPtr nodep = NULL;
40 xmlNodePtr oldnode = NULL;
41 dom_object *intern;
42 char *name, *value = NULL;
43 size_t name_len, value_len, name_valid;
44
45 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
46 RETURN_THROWS();
47 }
48
49 intern = Z_DOMOBJ_P(ZEND_THIS);
50
51 name_valid = xmlValidateName(BAD_CAST name, 0);
52 if (name_valid != 0) {
53 php_dom_throw_error(INVALID_CHARACTER_ERR, true);
54 RETURN_THROWS();
55 }
56
57 nodep = xmlNewProp(NULL, BAD_CAST name, BAD_CAST value);
58
59 if (!nodep) {
60 php_dom_throw_error(INVALID_STATE_ERR, true);
61 RETURN_THROWS();
62 }
63
64 oldnode = dom_object_get_node(intern);
65 if (oldnode != NULL) {
66 php_libxml_node_decrement_resource((php_libxml_node_object *)intern);
67 }
68 php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)nodep, (void *)intern);
69 }
70
71 /* }}} end DOMAttr::__construct */
72
73 /* {{{ name string
74 readonly=yes
75 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-1112119403
76 Modern spec URL: https://dom.spec.whatwg.org/#dom-attr-name
77 Since:
78 */
dom_attr_name_read(dom_object * obj,zval * retval)79 zend_result dom_attr_name_read(dom_object *obj, zval *retval)
80 {
81 DOM_PROP_NODE(xmlAttrPtr, attrp, obj);
82
83 if (php_dom_follow_spec_intern(obj)) {
84 zend_string *str = dom_node_get_node_name_attribute_or_element((xmlNodePtr) attrp, false);
85 ZVAL_NEW_STR(retval, str);
86 } else {
87 ZVAL_STRING(retval, (char *) attrp->name);
88 }
89
90 return SUCCESS;
91 }
92
93 /* }}} */
94
95 /* {{{ specified boolean
96 readonly=yes
97 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-862529273
98 Since:
99 */
dom_attr_specified_read(dom_object * obj,zval * retval)100 zend_result dom_attr_specified_read(dom_object *obj, zval *retval)
101 {
102 /* From spec: "useless; always returns true" */
103 ZVAL_TRUE(retval);
104 return SUCCESS;
105 }
106
107 /* }}} */
108
109 /* {{{ value string
110 readonly=no
111 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-221662474
112 Since:
113 */
dom_attr_value_read(dom_object * obj,zval * retval)114 zend_result dom_attr_value_read(dom_object *obj, zval *retval)
115 {
116 DOM_PROP_NODE(xmlNodePtr, attrp, obj);
117 php_dom_get_content_into_zval(attrp, retval, false);
118 return SUCCESS;
119 }
120
dom_attr_value_write(dom_object * obj,zval * newval)121 zend_result dom_attr_value_write(dom_object *obj, zval *newval)
122 {
123 DOM_PROP_NODE(xmlAttrPtr, attrp, obj);
124
125 /* Typed property, this is already a string */
126 ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING);
127 zend_string *str = Z_STR_P(newval);
128
129 dom_remove_all_children((xmlNodePtr) attrp);
130
131 if (php_dom_follow_spec_intern(obj)) {
132 xmlNodePtr node = xmlNewDocTextLen(attrp->doc, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
133 xmlAddChild((xmlNodePtr) attrp, node);
134 } else {
135 xmlNodeSetContentLen((xmlNodePtr) attrp, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
136 }
137
138 return SUCCESS;
139 }
140
141 /* }}} */
142
143 /* {{{ ownerElement DOMElement
144 readonly=yes
145 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Attr-ownerElement
146 Since: DOM Level 2
147 */
dom_attr_owner_element_read(dom_object * obj,zval * retval)148 zend_result dom_attr_owner_element_read(dom_object *obj, zval *retval)
149 {
150 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
151
152 xmlNodePtr nodeparent = nodep->parent;
153 if (!nodeparent) {
154 ZVAL_NULL(retval);
155 return SUCCESS;
156 }
157
158 php_dom_create_object(nodeparent, retval, obj);
159 return SUCCESS;
160 }
161
162 /* }}} */
163
164 /* {{{ schemaTypeInfo DOMTypeInfo
165 readonly=yes
166 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Attr-schemaTypeInfo
167 Since: DOM Level 3
168 */
dom_attr_schema_type_info_read(dom_object * obj,zval * retval)169 zend_result dom_attr_schema_type_info_read(dom_object *obj, zval *retval)
170 {
171 /* TODO */
172 ZVAL_NULL(retval);
173 return SUCCESS;
174 }
175
176 /* }}} */
177
178 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Attr-isId
179 Since: DOM Level 3
180 */
PHP_METHOD(DOMAttr,isId)181 PHP_METHOD(DOMAttr, isId)
182 {
183 zval *id;
184 dom_object *intern;
185 xmlAttrPtr attrp;
186
187 id = ZEND_THIS;
188 if (zend_parse_parameters_none() == FAILURE) {
189 RETURN_THROWS();
190 }
191
192 DOM_GET_OBJ(attrp, id, xmlAttrPtr, intern);
193
194 if (attrp->atype == XML_ATTRIBUTE_ID) {
195 RETURN_TRUE;
196 } else {
197 RETURN_FALSE;
198 }
199 }
200 /* }}} end dom_attr_is_id */
201
dom_attr_value(const xmlAttr * attr,bool * free)202 xmlChar *dom_attr_value(const xmlAttr *attr, bool *free)
203 {
204 /* For attributes we can have an optimized fast-path.
205 * This fast-path is only possible in the (common) case where the attribute
206 * has a single text child. Note that if the child or the content is NULL, this
207 * is equivalent to not having content (i.e. the attribute has the empty string as value). */
208
209 *free = false;
210
211 if (attr->children == NULL) {
212 return BAD_CAST "";
213 }
214
215 if (attr->children->type == XML_TEXT_NODE && attr->children->next == NULL) {
216 if (attr->children->content == NULL) {
217 return BAD_CAST "";
218 } else {
219 return attr->children->content;
220 }
221 }
222
223 xmlChar *value = xmlNodeGetContent((const xmlNode *) attr);
224 if (UNEXPECTED(value == NULL)) {
225 return BAD_CAST "";
226 }
227
228 *free = true;
229 return value;
230 }
231
dom_compare_value(const xmlAttr * attr,const xmlChar * value)232 bool dom_compare_value(const xmlAttr *attr, const xmlChar *value)
233 {
234 bool free;
235 xmlChar *attr_value = dom_attr_value(attr, &free);
236 bool result = xmlStrEqual(attr_value, value);
237 if (free) {
238 xmlFree(attr_value);
239 }
240 return result;
241 }
242
243 #endif
244