summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-09-07 19:31:05 +0300
committerdefanor <defanor@uberspace.net>2023-09-07 19:31:05 +0300
commit55db67a6abebeda001feccbbf2b7615d19cb93e5 (patch)
tree28b4693efc5e47288a11ed5ee610b8cd28e40e0d
parente3d8e7d63bb3e1ccd38ce5ca8ca9c94f995612d6 (diff)
Implement rexmpp_xml_eq in Rust
-rw-r--r--src/rexmpp.rs4
-rw-r--r--src/rexmpp_xml.c4
-rw-r--r--src/rexmpp_xml.rs118
3 files changed, 122 insertions, 4 deletions
diff --git a/src/rexmpp.rs b/src/rexmpp.rs
index b8057ba..2959ec3 100644
--- a/src/rexmpp.rs
+++ b/src/rexmpp.rs
@@ -89,6 +89,10 @@ pub enum TLSPolicy {
Avoid
}
+extern {
+ pub fn rexmpp_gen_id (s: *mut Rexmpp) -> *mut c_char;
+}
+
type IQCallback = unsafe extern "C"
fn (s: *mut Rexmpp, cb_data: *mut c_void,
request: *mut rexmpp_xml::RexmppXML, response: *mut rexmpp_xml::RexmppXML,
diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c
index e77bf78..862a783 100644
--- a/src/rexmpp_xml.c
+++ b/src/rexmpp_xml.c
@@ -575,7 +575,6 @@ char *rexmpp_xml_serialize (const rexmpp_xml_t *node, int pretty) {
s = rexmpp_str_putc(s, &s_len, '\0');
return s;
}
-#endif
rexmpp_xml_t *
rexmpp_xml_add_id (rexmpp_t *s,
@@ -589,6 +588,7 @@ rexmpp_xml_add_id (rexmpp_t *s,
free(buf);
return node;
}
+#endif
xmlNodePtr rexmpp_xml_parse_libxml2 (const char *str, int str_len) {
xmlNodePtr elem = NULL;
@@ -753,7 +753,6 @@ 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
@@ -766,7 +765,6 @@ int rexmpp_xml_eq (rexmpp_xml_t *n1, rexmpp_xml_t *n2) {
return eq;
}
-#ifndef USE_RUST
rexmpp_xml_t *rexmpp_xml_children (const rexmpp_xml_t *node) {
if (node != NULL && node->type == REXMPP_XML_ELEMENT) {
return node->alt.elem.children;
diff --git a/src/rexmpp_xml.rs b/src/rexmpp_xml.rs
index 622a28a..1f9f4d6 100644
--- a/src/rexmpp_xml.rs
+++ b/src/rexmpp_xml.rs
@@ -1,5 +1,5 @@
extern crate libc;
-use libc::{strdup, strndup, free};
+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};
@@ -7,6 +7,7 @@ use std::clone::Clone;
use std::fs::File;
use std::io::Write;
+use super::{rexmpp};
// extern {
// fn rexmpp_xml_parse (str: *mut c_char, str_len: c_int) -> *mut RexmppXML;
@@ -584,6 +585,25 @@ fn rexmpp_xml_serialize (node_ptr: *const RexmppXML,
#[no_mangle]
extern "C"
+fn rexmpp_xml_add_id (s: *mut rexmpp::Rexmpp, node: *mut RexmppXML)
+ -> *mut RexmppXML
+{
+ match CString::new("id") {
+ Err(_) => return ptr::null_mut(),
+ Ok(id_cstr) => {
+ let buf = unsafe { rexmpp::rexmpp_gen_id(s) };
+ 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]
+extern "C"
fn rexmpp_xml_write_file (path: *const c_char,
node: *const RexmppXML)
-> c_int
@@ -797,6 +817,102 @@ fn rexmpp_xml_find_child (node_ptr: *mut RexmppXML,
return ptr::null_mut();
}
+
+#[no_mangle]
+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 { node_type : NodeType::Text,
+ alt : RexmppXMLAlt { text: text1 },
+ next: next1 },
+ RexmppXML { node_type : NodeType::Text,
+ alt : RexmppXMLAlt { text: text2 },
+ next: next2 }
+ ) => strcmp(text1, text2) == 0,
+ (RexmppXML
+ { node_type : NodeType::Element,
+ alt : RexmppXMLAlt
+ { elem: RexmppXMLAltElem {
+ qname: RexmppXMLQName {
+ name: name1,
+ namespace: namespace1
+ },
+ attributes: attributes1,
+ children: children1
+ } },
+ next: _},
+ RexmppXML
+ { node_type : NodeType::Element,
+ 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]
extern "C"
fn rexmpp_xml_children (node: *const RexmppXML)