From e3d8e7d63bb3e1ccd38ce5ca8ca9c94f995612d6 Mon Sep 17 00:00:00 2001 From: defanor Date: Thu, 7 Sep 2023 14:32:41 +0300 Subject: Build rexmpp_xml_t directly on SAX parsing Afterwards it is used for the input queue, too. --- src/rexmpp.c | 44 ++++++++++++++++++++++++++++---------------- src/rexmpp.h | 12 ++++++++---- src/rexmpp.rs | 12 ++++++++---- src/rexmpp_xml.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/rexmpp_xml.h | 16 ++++++++++++++++ src/rexmpp_xml.rs | 26 +++++++++++++++++++++++++- 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 @@ -93,6 +93,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}; @@ -246,6 +246,18 @@ fn rexmpp_xml_new_text (str: *const c_char) -> *mut RexmppXML { return Box::into_raw(b); } +#[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) -> () { @@ -268,6 +280,18 @@ extern "C" fn rexmpp_xml_add_text (node: *mut RexmppXML, return 0; } +#[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, -- cgit v1.2.3