static void exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlXPathObjectPtr ret = NULL; if (ctxt == NULL) return; if (nargs != 1) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "dyn:evalute() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } str = xmlXPathPopString(ctxt); if (!str||!xmlStrlen(str)) { if (str) xmlFree(str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathEval(str,ctxt->context); if (ret) valuePush(ctxt,ret); else { xsltGenericError(xsltGenericErrorContext, "dyn:evaluate() : unable to evaluate expression '%s'\n",str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); } xmlFree(str); return; }
/** * exsltStrReturnString: * @ctxt: an XPath parser context * @str: a string * @len: length of string * * Returns a string as a node set. */ static int exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, int len) { xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); xmlDocPtr container; xmlNodePtr text_node; xmlXPathObjectPtr ret; container = xsltCreateRVT(tctxt); if (container == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xsltRegisterLocalRVT(tctxt, container); text_node = xmlNewTextLen(str, len); if (text_node == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xmlAddChild((xmlNodePtr) container, text_node); ret = xmlXPathNewNodeSet(text_node); if (ret == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xsltExtensionInstructionResultRegister(tctxt, ret); valuePush(ctxt, ret); return(0); }
USER_OBJECT_ R_xmlXPathNewNodeSet(USER_OBJECT_ s_node) { xmlNodePtr node = (xmlNodePtr) R_ExternalPtrAddr(s_node); xmlXPathObjectPtr nodeset; nodeset = xmlXPathNewNodeSet(node); return(RXSLT_export_xmlXPathObject(nodeset->nodesetval, "XPathNodeSet")); }
/************************************************************************** * * xmlSecXPathHereFunction: * @ctxt: the ponter to XPath context. * @nargs: the arguments nubmer. * * The implementation of XPath "here()" function. * See xmlXPtrHereFunction() in xpointer.c. the only change is that * we return NodeSet instead of NodeInterval. * *****************************************************************************/ static void xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) { XP_ERROR(XPTR_SYNTAX_ERROR); } valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->here)); }
/** * xsltCurrentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the current() XSLT function * node-set current() */ static void xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltTransformContextPtr tctxt; if (nargs != 0) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "current() : function uses no argument\n"); ctxt->error = XPATH_INVALID_ARITY; return; } tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "current() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */ } }
xmlXPathObjectPtr rxml_xpath_from_value(VALUE value) { xmlXPathObjectPtr result = NULL; switch (TYPE(value)) { case T_TRUE: case T_FALSE: result = xmlXPathNewBoolean(RTEST(value)); break; case T_FIXNUM: case T_FLOAT: result = xmlXPathNewFloat(NUM2DBL(value)); break; case T_STRING: result = xmlXPathWrapString(xmlStrdup((const xmlChar *)StringValuePtr(value))); break; case T_NIL: result = xmlXPathNewNodeSet(NULL); break; case T_ARRAY: { long i, j; result = xmlXPathNewNodeSet(NULL); for (i = RARRAY_LEN(value); i > 0; i--) { xmlXPathObjectPtr obj = rxml_xpath_from_value(rb_ary_shift(value)); if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) { for (j = 0; j < obj->nodesetval->nodeNr; j++) { xmlXPathNodeSetAdd(result->nodesetval, obj->nodesetval->nodeTab[j]); } } } break; } default: rb_raise(rb_eTypeError, "can't convert object of type %s to XPath object", rb_obj_classname(value) ); } return result; }
static void exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) { if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } if (xmlXPathStackIsNodeSet (ctxt)) { xsltFunctionNodeSet (ctxt, nargs); return; } else { xmlDocPtr fragment; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); xmlNodePtr txt; xmlChar *strval; xmlXPathObjectPtr obj; /* * SPEC EXSLT: * "You can also use this function to turn a string into a text * node, which is helpful if you want to pass a string to a * function that only accepts a node-set." */ fragment = xsltCreateRVT(tctxt); if (fragment == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltNodeSetFunction: Failed to create a tree fragment.\n"); tctxt->state = XSLT_STATE_STOPPED; return; } xsltRegisterLocalRVT(tctxt, fragment); strval = xmlXPathPopString (ctxt); txt = xmlNewDocText (fragment, strval); xmlAddChild((xmlNodePtr) fragment, txt); obj = xmlXPathNewNodeSet(txt); if (obj == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltNodeSetFunction: Failed to create a node set object.\n"); tctxt->state = XSLT_STATE_STOPPED; } else { /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, obj); } if (strval != NULL) xmlFree (strval); valuePush (ctxt, obj); } }
static void xslt_yelp_input (xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlXPathObjectPtr ret; YelpTransform *transform; tctxt = xsltXPathGetTransformContext (ctxt); transform = (YelpTransform *) tctxt->_private; /* FIXME: pretty sure this eats transform->input, memory corruption will follow */ transform->input_xslt = xsltNewDocument (tctxt, transform->input); ret = xmlXPathNewNodeSet (xmlDocGetRootElement (transform->input)); xsltExtensionInstructionResultRegister (tctxt, ret); valuePush (ctxt, ret); }
static void xslt_yelp_aux (xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlXPathObjectPtr ret; YelpTransform *transform; YelpTransformPrivate *priv; tctxt = xsltXPathGetTransformContext (ctxt); transform = YELP_TRANSFORM (tctxt->_private); priv = GET_PRIV (transform); priv->aux_xslt = xsltNewDocument (tctxt, priv->aux); ret = xmlXPathNewNodeSet (xmlDocGetRootElement (priv->aux)); xsltExtensionInstructionResultRegister (tctxt, ret); valuePush (ctxt, ret); }
static void exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlNodeSetPtr nodeset = NULL; xsltTransformContextPtr tctxt; xmlXPathCompExprPtr comp = NULL; xmlXPathObjectPtr ret = NULL; xmlDocPtr oldDoc, container = NULL; xmlNodePtr oldNode; int oldContextSize; int oldProximityPosition; int i, j; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } nodeset = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathNewNodeSet(NULL); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltDynMapFunction: ret == NULL\n"); goto cleanup; } oldDoc = ctxt->context->doc; oldNode = ctxt->context->node; oldContextSize = ctxt->context->contextSize; oldProximityPosition = ctxt->context->proximityPosition; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "dyn:map : internal error tctxt == NULL\n"); goto cleanup; } container = xsltCreateRVT(tctxt); if (container == NULL) { xsltTransformError(tctxt, NULL, NULL, "dyn:map : internal error container == NULL\n"); goto cleanup; } xsltRegisterLocalRVT(tctxt, container); if (nodeset && nodeset->nodeNr > 0) { xmlXPathNodeSetSort(nodeset); ctxt->context->contextSize = nodeset->nodeNr; ctxt->context->proximityPosition = 0; for (i = 0; i < nodeset->nodeNr; i++) { xmlXPathObjectPtr subResult = NULL; ctxt->context->proximityPosition++; ctxt->context->node = nodeset->nodeTab[i]; ctxt->context->doc = nodeset->nodeTab[i]->doc; subResult = xmlXPathCompiledEval(comp, ctxt->context); if (subResult != NULL) { switch (subResult->type) { case XPATH_NODESET: if (subResult->nodesetval != NULL) for (j = 0; j < subResult->nodesetval->nodeNr; j++) xmlXPathNodeSetAdd(ret->nodesetval, subResult->nodesetval-> nodeTab[j]); break; case XPATH_BOOLEAN: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "boolean", BAD_CAST (subResult-> boolval ? "true" : "")); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_NUMBER: if (container != NULL) { xmlChar *val = xmlXPathCastNumberToString(subResult-> floatval); xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "number", val); if (val != NULL) xmlFree(val); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_STRING: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "string", subResult->stringval); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; default: break; } xmlXPathFreeObject(subResult); } } } ctxt->context->doc = oldDoc; ctxt->context->node = oldNode; ctxt->context->contextSize = oldContextSize; ctxt->context->proximityPosition = oldProximityPosition; cleanup: if (comp != NULL) xmlXPathFreeCompExpr(comp); if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, ret); return; }
static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */ { zval retval; int result, i; int error = 0; zend_fcall_info fci; xmlXPathObjectPtr obj; char *str; zend_string *callable = NULL; dom_xpath_object *intern; if (! zend_is_executing()) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: Function called from outside of PHP\n"); error = 1; } else { intern = (dom_xpath_object *) ctxt->context->userData; if (intern == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: failed to get the internal object\n"); error = 1; } else if (intern->registerPhpFunctions == 0) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: PHP Object did not register PHP functions\n"); error = 1; } } if (error == 1) { for (i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); xmlXPathFreeObject(obj); } return; } fci.param_count = nargs - 1; if (fci.param_count > 0) { fci.params = safe_emalloc(fci.param_count, sizeof(zval), 0); } /* Reverse order to pop values off ctxt stack */ for (i = nargs - 2; i >= 0; i--) { obj = valuePop(ctxt); switch (obj->type) { case XPATH_STRING: ZVAL_STRING(&fci.params[i], (char *)obj->stringval); break; case XPATH_BOOLEAN: ZVAL_BOOL(&fci.params[i], obj->boolval); break; case XPATH_NUMBER: ZVAL_DOUBLE(&fci.params[i], obj->floatval); break; case XPATH_NODESET: if (type == 1) { str = (char *)xmlXPathCastToString(obj); ZVAL_STRING(&fci.params[i], str); xmlFree(str); } else if (type == 2) { int j; array_init(&fci.params[i]); if (obj->nodesetval && obj->nodesetval->nodeNr > 0) { for (j = 0; j < obj->nodesetval->nodeNr; j++) { xmlNodePtr node = obj->nodesetval->nodeTab[j]; zval child; /* not sure, if we need this... it's copied from xpath.c */ if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr curns; xmlNodePtr nsparent; nsparent = node->_private; curns = xmlNewNs(NULL, node->name, NULL); if (node->children) { curns->prefix = xmlStrdup((xmlChar *) node->children); } if (node->children) { node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name); } else { node = xmlNewDocNode(node->doc, NULL, (xmlChar *) "xmlns", node->name); } node->type = XML_NAMESPACE_DECL; node->parent = nsparent; node->ns = curns; } php_dom_create_object(node, &child, &intern->dom); add_next_index_zval(&fci.params[i], &child); } } } break; default: ZVAL_STRING(&fci.params[i], (char *)xmlXPathCastToString(obj)); } xmlXPathFreeObject(obj); } fci.size = sizeof(fci); fci.function_table = EG(function_table); obj = valuePop(ctxt); if (obj->stringval == NULL) { php_error_docref(NULL, E_WARNING, "Handler name must be a string"); xmlXPathFreeObject(obj); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&fci.params[i]); } efree(fci.params); } return; } ZVAL_STRING(&fci.function_name, (char *) obj->stringval); xmlXPathFreeObject(obj); fci.symbol_table = NULL; fci.object = NULL; fci.retval = &retval; fci.no_separation = 0; if (!zend_make_callable(&fci.function_name, &callable)) { php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", callable->val); } else if (intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) { php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'.", callable->val); /* Push an empty string, so that we at least have an xslt result... */ valuePush(ctxt, xmlXPathNewString((xmlChar *)"")); } else { result = zend_call_function(&fci, NULL); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) { xmlNode *nodep; dom_object *obj; if (intern->node_list == NULL) { ALLOC_HASHTABLE(intern->node_list); zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0); } GC_REFCOUNT(&retval)++; zend_hash_next_index_insert(intern->node_list, &retval); obj = Z_DOMOBJ_P(&retval); nodep = dom_object_get_node(obj); valuePush(ctxt, xmlXPathNewNodeSet(nodep)); } else if (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE) { valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE)); } else if (Z_TYPE(retval) == IS_OBJECT) { php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string"); valuePush(ctxt, xmlXPathNewString((xmlChar *)"")); } else { zend_string *str = zval_get_string(&retval); valuePush(ctxt, xmlXPathNewString((xmlChar *) str->val)); zend_string_release(str); } zval_ptr_dtor(&retval); } } zend_string_release(callable); zval_dtor(&fci.function_name); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&fci.params[i]); } efree(fci.params); } }
/** * exsltStrTokenizeFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on the characters of the delimiter string and returns a * node set of token elements, each containing one token from the string. */ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiters = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); } if (delimiters == NULL) return; str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiters); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterTmpRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { ret->boolval = 0; /* Freeing is not handled there anymore */ for (cur = str, token = str; *cur != 0; cur++) { for (delimiter = delimiters; *delimiter != 0; delimiter++) { if (*cur == *delimiter) { if (cur == token) { /* discard empty tokens */ token = cur + 1; break; } *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; token = cur + 1; break; } } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } } } fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) xmlFree(delimiters); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
static void xslt_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) { XSLTProcessorData *intern = nullptr; int error = 0; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext (ctxt); if (tctxt == nullptr) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the transformation context\n" ); error = 1; } else { intern = (XSLTProcessorData*)tctxt->_private; if (intern == nullptr) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the internal object\n" ); error = 1; } else { if (intern->m_registerPhpFunctions == 0) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: PHP Object did not register PHP functions\n" ); error = 1; } } } xmlXPathObjectPtr obj; if (error == 1) { for (int i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); xmlXPathFreeObject(obj); } return; } Array args; // Reverse order to pop values off ctxt stack for (int i = nargs - 2; i >= 0; i--) { Variant arg; obj = valuePop(ctxt); switch (obj->type) { case XPATH_STRING: arg = String((char*)obj->stringval, CopyString); break; case XPATH_BOOLEAN: arg = (bool)obj->boolval; break; case XPATH_NUMBER: arg = (double)obj->floatval; break; case XPATH_NODESET: if (type == 1) { char *str = (char*)xmlXPathCastToString(obj); arg = String(str, CopyString); xmlFree(str); } else if (type == 2) { arg = Array::Create(); if (obj->nodesetval && obj->nodesetval->nodeNr > 0) { for (int j = 0; j < obj->nodesetval->nodeNr; j++) { // TODO: not sure this is the right thing to do. xmlNodePtr node = obj->nodesetval->nodeTab[j]; if (node->type == XML_ELEMENT_NODE) { Object element = newNode(s_DOMElement, xmlCopyNode(node, /*extended*/ 1)); arg.toArrRef().append(element); } else if (node->type == XML_ATTRIBUTE_NODE) { Object attribute = newNode(s_DOMAttr, (xmlNodePtr)xmlCopyProp(nullptr, (xmlAttrPtr)node)); arg.toArrRef().append(attribute); } else if (node->type == XML_TEXT_NODE) { Object text = newNode(s_DOMText, (xmlNodePtr)xmlNewText(xmlNodeGetContent(node))); arg.toArrRef().append(text); } else { raise_warning("Unhandled node type '%d'", node->type); // Use a generic DOMNode as fallback for now. Object nodeobj = newNode(s_DOMNode, xmlCopyNode(node, /*extended*/ 1)); arg.toArrRef().append(nodeobj); } } } } break; default: arg = String((char*)xmlXPathCastToString(obj), CopyString); } xmlXPathFreeObject(obj); args.prepend(arg); } obj = valuePop(ctxt); if (obj->stringval == nullptr) { raise_warning("Handler name must be a string"); xmlXPathFreeObject(obj); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); return; } String handler((char*)obj->stringval, CopyString); xmlXPathFreeObject(obj); if (!HHVM_FN(is_callable)(handler)) { raise_warning("Unable to call handler %s()", handler.data()); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else if (intern->m_registerPhpFunctions == 2 && !intern->m_registered_phpfunctions.exists(handler)) { raise_warning("Not allowed to call handler '%s()'", handler.data()); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else { Variant retval = vm_call_user_func(handler, args); if (retval.isObject() && retval.getObjectData()->instanceof(s_DOMNode)) { ObjectData *retval_data = retval.asCObjRef().get(); xmlNode* nodep = Native::data<DOMNode>(retval_data)->nodep(); valuePush(ctxt, xmlXPathNewNodeSet(nodep)); intern->m_usedElements.prepend(retval); } else if (retval.is(KindOfBoolean)) { valuePush(ctxt, xmlXPathNewBoolean(retval.toBoolean())); } else if (retval.isObject()) { raise_warning("A PHP Object cannot be converted to an XPath-string"); // Push an empty string to get an xslt result. valuePush(ctxt, xmlXPathNewString((xmlChar*)"")); } else { String sretval = retval.toString(); valuePush(ctxt, xmlXPathNewString((xmlChar*)sretval.data())); } } }
/** * xsltKeyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the key() XSLT function * node-set key(string, object) */ void xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj1, obj2; if (nargs != 2) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "key() : expects two arguments\n"); ctxt->error = XPATH_INVALID_ARITY; return; } /* * Get the key's value. */ obj2 = valuePop(ctxt); xmlXPathStringFunction(ctxt, 1); if ((obj2 == NULL) || (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj2); return; } /* * Get the key's name. */ obj1 = valuePop(ctxt); if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) { int i; xmlXPathObjectPtr newobj, ret; ret = xmlXPathNewNodeSet(NULL); if (obj2->nodesetval != NULL) { for (i = 0; i < obj2->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathObjectCopy(obj1)); valuePush(ctxt, xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); xsltKeyFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } valuePush(ctxt, ret); } else { xmlNodeSetPtr nodelist = NULL; xmlChar *key = NULL, *value; const xmlChar *keyURI; xsltTransformContextPtr tctxt; xmlChar *qname, *prefix; xmlXPathContextPtr xpctxt = ctxt->context; xmlNodePtr tmpNode = NULL; xsltDocumentPtr oldDocInfo; tctxt = xsltXPathGetTransformContext(ctxt); oldDocInfo = tctxt->document; if (xpctxt->node == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "The context node is not set on the XPath context.\n"); tctxt->state = XSLT_STATE_STOPPED; goto error; } /* * Get the associated namespace URI if qualified name */ qname = obj1->stringval; key = xmlSplitQName2(qname, &prefix); if (key == NULL) { key = xmlStrdup(obj1->stringval); keyURI = NULL; if (prefix != NULL) xmlFree(prefix); } else { if (prefix != NULL) { keyURI = xmlXPathNsLookup(xpctxt, prefix); if (keyURI == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "key() : prefix %s is not bound\n", prefix); /* * TODO: Shouldn't we stop here? */ } xmlFree(prefix); } else { keyURI = NULL; } } /* * Force conversion of first arg to string */ valuePush(ctxt, obj2); xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(tctxt, NULL, tctxt->inst, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; goto error; } obj2 = valuePop(ctxt); value = obj2->stringval; /* * We need to ensure that ctxt->document is available for * xsltGetKey(). * First find the relevant doc, which is the context node's * owner doc; using context->doc is not safe, since * the doc could have been acquired via the document() function, * or the doc might be a Result Tree Fragment. * FUTURE INFO: In XSLT 2.0 the key() function takes an additional * argument indicating the doc to use. */ if (xpctxt->node->type == XML_NAMESPACE_DECL) { /* * REVISIT: This is a libxml hack! Check xpath.c for details. * The XPath module sets the owner element of a ns-node on * the ns->next field. */ if ((((xmlNsPtr) xpctxt->node)->next != NULL) && (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE)) { tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next; } } else tmpNode = xpctxt->node; if ((tmpNode == NULL) || (tmpNode->doc == NULL)) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "Couldn't get the doc of the XPath context node.\n"); goto error; } if ((tctxt->document == NULL) || (tctxt->document->doc != tmpNode->doc)) { if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) { /* * This is a Result Tree Fragment. */ if (tmpNode->doc->_private == NULL) { tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc); if (tmpNode->doc->_private == NULL) goto error; } tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private; } else { /* * May be the initial source doc or a doc acquired via the * document() function. */ tctxt->document = xsltFindDocument(tctxt, tmpNode->doc); } if (tctxt->document == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "Could not get the document info of a context doc.\n"); tctxt->state = XSLT_STATE_STOPPED; goto error; } } /* * Get/compute the key value. */ nodelist = xsltGetKey(tctxt, key, keyURI, value); error: tctxt->document = oldDocInfo; valuePush(ctxt, xmlXPathWrapNodeSet( xmlXPathNodeSetMerge(NULL, nodelist))); if (key != NULL) xmlFree(key); } if (obj1 != NULL) xmlXPathFreeObject(obj1); if (obj2 != NULL) xmlXPathFreeObject(obj2); }
void swft_import_png( xmlXPathParserContextPtr ctx, int nargs ) { xsltTransformContextPtr tctx; char *filename; xsltDocumentPtr xsltdoc; xmlDocPtr doc = NULL; xmlNodePtr node; xmlXPathObjectPtr obj; char tmp[TMP_STRLEN]; png_colorp palette; int n_pal; int format = 5; int data_size = 0; xmlXPathStringFunction(ctx, 1); if (ctx->value->type != XPATH_STRING) { xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL, "swft:import-png() : invalid arg expecting a string\n"); ctx->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctx); if (obj->stringval == NULL) { valuePush(ctx, xmlXPathNewNodeSet(NULL)); return; } tctx = xsltXPathGetTransformContext(ctx); filename = swft_get_filename(obj->stringval, ctx->context->doc->URL); bool quiet = true; xmlXPathObjectPtr quietObj = xsltVariableLookup( tctx, (const xmlChar*)"quiet", NULL ); if (quietObj && quietObj->stringval) { quiet = !strcmp("true", (const char*)quietObj->stringval ); } FILE *fp = fopen( filename, "rb" ); if( !fp ) { xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL, "swft:import-png() : failed to read file '%s'\n", filename); valuePush(ctx, xmlXPathNewNodeSet(NULL)); goto fail; } doc = xmlNewDoc( (const xmlChar *)"1.0"); doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"png", NULL ); node = doc->xmlRootNode; swft_addFileName( node, filename ); // add data rewind(fp); unsigned char *data, *compressed; unsigned long w, h, rowbytes; int channels; int compressed_size; if( !fp ) goto fail; if( readpng_init( fp, &w, &h ) ) goto fail; // add w/h snprintf(tmp, TMP_STRLEN, "%lu", w); xmlSetProp( node, (const xmlChar *)"width", (const xmlChar *)&tmp ); snprintf(tmp,TMP_STRLEN,"%lu", h); xmlSetProp( node, (const xmlChar *)"height", (const xmlChar *)&tmp ); data = readpng_get_image( 2.2, &channels, &rowbytes, &palette, &n_pal ); if( !quiet ) { fprintf(stderr,"Importing PNG: '%s' (%lu bit/pixel)\n", filename, (rowbytes*8)/w ); } if( channels == 4 && rowbytes == (4*w) ) { int c; float a; unsigned char r,g,b; for( int i=0; i<w*h*4; i+=4 ) { a = data[i+3]/255.0; r = (unsigned char)((data[i+0])*a); g = (unsigned char)((data[i+1])*a); b = (unsigned char)((data[i+2])*a); data[i] = data[i+3]; data[i+1] = r; data[i+2] = g; data[i+3] = b; } data_size = w*h*4; } else if( channels == 3 && rowbytes == (3*w) ) { unsigned char *rgba = new unsigned char[ w*h*4 ]; for( int i=0; i<w*h; i++ ) { rgba[i*4] = 0xff; rgba[(i*4)+3] = data[(i*3)+2]; rgba[(i*4)+2] = data[(i*3)+1]; rgba[(i*4)+1] = data[(i*3)]; } data = rgba; data_size = w*h*4; } else if( channels == 1 && rowbytes == w ) { unsigned char *img_data = data; format = 3; int bpr = rowbytes; bpr += (rowbytes % 4) ? 4 - (rowbytes % 4) : 0; if( n_pal ) { data_size = (4*n_pal) + (bpr*h); data = new unsigned char[ data_size ]; for( int i=0; i<n_pal; i++ ) { unsigned char *entry = &data[(i*4)]; entry[2] = palette[i].blue; entry[1] = palette[i].green; entry[0] = palette[i].red; entry[3] = 0xff; } } else { n_pal = 0xff; data_size = (4*n_pal) + (bpr*h); data = new unsigned char[ data_size ]; for( int i=0; i<n_pal; i++ ) { unsigned char *entry = &data[(i*4)]; entry[2] = i; entry[1] = i; entry[0] = i; entry[3] = 0xff; } } /* copy row by row with 32bit alignment */ unsigned char *dst = &data[ (4*n_pal) ]; unsigned char *src = img_data; memset( dst, 0, bpr*h ); for( int y=0; y<h; y++ ) { memcpy( dst, src, rowbytes ); dst += bpr; src += rowbytes; } snprintf(tmp,TMP_STRLEN,"%i", n_pal-1 ); xmlSetProp( node, (const xmlChar *)"n_colormap", (const xmlChar *)&tmp ); } else { fprintf(stderr, "WARNING: can only import 8bit palette, 24 or 32bit " "RGB(A) PNGs (%s has %i channels, rowstride %lu)\n", filename, channels, rowbytes); goto fail; } // format is 5 for RGB(A), 3 for palette (4 for 16bit, unused) snprintf(tmp,TMP_STRLEN,"%i", format ); xmlSetProp( node, (const xmlChar *)"format", (const xmlChar *)&tmp ); compressed_size = data_size; if( compressed_size < 1024 ) compressed_size = 1024; compressed = new unsigned char[ compressed_size ]; if( compress( data, data_size, compressed, &compressed_size ) ) { swft_addData( node, (char*)compressed, compressed_size ); valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) ); } goto end; fail: fprintf( stderr, "WARNING: could not import %s\n", filename ); end: if (fp) { fclose(fp); } delete compressed; delete filename; readpng_cleanup( true ); }
/** * xsltKeyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the key() XSLT function * node-set key(string, object) */ void xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlNodeSetPtr nodelist; xmlXPathObjectPtr obj1, obj2; xmlChar *key = NULL, *value; const xmlChar *keyURI; xsltTransformContextPtr tctxt; if (nargs != 2) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : expects two arguments\n"); ctxt->error = XPATH_INVALID_ARITY; return; } obj2 = valuePop(ctxt); if ((obj2 == NULL) || (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj2); return; } obj1 = valuePop(ctxt); if (obj2->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; ret = xmlXPathNewNodeSet(NULL); if (obj2->nodesetval != NULL) { for (i = 0; i < obj2->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathObjectCopy(obj1)); valuePush(ctxt, xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); xsltKeyFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } valuePush(ctxt, ret); } else { xmlChar *qname, *prefix; /* * Get the associated namespace URI if qualified name */ qname = obj1->stringval; key = xmlSplitQName2(qname, &prefix); if (key == NULL) { key = xmlStrdup(obj1->stringval); keyURI = NULL; if (prefix != NULL) xmlFree(prefix); } else { if (prefix != NULL) { keyURI = xmlXPathNsLookup(ctxt->context, prefix); if (keyURI == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : prefix %s is not bound\n", prefix); } xmlFree(prefix); } else { keyURI = NULL; } } /* * Force conversion of first arg to string */ valuePush(ctxt, obj2); xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj1); return; } obj2 = valuePop(ctxt); value = obj2->stringval; tctxt = xsltXPathGetTransformContext(ctxt); nodelist = xsltGetKey(tctxt, key, keyURI, value); valuePush(ctxt, xmlXPathWrapNodeSet( xmlXPathNodeSetMerge(NULL, nodelist))); } if (obj1 != NULL) xmlXPathFreeObject(obj1); if (obj2 != NULL) xmlXPathFreeObject(obj2); if (key != NULL) xmlFree(key); }
/** * exsltStrTokenizeFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on the characters of the delimiter string and returns a * node set of token elements, each containing one token from the string. */ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int clen; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiters = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); } if (delimiters == NULL) return; str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiters); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur += clen) { clen = xmlUTF8Size(cur); if (*delimiters == 0) { /* empty string case */ xmlChar ctmp; ctmp = *(cur+clen); *(cur+clen) = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", cur); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *(cur+clen) = ctmp; /* restore the changed byte */ token = cur + clen; } else for (delimiter = delimiters; *delimiter != 0; delimiter += xmlUTF8Size(delimiter)) { if (!xmlUTF8Charcmp(cur, delimiter)) { if (cur == token) { /* discard empty tokens */ token = cur + clen; break; } *cur = 0; /* terminate the token */ node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; /* restore the changed byte */ token = cur + clen; break; } } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) xmlFree(delimiters); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */ { xsltTransformContextPtr tctxt; zval *args; zval retval; int result, i; int error = 0; zend_fcall_info fci; zval handler; xmlXPathObjectPtr obj; char *str; xsl_object *intern; zend_string *callable = NULL; if (! zend_is_executing()) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: Function called from outside of PHP\n"); error = 1; } else { tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the transformation context\n"); error = 1; } else { intern = (xsl_object*)tctxt->_private; if (intern == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: failed to get the internal object\n"); error = 1; } else if (intern->registerPhpFunctions == 0) { xsltGenericError(xsltGenericErrorContext, "xsltExtFunctionTest: PHP Object did not register PHP functions\n"); error = 1; } } } if (error == 1) { for (i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); xmlXPathFreeObject(obj); } return; } fci.param_count = nargs - 1; if (fci.param_count > 0) { args = safe_emalloc(fci.param_count, sizeof(zval), 0); } /* Reverse order to pop values off ctxt stack */ for (i = nargs - 2; i >= 0; i--) { obj = valuePop(ctxt); switch (obj->type) { case XPATH_STRING: ZVAL_STRING(&args[i], (char *)obj->stringval); break; case XPATH_BOOLEAN: ZVAL_BOOL(&args[i], obj->boolval); break; case XPATH_NUMBER: ZVAL_DOUBLE(&args[i], obj->floatval); break; case XPATH_NODESET: if (type == 1) { str = (char*)xmlXPathCastToString(obj); ZVAL_STRING(&args[i], str); xmlFree(str); } else if (type == 2) { int j; dom_object *domintern = (dom_object *)intern->doc; array_init(&args[i]); if (obj->nodesetval && obj->nodesetval->nodeNr > 0) { for (j = 0; j < obj->nodesetval->nodeNr; j++) { xmlNodePtr node = obj->nodesetval->nodeTab[j]; zval child; /* not sure, if we need this... it's copied from xpath.c */ if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr curns; xmlNodePtr nsparent; nsparent = node->_private; curns = xmlNewNs(NULL, node->name, NULL); if (node->children) { curns->prefix = xmlStrdup((char *)node->children); } if (node->children) { node = xmlNewDocNode(node->doc, NULL, (char *) node->children, node->name); } else { node = xmlNewDocNode(node->doc, NULL, (const xmlChar *) "xmlns", node->name); } node->type = XML_NAMESPACE_DECL; node->parent = nsparent; node->ns = curns; } else { node = xmlDocCopyNodeList(domintern->document->ptr, node); } php_dom_create_object(node, &child, domintern); add_next_index_zval(&args[i], &child); } } } break; default: str = (char *) xmlXPathCastToString(obj); ZVAL_STRING(&args[i], str); xmlFree(str); } xmlXPathFreeObject(obj); } fci.size = sizeof(fci); fci.function_table = EG(function_table); if (fci.param_count > 0) { fci.params = args; } else { fci.params = NULL; } obj = valuePop(ctxt); if (obj->stringval == NULL) { php_error_docref(NULL, E_WARNING, "Handler name must be a string"); xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&args[i]); } efree(args); } return; } ZVAL_STRING(&handler, (char *) obj->stringval); xmlXPathFreeObject(obj); ZVAL_COPY_VALUE(&fci.function_name, &handler); fci.symbol_table = NULL; fci.object = NULL; fci.retval = &retval; fci.no_separation = 0; /*fci.function_handler_cache = &function_ptr;*/ if (!zend_make_callable(&handler, &callable)) { php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable)); valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) { php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable)); /* Push an empty string, so that we at least have an xslt result... */ valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); } else { result = zend_call_function(&fci, NULL); if (result == FAILURE) { if (Z_TYPE(handler) == IS_STRING) { php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL(handler)); valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); } /* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */ } else if (Z_ISUNDEF(retval)) { } else { if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) { xmlNode *nodep; dom_object *obj; if (intern->node_list == NULL) { ALLOC_HASHTABLE(intern->node_list); zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0); } Z_ADDREF(retval); zend_hash_next_index_insert(intern->node_list, &retval); obj = Z_DOMOBJ_P(&retval); nodep = dom_object_get_node(obj); valuePush(ctxt, xmlXPathNewNodeSet(nodep)); } else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) { valuePush(ctxt, xmlXPathNewBoolean(Z_LVAL(retval))); } else if (Z_TYPE(retval) == IS_OBJECT) { php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string"); valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); } else { convert_to_string_ex(&retval); valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval))); } zval_ptr_dtor(&retval); } } zend_string_release(callable); zval_ptr_dtor(&handler); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&args[i]); } efree(args); } }
static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */ { zval **args = NULL; zval *retval; int result, i, ret; int error = 0; zend_fcall_info fci; zval handler; xmlXPathObjectPtr obj; char *str; char *callable = NULL; dom_xpath_object *intern; TSRMLS_FETCH(); if (! zend_is_executing(TSRMLS_C)) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: Function called from outside of PHP\n"); error = 1; } else { intern = (dom_xpath_object *) ctxt->context->userData; if (intern == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: failed to get the internal object\n"); error = 1; } else if (intern->registerPhpFunctions == 0) { xmlGenericError(xmlGenericErrorContext, "xmlExtFunctionTest: PHP Object did not register PHP functions\n"); error = 1; } } if (error == 1) { for (i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); xmlXPathFreeObject(obj); } return; } fci.param_count = nargs - 1; if (fci.param_count > 0) { fci.params = safe_emalloc(fci.param_count, sizeof(zval**), 0); args = safe_emalloc(fci.param_count, sizeof(zval *), 0); } /* Reverse order to pop values off ctxt stack */ for (i = nargs - 2; i >= 0; i--) { obj = valuePop(ctxt); MAKE_STD_ZVAL(args[i]); switch (obj->type) { case XPATH_STRING: ZVAL_STRING(args[i], (char *)obj->stringval, 1); break; case XPATH_BOOLEAN: ZVAL_BOOL(args[i], obj->boolval); break; case XPATH_NUMBER: ZVAL_DOUBLE(args[i], obj->floatval); break; case XPATH_NODESET: if (type == 1) { str = (char *)xmlXPathCastToString(obj); ZVAL_STRING(args[i], str, 1); xmlFree(str); } else if (type == 2) { int j; array_init(args[i]); if (obj->nodesetval && obj->nodesetval->nodeNr > 0) { for (j = 0; j < obj->nodesetval->nodeNr; j++) { xmlNodePtr node = obj->nodesetval->nodeTab[j]; zval *child; MAKE_STD_ZVAL(child); /* not sure, if we need this... it's copied from xpath.c */ if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr curns; xmlNodePtr nsparent; nsparent = node->_private; curns = xmlNewNs(NULL, node->name, NULL); if (node->children) { curns->prefix = xmlStrdup((xmlChar *) node->children); } if (node->children) { node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name); } else { node = xmlNewDocNode(node->doc, NULL, (xmlChar *) "xmlns", node->name); } node->type = XML_NAMESPACE_DECL; node->parent = nsparent; node->ns = curns; } child = php_dom_create_object(node, &ret, child, (dom_object *)intern TSRMLS_CC); add_next_index_zval(args[i], child); } } } break; default: ZVAL_STRING(args[i], (char *)xmlXPathCastToString(obj), 1); } xmlXPathFreeObject(obj); fci.params[i] = &args[i]; } fci.size = sizeof(fci); fci.function_table = EG(function_table); obj = valuePop(ctxt); if (obj->stringval == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string"); xmlXPathFreeObject(obj); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&args[i]); } efree(args); efree(fci.params); } return; } INIT_PZVAL(&handler); ZVAL_STRING(&handler, obj->stringval, 1); xmlXPathFreeObject(obj); fci.function_name = &handler; fci.symbol_table = NULL; fci.object_ptr = NULL; fci.retval_ptr_ptr = &retval; fci.no_separation = 0; if (!zend_make_callable(&handler, &callable TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", callable); } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable, strlen(callable) + 1) == 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not allowed to call handler '%s()'.", callable); /* Push an empty string, so that we at least have an xslt result... */ valuePush(ctxt, xmlXPathNewString((xmlChar *)"")); } else { result = zend_call_function(&fci, NULL TSRMLS_CC); if (result == FAILURE) { if (Z_TYPE(handler) == IS_STRING) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", Z_STRVAL_P(&handler)); } /* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */ } else if (retval == NULL) { } else { if (retval->type == IS_OBJECT && instanceof_function( Z_OBJCE_P(retval), dom_node_class_entry TSRMLS_CC)) { xmlNode *nodep; dom_object *obj; if (intern->node_list == NULL) { ALLOC_HASHTABLE(intern->node_list); zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0); } zval_add_ref(&retval); zend_hash_next_index_insert(intern->node_list, &retval, sizeof(zval *), NULL); obj = (dom_object *)zend_object_store_get_object(retval TSRMLS_CC); nodep = dom_object_get_node(obj); valuePush(ctxt, xmlXPathNewNodeSet(nodep)); } else if (retval->type == IS_BOOL) { valuePush(ctxt, xmlXPathNewBoolean(retval->value.lval)); } else if (retval->type == IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "A PHP Object cannot be converted to a XPath-string"); valuePush(ctxt, xmlXPathNewString((xmlChar *)"")); } else { convert_to_string_ex(&retval); valuePush(ctxt, xmlXPathNewString( Z_STRVAL_P(retval))); } zval_ptr_dtor(&retval); } } efree(callable); zval_dtor(&handler); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { zval_ptr_dtor(&args[i]); } efree(args); efree(fci.params); } }
static void exsltRegexpMatchFunction (xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; xmlChar *haystack, *regexp, *flagstr, *working, *match; int rc, x, flags, global, ovector[30]; if ((nargs < 1) || (nargs > 3)) { xmlXPathSetArityError(ctxt); return; } if (nargs > 2) { flagstr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (flagstr == NULL)) { return; } } else { flagstr = xmlStrdup(""); } regexp = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (regexp == NULL)) { xmlFree(flagstr); return; } haystack = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (haystack == NULL)) { xmlFree(regexp); xmlFree(flagstr); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:regexp : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterTmpRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { ret->boolval = 0; exsltRegexpFlagsFromString(flagstr, &global, &flags); working = haystack; rc = exsltRegexpExecute(ctxt, working, regexp, flags, ovector, sizeof(ovector)/sizeof(int)); while (rc > 0) { for(int group = 0; group < rc; group++) { match = xmlStrsub(working, ovector[group*2], ovector[group*2+1]-ovector[group*2]); if (NULL == match) goto fail; node = xmlNewDocRawNode(container, NULL, "match", match); xmlFree(match); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } if (!global) break; working = working + ovector[1]; rc = exsltRegexpExecute(ctxt, working, regexp, flags, ovector, sizeof(ovector)/sizeof(int)); } } } fail: if (flagstr != NULL) xmlFree(flagstr); if (regexp != NULL) xmlFree(regexp); if (haystack != NULL) xmlFree(haystack); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
/** * exsltStrSplitFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on a delimiting string and returns a node set of token * elements, each containing one token from the string. */ static void exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiter, *cur; const xmlChar *token; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int delimiterLength; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiter = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiter = xmlStrdup((const xmlChar *) " "); } if (delimiter == NULL) return; delimiterLength = xmlStrlen (delimiter); str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiter); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } /* * OPTIMIZE TODO: We are creating an xmlDoc for every split! */ container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur++) { if (delimiterLength == 0) { if (cur != token) { xmlChar tmp = *cur; *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = tmp; token++; } } else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { if (cur == token) { /* discard empty tokens */ cur = cur + delimiterLength - 1; token = cur + 1; continue; } *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; cur = cur + delimiterLength - 1; token = cur + 1; } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiter != NULL) xmlFree(delimiter); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
static void xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI) { xsltTransformContextPtr tctxt; xmlURIPtr uri; xmlChar *fragment; xsltDocumentPtr idoc; /* document info */ xmlDocPtr doc; xmlXPathContextPtr xptrctxt = NULL; xmlXPathObjectPtr resObj = NULL; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(NULL, NULL, NULL, "document() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } uri = xmlParseURI((const char *) URI); if (uri == NULL) { xsltTransformError(tctxt, NULL, NULL, "document() : failed to parse URI\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } /* * check for and remove fragment identifier */ fragment = (xmlChar *)uri->fragment; if (fragment != NULL) { xmlChar *newURI; uri->fragment = NULL; newURI = xmlSaveUri(uri); idoc = xsltLoadDocument(tctxt, newURI); xmlFree(newURI); } else idoc = xsltLoadDocument(tctxt, URI); xmlFreeURI(uri); if (idoc == NULL) { if ((URI == NULL) || (URI[0] == '#') || ((tctxt->style->doc != NULL) && (xmlStrEqual(tctxt->style->doc->URL, URI)))) { /* * This selects the stylesheet's doc itself. */ doc = tctxt->style->doc; } else { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); if (fragment != NULL) xmlFree(fragment); return; } } else doc = idoc->doc; if (fragment == NULL) { valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc)); return; } /* use XPointer of HTML location for fragment ID */ #ifdef LIBXML_XPTR_ENABLED xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); if (xptrctxt == NULL) { xsltTransformError(tctxt, NULL, NULL, "document() : internal error xptrctxt == NULL\n"); goto out_fragment; } resObj = xmlXPtrEval(fragment, xptrctxt); xmlXPathFreeContext(xptrctxt); #endif if (resObj == NULL) goto out_fragment; switch (resObj->type) { case XPATH_NODESET: break; case XPATH_UNDEFINED: case XPATH_BOOLEAN: case XPATH_NUMBER: case XPATH_STRING: case XPATH_POINT: case XPATH_USERS: case XPATH_XSLT_TREE: case XPATH_RANGE: case XPATH_LOCATIONSET: xsltTransformError(tctxt, NULL, NULL, "document() : XPointer does not select a node set: #%s\n", fragment); goto out_object; } valuePush(ctxt, resObj); xmlFree(fragment); return; out_object: xmlXPathFreeObject(resObj); out_fragment: valuePush(ctxt, xmlXPathNewNodeSet(NULL)); xmlFree(fragment); }
/** * xsltDocumentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the document() XSLT function * node-set document(object, node-set?) */ void xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj, obj2 = NULL; xmlChar *base = NULL, *URI; if ((nargs < 1) || (nargs > 2)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } if (ctxt->value == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg value\n"); ctxt->error = XPATH_INVALID_TYPE; return; } if (nargs == 2) { if (ctxt->value->type != XPATH_NODESET) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg expecting a nodeset\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj2 = valuePop(ctxt); } if (ctxt->value->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; obj = valuePop(ctxt); ret = xmlXPathNewNodeSet(NULL); if ((obj != NULL) && obj->nodesetval) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); if (nargs == 2) { valuePush(ctxt, xmlXPathObjectCopy(obj2)); } else { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval-> nodeTab[i])); } xsltDocumentFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } if (obj != NULL) xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); valuePush(ctxt, ret); return; } /* * Make sure it's converted to a string */ xmlXPathStringFunction(ctxt, 1); if (ctxt->value->type != XPATH_STRING) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; if (obj2 != NULL) xmlXPathFreeObject(obj2); return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((obj2 != NULL) && (obj2->nodesetval != NULL) && (obj2->nodesetval->nodeNr > 0) && IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) { xmlNodePtr target; target = obj2->nodesetval->nodeTab[0]; if ((target->type == XML_ATTRIBUTE_NODE) || (target->type == XML_PI_NODE)) { target = ((xmlAttrPtr) target)->parent; } base = xmlNodeGetBase(target->doc, target); } else { if ((tctxt != NULL) && (tctxt->inst != NULL)) { base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst); } else if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL)) { base = xmlNodeGetBase(tctxt->style->doc, (xmlNodePtr) tctxt->style->doc); } } URI = xmlBuildURI(obj->stringval, base); if (base != NULL) xmlFree(base); if (URI == NULL) { if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL) && (xmlStrEqual(URI, tctxt->style->doc->URL))) { /* This selects the stylesheet's doc itself. */ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) tctxt->style->doc)); } else { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } } else { xsltDocumentFunctionLoadDocument( ctxt, URI ); xmlFree(URI); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); }
/** * xsltDocumentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the document() XSLT function * node-set document(object, node-set?) */ void xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltDocumentPtr doc; xmlXPathObjectPtr obj, obj2 = NULL; xmlChar *base = NULL, *URI; if ((nargs < 1) || (nargs > 2)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } if (ctxt->value == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg value\n"); ctxt->error = XPATH_INVALID_TYPE; return; } if (nargs == 2) { if (ctxt->value->type != XPATH_NODESET) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg expecting a nodeset\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj2 = valuePop(ctxt); } if (ctxt->value->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; obj = valuePop(ctxt); ret = xmlXPathNewNodeSet(NULL); if (obj->nodesetval) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); if (nargs == 2) { valuePush(ctxt, xmlXPathObjectCopy(obj2)); } else { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); } xsltDocumentFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); valuePush(ctxt, ret); return; } /* * Make sure it's converted to a string */ xmlXPathStringFunction(ctxt, 1); if (ctxt->value->type != XPATH_STRING) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; if (obj2 != NULL) xmlXPathFreeObject(obj2); return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if ((obj2 != NULL) && (obj2->nodesetval != NULL) && (obj2->nodesetval->nodeNr > 0) && IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) { xmlNodePtr target; target = obj2->nodesetval->nodeTab[0]; if (target->type == XML_ATTRIBUTE_NODE) { target = ((xmlAttrPtr) target)->parent; } base = xmlNodeGetBase(target->doc, target); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((tctxt != NULL) && (tctxt->inst != NULL)) { base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst); } else if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL)) { base = xmlNodeGetBase(tctxt->style->doc, (xmlNodePtr) tctxt->style->doc); } } URI = xmlBuildURI(obj->stringval, base); if (base != NULL) xmlFree(base); if (URI == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if (xmlStrEqual(tctxt->style->doc->URL, URI)) { valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)tctxt->style->doc)); } else { doc = xsltLoadDocument(tctxt, URI); if (doc == NULL) valuePush(ctxt, xmlXPathNewNodeSet(NULL)); else { /* TODO: use XPointer of HTML location for fragment ID */ /* pbm #xxx can lead to location sets, not nodesets :-) */ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc->doc)); } } } xmlFree(URI); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); }