summaryrefslogtreecommitdiff
path: root/src/rexmpp_xml_parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp_xml_parser.rs')
-rw-r--r--src/rexmpp_xml_parser.rs145
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)
+}