summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-09-07 14:32:41 +0300
committerdefanor <defanor@uberspace.net>2023-09-07 18:03:30 +0300
commite3d8e7d63bb3e1ccd38ce5ca8ca9c94f995612d6 (patch)
treeda034f90f6365edaf15c87cd7996fa339ffeded5
parent1e01dbfc114e4ff96c428d1db38a4908ba8d0438 (diff)
Build rexmpp_xml_t directly on SAX parsing
Afterwards it is used for the input queue, too.
-rw-r--r--src/rexmpp.c44
-rw-r--r--src/rexmpp.h12
-rw-r--r--src/rexmpp.rs12
-rw-r--r--src/rexmpp_xml.c43
-rw-r--r--src/rexmpp_xml.h16
-rw-r--r--src/rexmpp_xml.rs26
6 files changed, 128 insertions, 25 deletions
diff --git a/src/rexmpp.c b/src/rexmpp.c
index 77413f1..bdbfb94 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -725,12 +725,12 @@ void rexmpp_cleanup (rexmpp_t *s) {
s->send_queue = NULL;
}
if (s->current_element_root != NULL) {
- xmlFreeNode(s->current_element_root);
+ rexmpp_xml_free_list(s->current_element_root);
s->current_element_root = NULL;
s->current_element = NULL;
}
if (s->input_queue != NULL) {
- xmlFreeNodeList(s->input_queue);
+ rexmpp_xml_free_list(s->input_queue);
s->input_queue = NULL;
s->input_queue_last = NULL;
}
@@ -1240,7 +1240,7 @@ rexmpp_err_t rexmpp_recv (rexmpp_t *s) {
}
chunk = NULL;
- xmlNodePtr elem;
+ rexmpp_xml_t *elem;
for (elem = s->input_queue;
/* Skipping everything after an error. Might be better to
process it anyway, but it could lead to more errors if
@@ -1248,16 +1248,14 @@ rexmpp_err_t rexmpp_recv (rexmpp_t *s) {
elem != NULL && (err == REXMPP_SUCCESS || err == REXMPP_E_AGAIN);
elem = elem->next)
{
- rexmpp_xml_t *elem_tmp = rexmpp_xml_from_libxml2(elem);
- if (s->xml_in_cb != NULL && s->xml_in_cb(s, elem_tmp) != 0) {
+ if (s->xml_in_cb != NULL && s->xml_in_cb(s, elem) != 0) {
rexmpp_log(s, LOG_WARNING,
"Message processing was cancelled by xml_in_cb.");
} else {
- err = rexmpp_process_element(s, elem_tmp);
+ err = rexmpp_process_element(s, elem);
}
- rexmpp_xml_free(elem_tmp);
}
- xmlFreeNodeList(s->input_queue);
+ rexmpp_xml_free_list(s->input_queue);
s->input_queue = NULL;
s->input_queue_last = NULL;
if (err != REXMPP_SUCCESS && err != REXMPP_E_AGAIN) {
@@ -2226,7 +2224,11 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, rexmpp_xml_t *elem) {
void rexmpp_sax_characters (rexmpp_t *s, const char *ch, int len)
{
if (s->current_element != NULL) {
- xmlNodeAddContentLen(s->current_element, ch, len);
+ rexmpp_xml_t *text_node = rexmpp_xml_new_text_len(ch, len);
+ if (text_node != NULL) {
+ text_node->next = s->current_element->alt.elem.children;
+ s->current_element->alt.elem.children = text_node;
+ }
}
}
@@ -2244,6 +2246,7 @@ void rexmpp_sax_start_elem_ns (rexmpp_t *s,
(void)nb_namespaces;
(void)namespaces;
(void)nb_defaulted;
+ (void)prefix;
int i;
if (s->stream_state == REXMPP_STREAM_OPENING &&
@@ -2256,21 +2259,22 @@ void rexmpp_sax_start_elem_ns (rexmpp_t *s,
if (s->stream_state != REXMPP_STREAM_OPENING) {
if (s->current_element == NULL) {
- s->current_element = xmlNewNode(NULL, localname);
+ s->current_element = rexmpp_xml_new_elem(localname, URI);
s->current_element_root = s->current_element;
} else {
- xmlNodePtr node = xmlNewNode(NULL, localname);
- xmlAddChild(s->current_element, node);
+ rexmpp_xml_t *node = rexmpp_xml_new_elem(localname, URI);
+ node->next = s->current_element->alt.elem.children;
+ s->current_element->alt.elem.children = node;
s->current_element = node;
}
- xmlNsPtr ns = xmlNewNs(s->current_element, URI, prefix);
- s->current_element->ns = ns;
for (i = 0; i < nb_attributes; i++) {
size_t attr_len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
char *attr_val = malloc(attr_len + 1);
attr_val[attr_len] = '\0';
strncpy(attr_val, attributes[i * 5 + 3], attr_len);
- xmlNewProp(s->current_element, attributes[i * 5], attr_val);
+ rexmpp_xml_add_attr_ns(s->current_element,
+ attributes[i * 5],
+ NULL, attr_val);
free(attr_val);
}
}
@@ -2305,8 +2309,16 @@ void rexmpp_sax_end_elem_ns (rexmpp_t *s,
}
if (s->current_element != s->current_element_root) {
- s->current_element = s->current_element->parent;
+ /* Find the parent, set it as current element. */
+ rexmpp_xml_t *parent = s->current_element_root;
+ while (parent->alt.elem.children != s->current_element) {
+ parent = parent->alt.elem.children;
+ }
+ s->current_element = parent;
} else {
+ /* Done parsing this element; reverse all the lists of children
+ and queue it. */
+ s->current_element = rexmpp_xml_reverse_all(s->current_element);
if (s->input_queue == NULL) {
s->input_queue = s->current_element;
s->input_queue_last = s->current_element;
diff --git a/src/rexmpp.h b/src/rexmpp.h
index 8211886..4cde101 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -368,13 +368,17 @@ struct rexmpp
/* A queue of XML elements to send. */
rexmpp_xml_t *send_queue;
+ /* An input queue of parsed XML structures. */
+ rexmpp_xml_t *input_queue;
+ rexmpp_xml_t *input_queue_last;
+
/* XML parser context, and current element pointer for building
XML nodes with a SAX2 parser interface. */
xmlParserCtxtPtr xml_parser;
- xmlNodePtr current_element_root;
- xmlNodePtr current_element;
- xmlNodePtr input_queue;
- xmlNodePtr input_queue_last;
+
+ /* The children are stored in reverse order during building. */
+ rexmpp_xml_t *current_element_root;
+ rexmpp_xml_t *current_element;
/* TLS structures. */
rexmpp_tls_t *tls;
diff --git a/src/rexmpp.rs b/src/rexmpp.rs
index 92b6fa0..b8057ba 100644
--- a/src/rexmpp.rs
+++ b/src/rexmpp.rs
@@ -233,13 +233,17 @@ pub struct Rexmpp {
// A queue of XML elements to send
pub send_queue: *mut rexmpp_xml::RexmppXML,
+ // An input queue of parsed XML structures
+ pub input_queue: *mut rexmpp_xml::RexmppXML,
+ pub input_queue_last: *mut rexmpp_xml::RexmppXML,
+
// XML parser context, and current element pointer for building
// XML nodes with a SAX2 parser interface
pub xml_parser: *mut c_void,
- pub current_element_root: *mut c_void,
- pub current_element: *mut c_void,
- pub input_queue: *mut c_void,
- pub input_queue_last: *mut c_void,
+
+ // The children are stored in reverse order during building
+ pub current_element_root: *mut rexmpp_xml::RexmppXML,
+ pub current_element: *mut rexmpp_xml::RexmppXML,
// TLS structures
pub tls: *mut c_void,
diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c
index 7e428e2..e77bf78 100644
--- a/src/rexmpp_xml.c
+++ b/src/rexmpp_xml.c
@@ -256,6 +256,14 @@ rexmpp_xml_t *rexmpp_xml_new_text (const char *str) {
return node;
}
+rexmpp_xml_t *rexmpp_xml_new_text_len (const char *str, size_t len) {
+ rexmpp_xml_t *node = malloc(sizeof(rexmpp_xml_t));
+ node->type = REXMPP_XML_TEXT;
+ node->alt.text = strndup(str, len);
+ node->next = NULL;
+ return node;
+}
+
void rexmpp_xml_add_child (rexmpp_xml_t *node,
rexmpp_xml_t *child)
{
@@ -277,6 +285,18 @@ int rexmpp_xml_add_text (rexmpp_xml_t *node,
return -1;
}
+int rexmpp_xml_add_text_len (rexmpp_xml_t *node,
+ const char *str,
+ size_t len)
+{
+ rexmpp_xml_t *text_node = rexmpp_xml_new_text_len(str, len);
+ if (text_node != NULL) {
+ rexmpp_xml_add_child(node, text_node);
+ return 0;
+ }
+ return -1;
+}
+
rexmpp_xml_t *rexmpp_xml_new_elem (const char *name,
const char *namespace)
{
@@ -787,4 +807,27 @@ char *rexmpp_xml_text (rexmpp_xml_t *node) {
char *rexmpp_xml_text_child (rexmpp_xml_t *node) {
return rexmpp_xml_text(rexmpp_xml_children(node));
}
+
+rexmpp_xml_t *rexmpp_xml_reverse (rexmpp_xml_t *node) {
+ rexmpp_xml_t *next, *prev = NULL;
+ while (node != NULL) {
+ next = node->next;
+ node->next = prev;
+ prev = node;
+ node = next;
+ }
+ return prev;
+}
+
+rexmpp_xml_t *rexmpp_xml_reverse_all (rexmpp_xml_t *node) {
+ node = rexmpp_xml_reverse(node);
+ rexmpp_xml_t *cur;
+ for (cur = node; cur != NULL; cur = cur->next) {
+ if (cur->type == REXMPP_XML_ELEMENT) {
+ cur->alt.elem.children = rexmpp_xml_reverse_all(cur->alt.elem.children);
+ }
+ }
+ return node;
+}
+
#endif
diff --git a/src/rexmpp_xml.h b/src/rexmpp_xml.h
index 0a3cb63..972c75c 100644
--- a/src/rexmpp_xml.h
+++ b/src/rexmpp_xml.h
@@ -94,6 +94,12 @@ xmlNodePtr rexmpp_xml_to_libxml2_list (rexmpp_xml_t *from);
rexmpp_xml_t *rexmpp_xml_new_text (const char *str);
/**
+ @brief Creates a textual ::rexmpp_xml_t XML node (with type =
+ ::REXMPP_XML_TEXT).
+*/
+rexmpp_xml_t *rexmpp_xml_new_text_len (const char *str, size_t len);
+
+/**
@brief Creates an element ::rexmpp_xml_t XML node (with type =
::REXMPP_XML_ELEMENT).
*/
@@ -112,6 +118,13 @@ void rexmpp_xml_add_child (rexmpp_xml_t *node,
int rexmpp_xml_add_text (rexmpp_xml_t *node,
const char *str);
+/**
+ @brief Creates a text node, and adds it as a child.
+*/
+int rexmpp_xml_add_text_len (rexmpp_xml_t *node,
+ const char *str,
+ size_t len);
+
rexmpp_xml_attr_t *rexmpp_xml_attr_new (const char *name,
const char *namespace,
const char *value);
@@ -233,4 +246,7 @@ rexmpp_xml_t *rexmpp_xml_parse (const char *str, int str_len);
rexmpp_xml_t *rexmpp_xml_read_file (const char *path);
int rexmpp_xml_write_file (const char *path, rexmpp_xml_t* node);
+rexmpp_xml_t *rexmpp_xml_reverse (rexmpp_xml_t *node);
+rexmpp_xml_t *rexmpp_xml_reverse_all (rexmpp_xml_t *node);
+
#endif
diff --git a/src/rexmpp_xml.rs b/src/rexmpp_xml.rs
index 30f5f38..622a28a 100644
--- a/src/rexmpp_xml.rs
+++ b/src/rexmpp_xml.rs
@@ -1,5 +1,5 @@
extern crate libc;
-use libc::{strdup, free};
+use libc::{strdup, strndup, free};
use std::os::raw::{c_char, c_int, c_void, c_uint};
use std::ptr;
use std::ffi::{CStr, CString};
@@ -247,6 +247,18 @@ fn rexmpp_xml_new_text (str: *const c_char) -> *mut RexmppXML {
}
#[no_mangle]
+extern "C"
+fn rexmpp_xml_new_text_len (str: *const c_char, len: usize) -> *mut RexmppXML {
+ let node = RexmppXML {
+ node_type: NodeType::Text,
+ alt: RexmppXMLAlt { text: unsafe { strndup(str, len) } },
+ 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 =
@@ -269,6 +281,18 @@ extern "C" fn rexmpp_xml_add_text (node: *mut RexmppXML,
}
#[no_mangle]
+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]
extern "C"
fn rexmpp_xml_new_elem (name: *const c_char,
namespace: *const c_char) -> *mut RexmppXML {