diff options
Diffstat (limited to 'src/rexmpp_xml_parser.rs')
-rw-r--r-- | src/rexmpp_xml_parser.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/rexmpp_xml_parser.rs b/src/rexmpp_xml_parser.rs new file mode 100644 index 0000000..037c2f2 --- /dev/null +++ b/src/rexmpp_xml_parser.rs @@ -0,0 +1,145 @@ +extern crate libc; +extern crate rxml; +use libc::{free, strndup}; +use std::ptr; +use std::os::raw::{c_char, c_void}; +use std::ffi::{CStr, CString}; +use std::slice; +use rxml::{FeedParser, Error, ResolvedEvent, XmlVersion, EventRead, CData}; +use std::io; +use super::{rexmpp_xml}; + +type RexmppXMLParserElementStart = unsafe extern "C" +fn (data: *mut c_void, + name: *const c_char, + namespace: *const c_char, + attributes: *mut rexmpp_xml::RexmppXMLAttribute) -> (); + +type RexmppXMLParserElementEnd = unsafe extern "C" +fn (data: *mut c_void) -> (); + +type RexmppXMLParserCharacters = unsafe extern "C" +fn (data: *mut c_void, + ch: *const c_char, + len: usize) -> (); + +#[repr(C)] +struct RexmppXMLParserHandlers { + elem_start: RexmppXMLParserElementStart, + elem_end: RexmppXMLParserElementEnd, + text: RexmppXMLParserCharacters +} + +#[repr(C)] +struct RexmppXMLParserCtx { + xml_parser: *mut FeedParser, + handlers: *mut RexmppXMLParserHandlers, + user_data: *mut c_void +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_parser_new (handlers: *mut RexmppXMLParserHandlers, + data: *mut c_void) + -> *mut RexmppXMLParserCtx +{ + let mut fp = FeedParser::default(); + let ctx = RexmppXMLParserCtx { + xml_parser: Box::into_raw(Box::new(fp)), + handlers: handlers, + user_data: data + }; + Box::into_raw(Box::new(ctx)) +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_parser_free (ctx: *mut RexmppXMLParserCtx) { + unsafe { free(ctx as *mut c_void) }; +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_parser_feed (ctx: *mut RexmppXMLParserCtx, + chunk: *const c_char, + len: usize, + is_final: bool) +{ + unsafe { + // todo: maybe duplicate the string, since apparently a + // mutable one is expected by the parser. + let mut buf : &[u8] = slice::from_raw_parts(chunk as *mut u8, len); + let user_data_ptr = (*ctx).user_data; + let handlers = (*ctx).handlers; + (*((*ctx).xml_parser)).parse_all(&mut buf, is_final, |ev| { + match ev { + ResolvedEvent::StartElement(_, (namespace, name), attrs) => + { + let name_str = name.to_string(); + let ns_opt_cstr : Option<CString> = match namespace { + None => None, + Some(ns_arc_name) => { + match CString::new(ns_arc_name.to_string()) { + Ok(cstr) => Some(cstr), + Err(_) => None + } + } + }; + match CString::new(name_str) { + Ok(name_cstr) => { + let name_cstr_ptr = name_cstr.as_ptr(); + let namespace_cstr_ptr = + match ns_opt_cstr { + None => ptr::null_mut(), + // "ref" is important to use here, + // otherwise the pointer will be + // wrong. + Some(ref ns_cstr) => ns_cstr.as_ptr() + }; + let mut attributes = ptr::null_mut(); + for ((_, attr_name), attr_val) in attrs.iter() { + match (CString::new(attr_name.to_string()), + CString::new(attr_val.to_string())) { + (Ok(attr_name_cstr), Ok(attr_val_cstr)) => { + let attr = + rexmpp_xml::rexmpp_xml_attr_new + (attr_name_cstr.as_ptr(), + ptr::null_mut(), + attr_val_cstr.as_ptr()); + (*attr).next = attributes; + attributes = attr; + }, + _ => () + } + } + ((*handlers).elem_start) + (user_data_ptr, + name_cstr_ptr, + namespace_cstr_ptr, + attributes); + }, + Err(_) => () + } + }, + ResolvedEvent::EndElement(_) => + ((*handlers).elem_end)(user_data_ptr), + ResolvedEvent::Text(_, cd) => + ((*handlers).text)( + user_data_ptr, + cd.as_ptr() as *const i8, + cd.len() + ), + _ => () + } + }); + } +} + +#[no_mangle] +extern "C" +fn rexmpp_xml_parser_reset (ctx_raw: *mut RexmppXMLParserCtx) + -> *mut RexmppXMLParserCtx +{ + let ctx = unsafe { Box::from_raw(ctx_raw) }; + rexmpp_xml_parser_new((*ctx).handlers, (*ctx).user_data) +} |