From c12a24ef337889ed1f980cce2baf78ac6bd0ee93 Mon Sep 17 00:00:00 2001 From: defanor Date: Sun, 18 Jun 2023 17:38:35 +0300 Subject: Duplicate most of the XML functions in Rust, use Cargo --- configure.ac | 5 +- src/Cargo.toml | 15 ++ src/Makefile.am | 10 +- src/rexmpp_rust.rs | 2 + src/rexmpp_xml.c | 30 +-- src/rexmpp_xml.h | 8 +- src/rexmpp_xml.rs | 621 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 671 insertions(+), 20 deletions(-) create mode 100644 src/Cargo.toml create mode 100644 src/rexmpp_rust.rs create mode 100644 src/rexmpp_xml.rs diff --git a/configure.ac b/configure.ac index e9588fa..251a94f 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,10 @@ AC_ARG_WITH([rust], AS_IF([test "x$with_rust" == "xyes"], [AC_PATH_PROG([RUSTC], [rustc], [notfound]) - AS_IF([test "x$RUSTC" == "xnotfound"], [AC_MSG_ERROR([rustc is required])])]) + AS_IF([test "x$RUSTC" == "xnotfound"], [AC_MSG_ERROR([rustc is required])]) + AC_PATH_PROG([CARGO], [cargo], [notfound]) + AS_IF([test "x$CARGO" == "xnotfound"], [AC_MSG_ERROR([cargo is required])]) + AC_DEFINE([USE_RUST], [1], [Use Rust sources over C ones])]) AM_CONDITIONAL([USE_RUST], [test "x$with_rust" == "xyes"]) LT_INIT diff --git a/src/Cargo.toml b/src/Cargo.toml new file mode 100644 index 0000000..fc59bfc --- /dev/null +++ b/src/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rexmpp_rust" +version = "0.1.0" +authors = ["defanor "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "rexmpp_rust" +crate-type = ["staticlib"] +path = "rexmpp_rust.rs" + +[dependencies] +libc = "0.2" diff --git a/src/Makefile.am b/src/Makefile.am index 0955d81..36365ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,13 +40,13 @@ librexmpp_la_LIBADD = $(LIBXML_LIBS) \ librexmpp_la_LDFLAGS = [] if USE_RUST -librexmpp_rust_a_SOURCES = rexmpp_socks.rs -noinst_LIBRARIES = librexmpp_rust.a -librexmpp_la_LIBADD += librexmpp_rust.a +target_debug_librexmpp_rust_a_SOURCES = rexmpp_rust.rs rexmpp_socks.rs rexmpp_xml.rs +noinst_LIBRARIES = target/debug/librexmpp_rust.a +librexmpp_la_LIBADD += target/debug/librexmpp_rust.a librexmpp_la_LDFLAGS += -L. -lpthread -ldl -librexmpp_rust.a: $(librexmpp_rust_a_SOURCES) - rustc --crate-type=staticlib -o $@ $(librexmpp_rust_a_SOURCES) +target/debug/librexmpp_rust.a: $(target_debug_librexmpp_rust_a_SOURCES) + $(CARGO) build else librexmpp_la_SOURCES += rexmpp_socks.h rexmpp_socks.c diff --git a/src/rexmpp_rust.rs b/src/rexmpp_rust.rs new file mode 100644 index 0000000..9fa3ae4 --- /dev/null +++ b/src/rexmpp_rust.rs @@ -0,0 +1,2 @@ +mod rexmpp_socks; +mod rexmpp_xml; diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c index 8c91d32..f384470 100644 --- a/src/rexmpp_xml.c +++ b/src/rexmpp_xml.c @@ -12,6 +12,7 @@ #include "rexmpp.h" #include "rexmpp_xml.h" +#ifndef USE_RUST void rexmpp_xml_qname_free (rexmpp_xml_qname_t *qname) { if (qname->name != NULL) { free(qname->name); @@ -116,7 +117,7 @@ rexmpp_xml_t *rexmpp_xml_clone_list (rexmpp_xml_t *node) { } return first; } - +#endif rexmpp_xml_t *rexmpp_xml_from_libxml2 (xmlNodePtr from) { if (from == NULL) { @@ -244,6 +245,7 @@ xmlNodePtr rexmpp_xml_to_libxml2_list (rexmpp_xml_t *from) { return to; } +#ifndef USE_RUST rexmpp_xml_t *rexmpp_xml_new_text (const char *str) { rexmpp_xml_t *node = malloc(sizeof(rexmpp_xml_t)); node->type = REXMPP_XML_TEXT; @@ -273,7 +275,6 @@ int rexmpp_xml_add_text (rexmpp_xml_t *node, return -1; } - rexmpp_xml_t *rexmpp_xml_new_elem (const char *name, const char *namespace) { @@ -308,9 +309,9 @@ rexmpp_xml_attr_t *rexmpp_xml_attr_new (const char *name, } int rexmpp_xml_add_attr_ns (rexmpp_xml_t *node, - const char *name, - const char *namespace, - const char *value) + const char *name, + const char *namespace, + const char *value) { if (node == NULL || node->type != REXMPP_XML_ELEMENT) { return -1; @@ -323,8 +324,8 @@ int rexmpp_xml_add_attr_ns (rexmpp_xml_t *node, } int rexmpp_xml_remove_attr_ns (rexmpp_xml_t *node, - const char *name, - const char *namespace) { + const char *name, + const char *namespace) { if (node == NULL || node->type != REXMPP_XML_ELEMENT) { return -1; } @@ -342,16 +343,17 @@ int rexmpp_xml_remove_attr_ns (rexmpp_xml_t *node, } int rexmpp_xml_add_attr (rexmpp_xml_t *node, - const char *name, - const char *value) + const char *name, + const char *value) { return rexmpp_xml_add_attr_ns(node, name, NULL, value); } int rexmpp_xml_remove_attr (rexmpp_xml_t *node, - const char *name) { + const char *name) { return rexmpp_xml_remove_attr_ns(node, name, NULL); } +#endif rexmpp_xml_t * rexmpp_xml_add_id (rexmpp_t *s, @@ -416,6 +418,7 @@ int rexmpp_xml_write_file (const char *path, rexmpp_xml_t* node) { return 0; } +#ifndef USE_RUST unsigned int rexmpp_xml_siblings_count (rexmpp_xml_t *node) { unsigned int i = 0; for (i = 0; node != NULL; i++) { @@ -538,6 +541,7 @@ rexmpp_xml_find_child (rexmpp_xml_t *node, } return NULL; } +#endif int rexmpp_xml_eq (rexmpp_xml_t *n1, rexmpp_xml_t *n2) { /* Just serialize and compare strings for now: awkward, but @@ -550,6 +554,7 @@ int rexmpp_xml_eq (rexmpp_xml_t *n1, rexmpp_xml_t *n2) { return eq; } +#ifndef USE_RUST rexmpp_xml_t *rexmpp_xml_children (rexmpp_xml_t *node) { if (node != NULL && node->type == REXMPP_XML_ELEMENT) { return node->alt.elem.children; @@ -580,13 +585,14 @@ rexmpp_xml_t *rexmpp_xml_next_elem_sibling (rexmpp_xml_t *node) { return NULL; } -const char *rexmpp_xml_text (rexmpp_xml_t *node) { +char *rexmpp_xml_text (rexmpp_xml_t *node) { if (node != NULL && node->type == REXMPP_XML_TEXT) { return node->alt.text; } return NULL; } -const char *rexmpp_xml_text_child (rexmpp_xml_t *node) { +char *rexmpp_xml_text_child (rexmpp_xml_t *node) { return rexmpp_xml_text(rexmpp_xml_children(node)); } +#endif diff --git a/src/rexmpp_xml.h b/src/rexmpp_xml.h index 33f61f2..dbd8ea8 100644 --- a/src/rexmpp_xml.h +++ b/src/rexmpp_xml.h @@ -47,6 +47,10 @@ struct rexmpp_xml_node { }; +void rexmpp_xml_qname_free (rexmpp_xml_qname_t *qname); +void rexmpp_xml_attribute_free (rexmpp_xml_attr_t *attr); +void rexmpp_xml_attribute_free_list (rexmpp_xml_attr_t *attr); + /** @brief Frees a single XML node. Does not free its siblings. */ @@ -205,9 +209,9 @@ rexmpp_xml_t *rexmpp_xml_find_child (rexmpp_xml_t *node, rexmpp_xml_t *rexmpp_xml_children (rexmpp_xml_t *node); -const char *rexmpp_xml_text (rexmpp_xml_t *node); +char *rexmpp_xml_text (rexmpp_xml_t *node); -const char *rexmpp_xml_text_child (rexmpp_xml_t *node); +char *rexmpp_xml_text_child (rexmpp_xml_t *node); rexmpp_xml_t *rexmpp_xml_first_elem_child (rexmpp_xml_t *node); diff --git a/src/rexmpp_xml.rs b/src/rexmpp_xml.rs new file mode 100644 index 0000000..89b87a8 --- /dev/null +++ b/src/rexmpp_xml.rs @@ -0,0 +1,621 @@ +extern crate libc; +use libc::{strdup, free}; +use std::os::raw::{c_char, c_int, c_void, c_uint}; +use std::ptr; +use std::ffi::{CStr, CString}; +use std::clone::Clone; + +// extern { +// fn rexmpp_xml_serialize (node: *mut RexmppXML) -> *mut c_char; +// fn rexmpp_xml_parse (str: *mut c_char, str_len: c_int) -> *mut RexmppXML; +// } + +#[repr(C)] +pub struct RexmppXMLQName { + name: *mut c_char, + namespace: *mut c_char +} + +impl Copy for RexmppXMLQName { } + +impl Clone for RexmppXMLQName { + fn clone(&self) -> RexmppXMLQName { + RexmppXMLQName { + name: unsafe { strdup(self.name) }, + namespace: if self.namespace != ptr::null_mut() { + unsafe { strdup(self.namespace) } + } else { + ptr::null_mut() + } + } + } +} + +#[repr(C)] +pub struct RexmppXMLAttribute { + qname: RexmppXMLQName, + value: *mut c_char, + next: *mut RexmppXMLAttribute +} + +impl Copy for RexmppXMLAttribute { } + +impl Clone for RexmppXMLAttribute { + fn clone(&self) -> RexmppXMLAttribute { + RexmppXMLAttribute { + qname: Clone::clone(&self.qname), + value: unsafe { strdup(self.value) }, + next: ptr::null_mut() + } + } +} + +#[derive(Copy, Clone)] +#[derive(PartialEq)] +#[repr(C)] +enum NodeType { + Element, + Text +} + +#[repr(C)] +struct RexmppXMLAltElem { + qname: RexmppXMLQName, + attributes: *mut RexmppXMLAttribute, + children: *mut RexmppXML +} + +impl Copy for RexmppXMLAltElem { } + +impl Clone for RexmppXMLAltElem { + fn clone(&self) -> RexmppXMLAltElem { + let mut ret = RexmppXMLAltElem { + qname: Clone::clone(&self.qname), + attributes: ptr::null_mut(), + children: ptr::null_mut() + }; + let mut old_attr_ptr = self.attributes; + let mut next_attr_ptr_ptr : *mut *mut RexmppXMLAttribute = &mut ret.attributes; + while old_attr_ptr != ptr::null_mut() { + let old_attr = unsafe { *old_attr_ptr }; + let new_attr_ptr = rexmpp_xml_attr_new(old_attr.qname.name, + old_attr.qname.namespace, + old_attr.value); + unsafe { (*next_attr_ptr_ptr) = new_attr_ptr }; + next_attr_ptr_ptr = unsafe { &mut ((*new_attr_ptr).next) }; + old_attr_ptr = old_attr.next; + } + ret.children = rexmpp_xml_clone_list(self.children); + return ret; + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +union RexmppXMLAlt { + elem: RexmppXMLAltElem, + text: *mut c_char +} + +#[repr(C)] +pub struct RexmppXML { + node_type: NodeType, + alt: RexmppXMLAlt, + next: *mut RexmppXML +} + +impl Copy for RexmppXML { } + +impl Clone for RexmppXML { + fn clone(&self) -> RexmppXML { + RexmppXML { + node_type: Clone::clone(&self.node_type), + alt: match self.node_type { + NodeType::Text => RexmppXMLAlt + { text: unsafe { strdup(self.alt.text) }}, + NodeType::Element => RexmppXMLAlt + { elem: Clone::clone(& unsafe { self.alt.elem }) } + }, + next: ptr::null_mut() + } + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_qname_free (qname_ptr: *const RexmppXMLQName) { + if qname_ptr == ptr::null_mut() { + return; + } + let mut qname : RexmppXMLQName = unsafe { *qname_ptr }; + if qname.name != ptr::null_mut() { + unsafe { free(qname.name as *mut c_void) }; + qname.name = ptr::null_mut(); + } + if qname.namespace != ptr::null_mut() { + unsafe { free(qname.namespace as *mut c_void) }; + qname.namespace = ptr::null_mut(); + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_attribute_free (attr_ptr: *mut RexmppXMLAttribute) { + if attr_ptr == ptr::null_mut() { + return; + } + let mut attr : RexmppXMLAttribute = unsafe { *Box::from_raw(attr_ptr) }; + rexmpp_xml_qname_free(&(attr.qname)); + if attr.value != ptr::null_mut() { + unsafe { free(attr.value as *mut c_void) } + attr.value = ptr::null_mut(); + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_attribute_free_list (mut attr_ptr: *mut RexmppXMLAttribute) { + let mut next; + while attr_ptr != ptr::null_mut() { + next = unsafe { (*attr_ptr).next }; + rexmpp_xml_attribute_free(attr_ptr); + attr_ptr = next; + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_free (node_ptr: *mut RexmppXML) { + if node_ptr == ptr::null_mut() { + return; + } + let mut node : RexmppXML = unsafe { *Box::from_raw(node_ptr) }; + unsafe { + match node { + RexmppXML { node_type : NodeType::Text, + alt : RexmppXMLAlt { text: text_ptr }, + next: _} => { + free(text_ptr as *mut c_void); + node.alt.text = ptr::null_mut(); + }, + RexmppXML { node_type : NodeType::Element, + alt : RexmppXMLAlt { elem: element }, + next: _} => { + rexmpp_xml_qname_free(&(element.qname)); + rexmpp_xml_attribute_free_list(element.attributes); + rexmpp_xml_free_list(element.children); + } + } + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_free_list (mut node_ptr: *mut RexmppXML) { + let mut next; + while node_ptr != ptr::null_mut() { + next = unsafe { (*node_ptr).next }; + rexmpp_xml_free(node_ptr); + node_ptr = next; + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_clone (node_ptr: *mut RexmppXML) -> *mut RexmppXML { + if node_ptr == ptr::null_mut() { + return ptr::null_mut(); + } + return Box::into_raw(Box::new(Clone::clone(& unsafe { *node_ptr }))); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_clone_list (mut node_ptr: *mut RexmppXML) -> *mut RexmppXML { + if node_ptr == ptr::null_mut() { + return ptr::null_mut(); + } + let first_ptr = rexmpp_xml_clone(node_ptr); + let mut last_ptr = first_ptr; + node_ptr = unsafe { (*node_ptr).next }; + while node_ptr != ptr::null_mut() { + unsafe { (*last_ptr).next = rexmpp_xml_clone(node_ptr) }; + last_ptr = unsafe { (*last_ptr).next }; + node_ptr = unsafe { (*node_ptr).next }; + } + return first_ptr; +} + + +#[no_mangle] +extern "C" +fn rexmpp_xml_new_text (str: *const c_char) -> *mut RexmppXML { + let node = RexmppXML { + node_type: NodeType::Text, + alt: RexmppXMLAlt { text: unsafe { strdup(str) } }, + next: ptr::null_mut() + }; + let b = Box::new(node); + return Box::into_raw(b); +} + +#[no_mangle] +extern "C" fn rexmpp_xml_add_child (node: *mut RexmppXML, + child: *mut RexmppXML) -> () { + let mut last_ptr : &mut *mut RexmppXML = + unsafe { &mut ((*node).alt.elem.children) }; + while *last_ptr != ptr::null_mut() { + last_ptr = unsafe { &mut ((*(* last_ptr)).next) }; + } + *last_ptr = child; +} + +#[no_mangle] +extern "C" fn rexmpp_xml_add_text (node: *mut RexmppXML, + str: *const c_char) -> c_int { + let text_node : *mut RexmppXML = rexmpp_xml_new_text(str); + if text_node != ptr::null_mut() { + rexmpp_xml_add_child(node, text_node); + return 1; + } + return 0; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_new_elem (name: *const c_char, + namespace: *const c_char) -> *mut RexmppXML { + let node = RexmppXML { + node_type: NodeType::Element, + alt: RexmppXMLAlt { + elem: RexmppXMLAltElem { + qname: RexmppXMLQName { + name: unsafe { strdup(name) }, + namespace: if namespace == ptr::null_mut() { + ptr::null_mut() + } else { + unsafe { strdup(namespace) } + } + }, + attributes: ptr::null_mut(), + children: ptr::null_mut() + } + }, + next: ptr::null_mut() + }; + let b = Box::new(node); + return Box::into_raw(b); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_attr_new (name: *const c_char, + namespace: *const c_char, + value: *const c_char) -> *mut RexmppXMLAttribute { + let node = RexmppXMLAttribute { + qname: RexmppXMLQName { + name: unsafe { strdup(name) }, + namespace: if namespace == ptr::null_mut() { + ptr::null_mut() + } else { + unsafe { strdup(namespace) } + } + }, + value: unsafe { strdup(value) }, + next: ptr::null_mut() + }; + return Box::into_raw(Box::new(node)); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_add_attr_ns (node: *mut RexmppXML, + name: *const c_char, + namespace: *const c_char, + value: *const c_char) -> c_int { + if node == ptr::null_mut() + || unsafe { (*node).node_type } != NodeType::Element { + return -1; + } + let attr = rexmpp_xml_attr_new(name, namespace, value); + unsafe { + (*attr).next = (*node).alt.elem.attributes; + (*node).alt.elem.attributes = attr; + } + return 0; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_remove_attr_ns (node: *mut RexmppXML, + name: *const c_char, + namespace: *const c_char) -> c_int { + if node == ptr::null_mut() + || unsafe { (*node).node_type } != NodeType::Element { + return -1; + } + let mut attr_ptr_ptr: *mut *mut RexmppXMLAttribute = + unsafe { &mut (*node).alt.elem.attributes }; + while unsafe { *attr_ptr_ptr } != ptr::null_mut() { + if rexmpp_xml_attr_match(unsafe { *attr_ptr_ptr }, namespace, name) > 0 { + let next_attr_ptr : *mut RexmppXMLAttribute = + unsafe { (**attr_ptr_ptr).next }; + rexmpp_xml_attribute_free(unsafe { *attr_ptr_ptr }); + unsafe { *attr_ptr_ptr = next_attr_ptr } + return 0; + } + attr_ptr_ptr = unsafe { &mut (**attr_ptr_ptr).next }; + } + return 1; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_add_attr (node: *mut RexmppXML, + name: *const c_char, + value: *const c_char) -> c_int { + rexmpp_xml_add_attr_ns(node, name, ptr::null_mut(), value) +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_remove_attr (node: *mut RexmppXML, + name: *const c_char) -> c_int { + rexmpp_xml_remove_attr_ns(node, name, ptr::null_mut()) +} + + +#[no_mangle] +extern "C" +fn rexmpp_xml_siblings_count (mut node: *const RexmppXML) -> c_uint { + let mut i : c_uint = 0; + while node != ptr::null() { + node = unsafe { (*node).next }; + i = i + 1; + } + return i; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_match (node_ptr: *const RexmppXML, + namespace: *const c_char, + name: *const c_char) -> c_int { + if node_ptr == ptr::null_mut() { + return 0; + } + let node : RexmppXML = unsafe { *node_ptr }; + if node.node_type != NodeType::Element { + return 0; + } + if name != ptr::null_mut() { + let name_cstr : &CStr = unsafe { CStr::from_ptr(name) }; + let elem_name_cstr : &CStr = unsafe { CStr::from_ptr(node.alt.elem.qname.name) }; + if name_cstr != elem_name_cstr { + return 0; + } + } + if namespace != ptr::null_mut() { + let namespace_cstr : &CStr = unsafe { CStr::from_ptr(namespace) }; + if unsafe { node.alt.elem.qname.namespace } == ptr::null_mut() { + match CStr::to_str(namespace_cstr) { + Ok(namespace_str) => if namespace_str == "jabber:client" { + return 1; + }, + Err(_) => return 0 + } + return 0; + } + let elem_namespace_cstr : &CStr = + unsafe { CStr::from_ptr(node.alt.elem.qname.namespace) }; + if namespace_cstr != elem_namespace_cstr { + return 0; + } + } + return 1; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_attr_match (attr: *const RexmppXMLAttribute, + namespace: *const c_char, + name: *const c_char) -> c_int { + if attr == ptr::null() { + return 0; + } + if name != ptr::null() { + let name_cstr : &CStr = unsafe { CStr::from_ptr(name) }; + let attr_name_cstr : &CStr = unsafe { CStr::from_ptr((*attr).qname.name) }; + if name_cstr != attr_name_cstr { + return 0; + } + } + if namespace != ptr::null() { + let namespace_cstr : &CStr = unsafe { CStr::from_ptr(namespace) }; + if unsafe { (*attr).qname.namespace } == ptr::null_mut() { + match CStr::to_str(namespace_cstr) { + Ok(namespace_str) => if namespace_str != "jabber:client" { + return 0; + }, + Err(_) => return 0 + } + } else { + let attr_namespace_cstr : &CStr = + unsafe { CStr::from_ptr((*attr).qname.namespace) }; + if namespace_cstr != attr_namespace_cstr { + return 0; + } + } + } + return 1; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_is_stanza (node: *const RexmppXML) -> c_int { + if rexmpp_xml_match(node, + CString::new("jabber:client").expect("CString::new failed").as_ptr(), + CString::new("message").expect("CString::new failed").as_ptr()) == 1 + || rexmpp_xml_match(node, + CString::new("jabber:client").expect("CString::new failed").as_ptr(), + CString::new("iq").expect("CString::new failed").as_ptr()) == 1 + || rexmpp_xml_match(node, + CString::new("jabber:client").expect("CString::new failed").as_ptr(), + CString::new("presence").expect("CString::new failed").as_ptr()) == 1 + { + return 1; + } + return 0; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_error (error_type: *const c_char, condition: *const c_char) + -> *mut RexmppXML { + let error : *mut RexmppXML = + rexmpp_xml_new_elem(CString::new("error") + .expect("CString::new failed") + .as_ptr(), + ptr::null_mut()); + rexmpp_xml_add_attr(error, + CString::new("type") + .expect("CString::new failed") + .as_ptr(), + error_type); + let cond = + rexmpp_xml_new_elem(condition, + CString::new("urn:ietf:params:xml:ns:xmpp-stanzas") + .expect("CString::new failed") + .as_ptr()); + rexmpp_xml_add_child(error, cond); + return error; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_find_attr (node_ptr: *mut RexmppXML, + name: *const c_char, + namespace: *const c_char) + -> *mut RexmppXMLAttribute { + if node_ptr == ptr::null_mut() { + return ptr::null_mut(); + } + let node : RexmppXML = unsafe { *node_ptr }; + if node.node_type != NodeType::Element { + return ptr::null_mut(); + } + let mut attr_ptr : *mut RexmppXMLAttribute = + unsafe { node.alt.elem.attributes }; + while attr_ptr != ptr::null_mut() { + if rexmpp_xml_attr_match(attr_ptr, namespace, name) > 0 { + return attr_ptr; + } + unsafe { attr_ptr = (*attr_ptr).next }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_find_attr_val_ns (node: *mut RexmppXML, + name: *const c_char, + namespace: *const c_char) + -> *const c_char { + let attr : *mut RexmppXMLAttribute = + rexmpp_xml_find_attr(node, name, namespace); + if attr != ptr::null_mut() { + return unsafe { (*attr).value }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_find_attr_val (node: *mut RexmppXML, + name: *const c_char) + -> *const c_char { + rexmpp_xml_find_attr_val_ns(node, name, ptr::null_mut()) +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_find_child (node_ptr: *mut RexmppXML, + namespace: *const c_char, + name: *const c_char) + -> *mut RexmppXML { + if node_ptr == ptr::null_mut() { + return ptr::null_mut(); + } + let node : RexmppXML = unsafe { *node_ptr }; + if node.node_type != NodeType::Element { + return ptr::null_mut(); + } + let mut child: *mut RexmppXML = unsafe { node.alt.elem.children }; + while child != ptr::null_mut() { + if rexmpp_xml_match(child, namespace, name) > 0 { + return child; + } + unsafe { child = (*child).next }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_children (node: *mut RexmppXML) + -> *mut RexmppXML { + if node != ptr::null_mut() + && unsafe { (*node).node_type } == NodeType::Element { + return unsafe { (*node).alt.elem.children }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_first_elem_child (node: *mut RexmppXML) + -> *mut RexmppXML { + let mut child: *mut RexmppXML = rexmpp_xml_children(node); + while child != ptr::null_mut() { + if unsafe { (*child).node_type == NodeType::Element } { + return child; + } + unsafe { child = (*child).next }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_next_elem_sibling (node: *mut RexmppXML) + -> *mut RexmppXML { + if node == ptr::null_mut() { + return ptr::null_mut(); + } + let mut sibling: *mut RexmppXML = unsafe { (*node).next }; + while sibling != ptr::null_mut() { + if unsafe { (*sibling).node_type == NodeType::Element } { + return sibling; + } + unsafe { sibling = (*sibling).next }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_text (node: *mut RexmppXML) + -> *mut c_char { + if node != ptr::null_mut() + && unsafe { (*node).node_type == NodeType::Text } { + return unsafe { (*node).alt.text }; + } + return ptr::null_mut(); +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_text_child (node: *mut RexmppXML) + -> *mut c_char { + rexmpp_xml_text(rexmpp_xml_children(node)) +} -- cgit v1.2.3