diff options
-rw-r--r-- | ext/dom/documenttype.c | 42 | ||||
-rw-r--r-- | ext/dom/element.c | 36 | ||||
-rw-r--r-- | ext/dom/node.c | 94 | ||||
-rw-r--r-- | ext/dom/php_dom.c | 64 | ||||
-rw-r--r-- | ext/dom/php_dom.h | 2 |
5 files changed, 213 insertions, 25 deletions
diff --git a/ext/dom/documenttype.c b/ext/dom/documenttype.c index f937883b5f..5b1108ae48 100644 --- a/ext/dom/documenttype.c +++ b/ext/dom/documenttype.c @@ -33,6 +33,13 @@ struct _nodeIterator { xmlNode *node; }; +typedef struct _notationIterator notationIterator; +struct _notationIterator { + int cur; + int index; + xmlNotation *notation; +}; + static void itemHashScanner (void *payload, void *data, xmlChar *name) { nodeIterator *priv = (nodeIterator *)data; @@ -45,6 +52,31 @@ static void itemHashScanner (void *payload, void *data, xmlChar *name) { } } +/* {{{ static xmlEntityPtr create_notation(const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) */ +static xmlNodePtr create_notation(const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) { + xmlEntityPtr ret; + + ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); + memset(ret, 0, sizeof(xmlEntity)); + ret->type = XML_NOTATION_NODE; + ret->name = xmlStrdup(name); + ret->ExternalID = xmlStrdup(ExternalID); + ret->SystemID = xmlStrdup(SystemID); + ret->length = 0; + ret->content = NULL; + ret->URI = NULL; + ret->orig = NULL; + ret->children = NULL; + ret->parent = NULL; + ret->doc = NULL; + ret->_private = NULL; + ret->last = NULL; + ret->prev = NULL; + return((xmlNodePtr) ret); +} + /* * class domdocumenttype extends domnode * @@ -133,7 +165,8 @@ int dom_documenttype_notations_read(dom_object *obj, zval **retval TSRMLS_DC) { xmlDtdPtr doctypep; xmlHashTable *notationht; - nodeIterator *iter; + notationIterator *iter; + xmlNotationPtr notep = NULL; xmlNode *nodep = NULL; int ret, htsize, index = 0; @@ -149,12 +182,13 @@ int dom_documenttype_notations_read(dom_object *obj, zval **retval TSRMLS_DC) while (index < htsize) { iter->cur = 0; iter->index = index; - iter->node = NULL; + iter->notation = NULL; xmlHashScan(notationht, itemHashScanner, iter); index++; - nodep = iter->node; - if (nodep != NULL) { + notep = iter->notation; + if (notep != NULL) { zval *child; + nodep = create_notation(notep->name, notep->PublicID, notep->SystemID); MAKE_STD_ZVAL(child); child = php_dom_create_object(nodep, &ret, NULL, child, obj TSRMLS_CC); add_assoc_zval(*retval, (char *) nodep->name, child); diff --git a/ext/dom/element.c b/ext/dom/element.c index 1f5ca0505c..7f67f66cac 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -183,6 +183,11 @@ PHP_FUNCTION(dom_element_set_attribute) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + attr = xmlHasProp(nodep,name); if (attr != NULL) { node_list_unlink(attr->children TSRMLS_CC); @@ -218,6 +223,11 @@ PHP_FUNCTION(dom_element_remove_attribute) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + attrp = xmlHasProp(nodep,name); if (attrp == NULL) { RETURN_FALSE; @@ -284,6 +294,11 @@ PHP_FUNCTION(dom_element_set_attribute_node) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + DOM_GET_OBJ(attrp, node, xmlAttrPtr, attrobj); if (attrp->type != XML_ATTRIBUTE_NODE) { @@ -340,6 +355,11 @@ PHP_FUNCTION(dom_element_remove_attribute_node) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + attrp = xmlHasProp(nodep,name); if (attrp == NULL) { RETURN_FALSE; @@ -486,6 +506,12 @@ PHP_FUNCTION(dom_element_set_attribute_ns) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &uri, &uri_len, &name, &name_len) == FAILURE) { return; } + + if (dom_node_is_read_only(elemp) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + nsptr = xmlSearchNsByHref (elemp->doc, elemp, uri); if (nsptr == NULL) { nsptr = dom_get_ns(uri, name, uri_len, name_len, &errorcode, (char **) &localname); @@ -538,6 +564,11 @@ PHP_FUNCTION(dom_element_remove_attribute_ns) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + if (xmlStrEqual(uri, DOM_XMLNS_NAMESPACE)) { DOM_NOT_IMPLEMENTED(); } else { @@ -620,6 +651,11 @@ PHP_FUNCTION(dom_element_set_attribute_node_ns) return; } + if (dom_node_is_read_only(nodep) == SUCCESS) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + DOM_GET_OBJ(attrp, node, xmlAttrPtr, attrobj); if (attrp->type != XML_ATTRIBUTE_NODE) { diff --git a/ext/dom/node.c b/ext/dom/node.c index 87b0cff72f..2faedfee80 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -154,7 +154,7 @@ currently here as a convience method while developing */ ZVAL_STRING(*retval, str, 1); xmlFree(str); } else { - ZVAL_EMPTY_STRING(*retval); + ZVAL_NULL(*retval); } @@ -202,7 +202,14 @@ int dom_node_node_type_read(dom_object *obj, zval **retval TSRMLS_DC) nodep = dom_object_get_node(obj); ALLOC_ZVAL(*retval); - ZVAL_LONG(*retval, nodep->type); + + /* Specs dictate that they are both type XML_DOCUMENT_TYPE_NODE */ + if (nodep->type == XML_DTD_NODE) { + ZVAL_LONG(*retval, XML_DOCUMENT_TYPE_NODE); + } else { + ZVAL_LONG(*retval, nodep->type); + } + return SUCCESS; } @@ -252,23 +259,27 @@ int dom_node_child_nodes_read(dom_object *obj, zval **retval TSRMLS_DC) nodep = dom_object_get_node(obj); - if ((nodep->type == XML_DOCUMENT_NODE) || (nodep->type == XML_HTML_DOCUMENT_NODE)) { - last = ((xmlDoc *) nodep)->children; + if (dom_node_children_valid(nodep) == SUCCESS) { + if ((nodep->type == XML_DOCUMENT_NODE) || (nodep->type == XML_HTML_DOCUMENT_NODE)) { + last = ((xmlDoc *) nodep)->children; + } else { + last = nodep->children; + } } else { - last = nodep->children; + last = NULL; } + MAKE_STD_ZVAL(*retval); array_init(*retval); - if (last) { - while (last) { - zval *child; - MAKE_STD_ZVAL(child); - child = php_dom_create_object(last, &ret, NULL, child, obj TSRMLS_CC); - add_next_index_zval(*retval, child); - last = last->next; - } + while (last) { + zval *child; + MAKE_STD_ZVAL(child); + child = php_dom_create_object(last, &ret, NULL, child, obj TSRMLS_CC); + add_next_index_zval(*retval, child); + last = last->next; } + return SUCCESS; } @@ -283,12 +294,15 @@ Since: */ int dom_node_first_child_read(dom_object *obj, zval **retval TSRMLS_DC) { - xmlNode *nodep, *first; + xmlNode *nodep, *first = NULL; int ret; nodep = dom_object_get_node(obj); - first = nodep->children; + if (dom_node_children_valid(nodep) == SUCCESS) { + first = nodep->children; + } + if (!first) { return FAILURE; } @@ -313,12 +327,15 @@ Since: */ int dom_node_last_child_read(dom_object *obj, zval **retval TSRMLS_DC) { - xmlNode *nodep, *last; + xmlNode *nodep, *last = NULL; int ret; nodep = dom_object_get_node(obj); - last = nodep->last; + if (dom_node_children_valid(nodep) == SUCCESS) { + last = nodep->last; + } + if (!last) { return FAILURE; } @@ -499,7 +516,7 @@ int dom_node_namespace_uri_read(dom_object *obj, zval **retval TSRMLS_DC) if(str != NULL) { ZVAL_STRING(*retval, str, 1); } else { - ZVAL_EMPTY_STRING(*retval); + ZVAL_NULL(*retval); } return SUCCESS; @@ -709,6 +726,12 @@ PHP_FUNCTION(dom_node_insert_before) new_child = NULL; + if (dom_node_is_read_only(parentp) == SUCCESS || + (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + if (dom_hierarchy(parentp, child) == FAILURE) { php_dom_throw_error(HIERARCHY_REQUEST_ERR, &return_value TSRMLS_CC); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hierarchy Request Error"); @@ -854,6 +877,10 @@ PHP_FUNCTION(dom_node_replace_child) DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern); + if (dom_node_children_valid(nodep) == FAILURE) { + RETURN_FALSE; + } + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oo", &newnode, &oldnode) == FAILURE) { return; } @@ -866,6 +893,12 @@ PHP_FUNCTION(dom_node_replace_child) RETURN_FALSE; } + if (dom_node_is_read_only(nodep) == SUCCESS || + (newchild->parent != NULL && dom_node_is_read_only(newchild->parent) == SUCCESS)) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + if (newchild->doc != nodep->doc && newchild->doc != NULL) { php_dom_throw_error(WRONG_DOCUMENT_ERR, &return_value TSRMLS_CC); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't add newnode as it was created from a different document"); @@ -892,6 +925,7 @@ PHP_FUNCTION(dom_node_replace_child) if (oldchild != newchild) { xmlNodePtr node; if (newchild->doc == NULL && nodep->doc != NULL) { + xmlSetTreeDoc(newchild, nodep->doc); newchildobj->document = intern->document; increment_document_reference(newchildobj, NULL TSRMLS_CC); } @@ -925,8 +959,18 @@ PHP_FUNCTION(dom_node_remove_child) return; } + if (dom_node_children_valid(nodep) == FAILURE) { + RETURN_FALSE; + } + DOM_GET_OBJ(child, node, xmlNodePtr, childobj); + if (dom_node_is_read_only(nodep) == SUCCESS || + (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + children = nodep->children; if (!children) { php_dom_throw_error(NOT_FOUND_ERR, &return_value TSRMLS_CC); @@ -966,8 +1010,18 @@ PHP_FUNCTION(dom_node_append_child) return; } + if (dom_node_children_valid(nodep) == FAILURE) { + RETURN_FALSE; + } + DOM_GET_OBJ(child, node, xmlNodePtr, childobj); + if (dom_node_is_read_only(nodep) == SUCCESS || + (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, &return_value TSRMLS_CC); + RETURN_FALSE; + } + if (dom_hierarchy(nodep, child) == FAILURE) { php_dom_throw_error(HIERARCHY_REQUEST_ERR, &return_value TSRMLS_CC); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hierarchy Request Error"); @@ -1053,6 +1107,10 @@ PHP_FUNCTION(dom_node_has_child_nodes) DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern); DOM_NO_ARGS(); + + if (dom_node_children_valid(nodep) == FAILURE) { + RETURN_FALSE; + } if (nodep->children) { RETURN_TRUE; diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index b366ecd511..c23d30436b 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -73,6 +73,42 @@ static zend_function_entry dom_functions[] = { {NULL, NULL, NULL} }; +/* {{{ int dom_node_is_read_only(xmlNodePtr node) */ +int dom_node_is_read_only(xmlNodePtr node) { + switch (node->type) { + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NAMESPACE_DECL: + return SUCCESS; + break; + default: + return FAILURE; + } +} +/* }}} end dom_node_is_read_only */ + +/* {{{ int dom_node_children_valid(xmlNodePtr node) */ +int dom_node_children_valid(xmlNodePtr node) { + switch (node->type) { + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + return FAILURE; + break; + default: + return SUCCESS; + } +} +/* }}} end dom_node_children_valid */ /* {{{ int increment_document_reference(dom_object *object) */ int increment_document_reference(dom_object *object, xmlDocPtr docp TSRMLS_DC) { @@ -500,12 +536,15 @@ PHP_MINIT_FUNCTION(dom) zend_hash_merge(&dom_documenttype_prop_handlers, &dom_node_prop_handlers, NULL, NULL, sizeof(dom_prop_handler), 0); zend_hash_add(&classes, ce.name, ce.name_length + 1, &dom_documenttype_prop_handlers, sizeof(dom_documenttype_prop_handlers), NULL); - REGISTER_DOM_CLASS(ce, "domnotation", dom_node_class_entry, php_dom_notation_class_functions, dom_notation_class_entry); + REGISTER_DOM_CLASS(ce, "domnotation", NULL, php_dom_notation_class_functions, dom_notation_class_entry); zend_hash_init(&dom_notation_prop_handlers, 0, NULL, NULL, 1); dom_register_prop_handler(&dom_notation_prop_handlers, "publicId", dom_notation_public_id_read, NULL TSRMLS_CC); dom_register_prop_handler(&dom_notation_prop_handlers, "systemId", dom_notation_system_id_read, NULL TSRMLS_CC); - zend_hash_merge(&dom_notation_prop_handlers, &dom_node_prop_handlers, NULL, NULL, sizeof(dom_prop_handler), 0); + /* Notation nodes are special */ + dom_register_prop_handler(&dom_notation_prop_handlers, "nodeName", dom_node_node_name_read, NULL TSRMLS_CC); + dom_register_prop_handler(&dom_notation_prop_handlers, "nodeValue", dom_node_node_value_read, dom_node_node_value_write TSRMLS_CC); + dom_register_prop_handler(&dom_notation_prop_handlers, "attributes", dom_node_attributes_read, NULL TSRMLS_CC); zend_hash_add(&classes, ce.name, ce.name_length + 1, &dom_notation_prop_handlers, sizeof(dom_notation_prop_handlers), NULL); REGISTER_DOM_CLASS(ce, "domentity", dom_node_class_entry, php_dom_entity_class_functions, dom_entity_class_entry); @@ -620,7 +659,7 @@ PHP_MSHUTDOWN_FUNCTION(dom) uncomment the following line, this will tell you the amount of not freed memory and the total used memory into apaches error_log */ /* xmlMemoryDump();*/ - +xmlMemoryDump(); return SUCCESS; } @@ -669,6 +708,23 @@ void dom_node_free(xmlNodePtr node) xmlFreeProp((xmlAttrPtr) node); break; case XML_ENTITY_DECL: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_NAMESPACE_DECL: + /* These can never stand alone */ + break; + case XML_NOTATION_NODE: + /* These require special handling */ + if (node->name != NULL) { + xmlFree((char *) node->name); + } + if (((xmlEntityPtr) node)->ExternalID != NULL) { + xmlFree((char *) ((xmlEntityPtr) node)->ExternalID); + } + if (((xmlEntityPtr) node)->SystemID != NULL) { + xmlFree((char *) ((xmlEntityPtr) node)->SystemID); + } + xmlFree(node); break; default: xmlFreeNode(node); @@ -688,6 +744,8 @@ void node_free_list(xmlNodePtr node TSRMLS_DC) node = curnode; switch (node->type) { /* Skip property freeing for the following types */ + case XML_NOTATION_NODE: + break; case XML_ENTITY_REF_NODE: node_free_list((xmlNodePtr) node->properties TSRMLS_CC); break; diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index a1f5f69f93..d3a5eb0bfc 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -83,6 +83,8 @@ void php_dom_create_implementation(zval **retval TSRMLS_DC); int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child); int dom_has_feature(char *feature, char *version); void add_domdocument_properties(zval *id TSRMLS_DC); +int dom_node_is_read_only(xmlNodePtr node); +int dom_node_children_valid(xmlNodePtr node); #define REGISTER_DOM_CLASS(ce, name, parent_ce, funcs, entry) \ INIT_CLASS_ENTRY(ce, name, funcs); \ |