summaryrefslogtreecommitdiff
path: root/src/rexmpp_xml.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp_xml.rs')
-rw-r--r--src/rexmpp_xml.rs1040
1 files changed, 1040 insertions, 0 deletions
diff --git a/src/rexmpp_xml.rs b/src/rexmpp_xml.rs
new file mode 100644
index 0000000..f0d292a
--- /dev/null
+++ b/src/rexmpp_xml.rs
@@ -0,0 +1,1040 @@
+extern crate libc;
+use libc::{strdup, strndup, free, strcmp};
+use std::os::raw::{c_char, c_int, c_void, c_uint};
+use std::ptr;
+use std::ffi::{CStr, CString};
+use std::clone::Clone;
+use std::fs::File;
+use std::io::Write;
+
+use super::{rexmpp};
+use super::{rexmpp_random};
+
+// extern {
+// fn rexmpp_xml_parse (str: *mut c_char, str_len: c_int) -> *mut RexmppXML;
+// }
+
+#[repr(C)]
+pub struct RexmppXMLQName {
+ pub name: *mut c_char,
+ pub 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 {
+ pub qname: RexmppXMLQName,
+ pub value: *mut c_char,
+ pub 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)]
+pub enum NodeType {
+ Element,
+ Text
+}
+
+#[repr(C)]
+pub struct RexmppXMLAltElem {
+ pub qname: RexmppXMLQName,
+ pub attributes: *mut RexmppXMLAttribute,
+ pub children: *mut RexmppXML
+}
+
+impl Copy for RexmppXMLAltElem { }
+
+impl Clone for RexmppXMLAltElem {
+ fn clone(&self) -> RexmppXMLAltElem {
+ unsafe {
+ 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;
+ loop {
+ match old_attr_ptr.as_mut() {
+ None => break,
+ Some(old_attr) => {
+ let new_attr_ptr = rexmpp_xml_attr_new(old_attr.qname.name,
+ old_attr.qname.namespace,
+ old_attr.value);
+ next_attr_ptr_ptr.write(new_attr_ptr);
+ next_attr_ptr_ptr = &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)]
+pub enum RexmppXMLAlt {
+ Elem(RexmppXMLAltElem),
+ Text(*mut c_char)
+}
+
+#[repr(C)]
+pub struct RexmppXML {
+ pub alt: RexmppXMLAlt,
+ pub next: *mut RexmppXML
+}
+
+impl Copy for RexmppXML { }
+
+impl Clone for RexmppXML {
+ fn clone(&self) -> RexmppXML {
+ RexmppXML {
+ alt: match self.alt {
+ RexmppXMLAlt::Text(text) =>
+ RexmppXMLAlt::Text(unsafe { strdup(text) }),
+ RexmppXMLAlt::Elem(e) =>
+ RexmppXMLAlt::Elem(Clone::clone(& e))
+ },
+ next: ptr::null_mut()
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_qname_free (qname_ptr: *mut RexmppXMLQName) {
+ match unsafe { qname_ptr.as_mut() } {
+ None => return,
+ Some(qname) => {
+ 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]
+pub 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(&mut (attr.qname));
+ if attr.value != ptr::null_mut() {
+ unsafe { free(attr.value as *mut c_void) }
+ attr.value = ptr::null_mut();
+ }
+}
+
+#[no_mangle]
+pub 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]
+pub 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.alt {
+ RexmppXMLAlt::Text(mut t) => {
+ free(t as *mut c_void);
+ t = ptr::null_mut();
+ },
+ RexmppXMLAlt::Elem(mut element) => {
+ rexmpp_xml_qname_free(&mut (element.qname));
+ rexmpp_xml_attribute_free_list(element.attributes);
+ rexmpp_xml_free_list(element.children);
+ }
+ }
+ }
+}
+
+#[no_mangle]
+pub 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]
+pub 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]
+pub 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]
+pub extern "C"
+fn rexmpp_xml_new_text (str: *const c_char) -> *mut RexmppXML {
+ let node = RexmppXML {
+ alt: RexmppXMLAlt::Text( unsafe { strdup(str) } ),
+ next: ptr::null_mut()
+ };
+ let b = Box::new(node);
+ return Box::into_raw(b);
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_new_text_len (str: *const c_char, len: usize) -> *mut RexmppXML {
+ let node = RexmppXML {
+ alt: RexmppXMLAlt::Text( unsafe { strndup(str, len) } ),
+ next: ptr::null_mut()
+ };
+ let b = Box::new(node);
+ return Box::into_raw(b);
+}
+
+#[no_mangle]
+pub extern "C" fn rexmpp_xml_add_child (node: *mut RexmppXML,
+ child: *mut RexmppXML) -> () {
+ // It is important to wrap everything in "unsafe" here; somehow
+ // the enum fields are not mutated otherwise.
+ unsafe {
+ match (*node).alt {
+ RexmppXMLAlt::Elem(ref mut elem) => {
+ let mut last_ptr : &mut *mut RexmppXML =
+ &mut ((*elem).children);
+ while *last_ptr != ptr::null_mut() {
+ last_ptr = &mut ((*(* last_ptr)).next);
+ }
+ *last_ptr = child;
+ },
+ _ => ()
+ }
+ }
+}
+
+#[no_mangle]
+pub 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]
+pub extern "C" fn rexmpp_xml_add_text_len (node: *mut RexmppXML,
+ str: *const c_char,
+ len: usize) -> c_int {
+ let text_node : *mut RexmppXML = rexmpp_xml_new_text_len(str, len);
+ if text_node != ptr::null_mut() {
+ rexmpp_xml_add_child(node, text_node);
+ return 1;
+ }
+ return 0;
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_new_elem (name: *const c_char,
+ namespace: *const c_char) -> *mut RexmppXML {
+ let node = RexmppXML {
+ 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]
+pub 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]
+pub 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() {
+ return -1;
+ }
+ // Wrapping everything into "unsafe", otherwise enum fields are
+ // not mutated.
+ unsafe {
+ match(*node).alt {
+ RexmppXMLAlt::Elem(ref mut elem) => {
+ let attr = rexmpp_xml_attr_new(name, namespace, value);
+ (*attr).next = (*elem).attributes;
+ (*elem).attributes = attr;
+ 0
+ },
+ _ => -1
+ }
+ }
+}
+
+#[no_mangle]
+pub 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() {
+ return -1;
+ }
+ // Wrapping everything into "unsafe", otherwise enum fields are
+ // not mutated.
+ unsafe {
+ match (*node).alt {
+ RexmppXMLAlt::Elem(ref mut elem) => {
+ let mut attr_ptr_ptr: *mut *mut RexmppXMLAttribute =
+ &mut (*elem).attributes;
+ while *attr_ptr_ptr != ptr::null_mut() {
+ if rexmpp_xml_attr_match(*attr_ptr_ptr,
+ namespace, name) > 0 {
+ let next_attr_ptr : *mut RexmppXMLAttribute =
+ (**attr_ptr_ptr).next;
+ rexmpp_xml_attribute_free(*attr_ptr_ptr);
+ *attr_ptr_ptr = next_attr_ptr;
+ return 0;
+ }
+ attr_ptr_ptr = &mut (**attr_ptr_ptr).next;
+ }
+ 1
+ },
+ _ => -1,
+ }
+ }
+}
+
+#[no_mangle]
+pub 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]
+pub 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())
+}
+
+
+fn rexmpp_xml_push_escaped (c: char, s: &mut String) {
+ if c == '<' {
+ s.push_str("&lt;")
+ } else if c == '>' {
+ s.push_str("&gt;")
+ } else if c == '&' {
+ s.push_str("&amp;")
+ } else if c == '\'' {
+ s.push_str("&apos;")
+ } else if c == '"' {
+ s.push_str("&quot;")
+ } else {
+ s.push_str(format!("&#{};", u32::from(c)).as_str());
+ };
+}
+
+fn rexmpp_xml_print_text (c: char, s: &mut String) {
+ if "<&>'\"".chars().any(|sc| sc == c) {
+ rexmpp_xml_push_escaped(c, s);
+ } else {
+ s.push(c);
+ }
+}
+
+fn rexmpp_xml_print_name (i: usize, c: char, s: &mut String) {
+ if c == ':'
+ || (c >= 'A' && c <= 'Z')
+ || c == '_'
+ || (c >= 'a' && c <= 'z')
+ || (c >= '\u{C0}' && c <= '\u{D6}')
+ || (c >= '\u{D8}' && c <= '\u{F6}')
+ || (c >= '\u{F8}' && c <= '\u{2FF}')
+ || (c >= '\u{370}' && c <= '\u{37D}')
+ || (c >= '\u{37F}' && c <= '\u{1FFF}')
+ || (c >= '\u{200C}' && c <= '\u{200D}')
+ || (c >= '\u{2070}' && c <= '\u{218F}')
+ || (c >= '\u{2C00}' && c <= '\u{2FEF}')
+ || (c >= '\u{3001}' && c <= '\u{D7FF}')
+ || (c >= '\u{F900}' && c <= '\u{FDCF}')
+ || (c >= '\u{FDF0}' && c <= '\u{FFF0}')
+ || (c >= '\u{10000}' && c <= '\u{EFFFF}')
+ || ((i > 0) &&
+ (c == '-'
+ || c == '.'
+ || (c >= '0' && c <= '9')
+ || c == '\u{B7}'
+ || (c >= '\u{0300}' && c <= '\u{036F}')
+ || (c >= '\u{203F}' && c <= '\u{2040}')))
+ {
+ // Print the allowed characters.
+ s.push(c);
+ }
+}
+
+fn rexmpp_xml_print_indent (indent: i32, s: &mut String) {
+ let mut i = 0;
+ while i < indent {
+ s.push_str(" ");
+ i = i + 1;
+ }
+}
+
+fn rexmpp_xml_print (node_ptr: *const RexmppXML,
+ ret: &mut String,
+ indent: i32)
+ -> ()
+{
+ unsafe {
+ let node : RexmppXML = *node_ptr;
+ match node {
+ RexmppXML { alt : RexmppXMLAlt::Text (text_ptr),
+ next: _} => {
+ let text_cstr : &CStr = CStr::from_ptr(text_ptr);
+ let text_str : String =
+ String::from_utf8_lossy(text_cstr.to_bytes())
+ .to_string();
+ // let mut escaped = String::with_capacity(text_str.capacity());
+ text_str.chars().
+ for_each(|c| rexmpp_xml_print_text(c, ret));
+ },
+ RexmppXML { alt : RexmppXMLAlt::Elem (element),
+ next: _} => {
+ // let mut ret = String::with_capacity(1024);
+ let name_cstr : &CStr =
+ CStr::from_ptr(element.qname.name);
+ let name_str : String =
+ String::from_utf8_lossy(name_cstr.to_bytes())
+ .to_string();
+ if indent > 0 {
+ ret.push('\n');
+ rexmpp_xml_print_indent(indent, ret);
+ }
+ ret.push('<');
+ name_str.char_indices().
+ for_each(|(i, c)| rexmpp_xml_print_name(i, c, ret));
+ if element.qname.namespace != ptr::null_mut() {
+ let namespace_cstr : &CStr =
+ CStr::from_ptr(element.qname.namespace);
+ let namespace_str : String =
+ String::from_utf8_lossy(namespace_cstr.to_bytes())
+ .to_string();
+ ret.push_str(" xmlns=\"");
+ namespace_str.chars().
+ for_each(|c| rexmpp_xml_print_text(c, ret));
+ ret.push('"');
+ }
+ if element.attributes != ptr::null_mut() {
+ let mut attr_ptr : *mut RexmppXMLAttribute =
+ element.attributes;
+ while attr_ptr != ptr::null_mut() {
+ let attr : RexmppXMLAttribute = *attr_ptr;
+ let attr_name_cstr =
+ CStr::from_ptr(attr.qname.name);
+ let attr_name_str =
+ String::from_utf8_lossy(attr_name_cstr.to_bytes())
+ .to_string();
+ // TODO: handle attribute namespaces someday.
+ let attr_value_cstr =
+ CStr::from_ptr(attr.value);
+ let attr_value_str =
+ String::from_utf8_lossy(attr_value_cstr.to_bytes())
+ .to_string();
+ ret.push(' ');
+ attr_name_str.char_indices().
+ for_each(|(i, c)|
+ rexmpp_xml_print_name(i, c, ret));
+ ret.push_str("=\"");
+ attr_value_str.chars().
+ for_each(|c| rexmpp_xml_print_text(c, ret));
+ ret.push('"');
+ attr_ptr = (*attr_ptr).next;
+ }
+ }
+ if element.children == ptr::null_mut() {
+ ret.push_str("/>");
+ } else {
+ ret.push('>');
+ let mut child = rexmpp_xml_children(node_ptr);
+ let mut last_child_is_textual = false;
+ while child != ptr::null_mut() {
+ rexmpp_xml_print(child, ret,
+ if indent > -1 { indent + 1 }
+ else { -1 } );
+ last_child_is_textual =
+ matches!((*child).alt, RexmppXMLAlt::Text(_));
+ child = (*child).next;
+ }
+ if indent > 0 && ! last_child_is_textual {
+ ret.push('\n');
+ rexmpp_xml_print_indent(indent, ret);
+ }
+ ret.push_str("</");
+ name_str.char_indices().
+ for_each(|(i, c)|
+ rexmpp_xml_print_name(i, c, ret));
+ ret.push('>');
+ }
+ }
+ }
+ }
+}
+
+fn rexmpp_xml_serialize_str (node_ptr: *const RexmppXML,
+ pretty: bool)
+ -> String
+{
+ let mut out = String::with_capacity(4096);
+ rexmpp_xml_print(node_ptr, &mut out, if pretty { 0 } else { -1 });
+ return out;
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_serialize (node_ptr: *const RexmppXML,
+ pretty: bool)
+ -> *mut c_char
+{
+ let out = rexmpp_xml_serialize_str(node_ptr, pretty);
+ match CString::new(out) {
+ Ok(cstr) => unsafe { strdup(cstr.as_ptr()) },
+ Err(_) => ptr::null_mut()
+ }
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_add_id (node: *mut RexmppXML)
+ -> *mut RexmppXML
+{
+ match CString::new("id") {
+ Err(_) => return ptr::null_mut(),
+ Ok(id_cstr) => {
+ let buf = unsafe { rexmpp_random::rexmpp_random_id() };
+ if buf == ptr::null_mut() {
+ return ptr::null_mut();
+ }
+ rexmpp_xml_add_attr(node, id_cstr.as_ptr(), buf);
+ unsafe { free(buf as *mut c_void) };
+ return node;
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_write_file (path: *const c_char,
+ node: *const RexmppXML)
+ -> c_int
+{
+ let path_cstr : &CStr = unsafe { CStr::from_ptr(path) };
+ let path_str : String =
+ String::from_utf8_lossy(path_cstr.to_bytes())
+ .to_string();
+ match File::create(path_str) {
+ Ok(mut fd) => {
+ fd.write_all(b"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ fd.write_all(rexmpp_xml_serialize_str(node, false).as_bytes());
+ },
+ Err(_) => { return -1; }
+ }
+ return 0;
+}
+
+#[no_mangle]
+pub 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]
+pub extern "C"
+fn rexmpp_xml_match (node: *const RexmppXML,
+ namespace: *const c_char,
+ name: *const c_char) -> c_int {
+ if node == ptr::null_mut() {
+ return 0;
+ }
+ match unsafe { (*node).alt } {
+ RexmppXMLAlt::Text(_) => return 0,
+ RexmppXMLAlt::Elem(elem) => {
+ if name != ptr::null_mut() {
+ let name_cstr : &CStr = unsafe { CStr::from_ptr(name) };
+ let elem_name_cstr : &CStr =
+ unsafe { CStr::from_ptr(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 { 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(elem.qname.namespace) };
+ if namespace_cstr != elem_namespace_cstr {
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+#[no_mangle]
+pub 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]
+pub 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]
+pub 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]
+pub extern "C"
+fn rexmpp_xml_find_attr (node: *mut RexmppXML,
+ name: *const c_char,
+ namespace: *const c_char)
+ -> *mut RexmppXMLAttribute {
+ if node == ptr::null_mut() {
+ return ptr::null_mut();
+ }
+ match unsafe { (*node).alt } {
+ RexmppXMLAlt::Elem(elem) => {
+ let mut attr_ptr : *mut RexmppXMLAttribute =
+ unsafe { 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();
+ },
+ _ => return ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub 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]
+pub 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]
+pub extern "C"
+fn rexmpp_xml_find_child (node: *mut RexmppXML,
+ namespace: *const c_char,
+ name: *const c_char)
+ -> *mut RexmppXML {
+ if node == ptr::null_mut() {
+ return ptr::null_mut();
+ }
+ match unsafe { (*node).alt } {
+ RexmppXMLAlt::Elem(elem) => {
+ let mut child: *mut RexmppXML = unsafe { elem.children };
+ while child != ptr::null_mut() {
+ if rexmpp_xml_match(child, namespace, name) > 0 {
+ return child;
+ }
+ unsafe { child = (*child).next };
+ }
+ ptr::null_mut()
+ },
+ _ => ptr::null_mut()
+ }
+}
+
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_eq (n1: *const RexmppXML, n2: *const RexmppXML) -> bool {
+ if n1 == n2 {
+ return true;
+ }
+ if n1 == ptr::null_mut() || n1 == ptr::null_mut() {
+ return false;
+ }
+ unsafe {
+ match (*n1, *n2) {
+ (RexmppXML { alt : RexmppXMLAlt::Text (text1),
+ next: _ },
+ RexmppXML { alt : RexmppXMLAlt::Text (text2),
+ next: _ }
+ ) => strcmp(text1, text2) == 0,
+ (RexmppXML
+ { alt : RexmppXMLAlt::Elem
+ ( RexmppXMLAltElem {
+ qname: RexmppXMLQName {
+ name: name1,
+ namespace: namespace1
+ },
+ attributes: attributes1,
+ children: children1
+ } ),
+ next: _},
+ RexmppXML
+ { alt : RexmppXMLAlt::Elem
+ ( RexmppXMLAltElem {
+ qname: RexmppXMLQName {
+ name: name2,
+ namespace: namespace2
+ },
+ attributes: attributes2,
+ children: children2
+ } ),
+ next: _}
+ ) => {
+ // Compare names
+ if strcmp(name1, name2) != 0
+ { return false; }
+ // Compare namespaces
+ if namespace1 != namespace2 &&
+ (namespace1 == ptr::null_mut() ||
+ namespace2 == ptr::null_mut() ||
+ strcmp(namespace1, namespace2) != 0)
+ { return false; }
+ // Compare attributes
+ let mut attr1 = attributes1;
+ let mut attr2 = attributes2;
+ while ! (attr1 == ptr::null_mut() && attr2 == ptr::null_mut()) {
+ if attr1 == ptr::null_mut() {
+ return false;
+ }
+ if attr2 == ptr::null_mut() {
+ return false;
+ }
+ if strcmp((*attr1).qname.name, (*attr2).qname.name) != 0 {
+ return false;
+ }
+ if strcmp((*attr1).value, (*attr2).value) != 0 {
+ return false;
+ }
+ attr1 = (*attr1).next;
+ attr2 = (*attr2).next;
+ }
+ // Compare children
+ let mut child1 = children1;
+ let mut child2 = children2;
+ while ! (child1 == ptr::null_mut() && child2 == ptr::null_mut())
+ {
+ if child1 == ptr::null_mut() {
+ return false;
+ }
+ if child2 == ptr::null_mut() {
+ return false;
+ }
+ if ! rexmpp_xml_eq(child1, child2) {
+ return false;
+ }
+ child1 = (*child1).next;
+ child2 = (*child2).next;
+ }
+ true
+ }
+ _ => false
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_children (node: *const RexmppXML)
+ -> *mut RexmppXML {
+ if node == ptr::null_mut() {
+ return ptr::null_mut();
+ }
+ match unsafe { (*node).alt } {
+ RexmppXMLAlt::Elem(elem) => elem.children,
+ _ => ptr::null_mut()
+ }
+}
+
+#[no_mangle]
+pub 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 matches!(unsafe { (*child).alt }, RexmppXMLAlt::Elem(_)) {
+ return child;
+ }
+ unsafe { child = (*child).next };
+ }
+ return ptr::null_mut();
+}
+
+#[no_mangle]
+pub 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 matches!(unsafe { (*sibling).alt }, RexmppXMLAlt::Elem(_)) {
+ return sibling;
+ }
+ unsafe { sibling = (*sibling).next };
+ }
+ return ptr::null_mut();
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_text (node: *mut RexmppXML)
+ -> *mut c_char {
+ if node == ptr::null_mut() {
+ return ptr::null_mut();
+ }
+ match unsafe { (*node).alt } {
+ RexmppXMLAlt::Text(text) => text,
+ _ => ptr::null_mut()
+ }
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_text_child (node: *mut RexmppXML)
+ -> *mut c_char {
+ rexmpp_xml_text(rexmpp_xml_children(node))
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_reverse_list (mut node: *mut RexmppXML)
+ -> *mut RexmppXML {
+ let mut next;
+ let mut prev = ptr::null_mut();
+ while node != ptr::null_mut() {
+ unsafe {
+ next = (*node).next;
+ (*node).next = prev;
+ prev = node;
+ node = next;
+ }
+ }
+ return prev;
+}
+
+#[no_mangle]
+pub extern "C"
+fn rexmpp_xml_reverse_children (node: *mut RexmppXML)
+ -> *mut RexmppXML {
+ unsafe {
+ if node == ptr::null_mut() {
+ return node;
+ }
+ match (*node).alt {
+ RexmppXMLAlt::Elem(ref mut elem) => {
+ (*elem).children = rexmpp_xml_reverse_list((*elem).children);
+ let mut cur = node;
+ while cur != ptr::null_mut() {
+ match (*cur).alt {
+ RexmppXMLAlt::Elem(ref mut cur_elem) => {
+ (*cur_elem).children =
+ rexmpp_xml_reverse_children((*cur_elem).children);
+ },
+ _ => ()
+ }
+ cur = (*cur).next;
+ }
+ },
+ _ => ()
+ }
+ }
+ return node;
+}