[librsvg] xml2_load.rs: Move all the libxml2 callbacks to here; port them to Rust.



commit 1ec9a4feaa386f8f83ddf6c34d1407ec07de9cf5
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Dec 5 13:07:35 2018 -0600

    xml2_load.rs: Move all the libxml2 callbacks to here; port them to Rust.

 Makefile.am                        |   3 +-
 librsvg/rsvg-load.c                | 265 ++++-----------------------------
 rsvg_internals/src/lib.rs          |   9 +-
 rsvg_internals/src/property_bag.rs |   1 -
 rsvg_internals/src/xml.rs          |  99 ------------
 rsvg_internals/src/xml2.rs         |   4 +-
 rsvg_internals/src/xml2_load.rs    | 298 +++++++++++++++++++++++++++++++++++++
 7 files changed, 332 insertions(+), 347 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 17ea9422..17f1a2f5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,7 +121,8 @@ RUST_SRC =                                                  \
        rsvg_internals/src/viewbox.rs                           \
        rsvg_internals/src/viewport.rs                          \
        rsvg_internals/src/xml.rs                               \
-       rsvg_internals/src/xml2.rs
+       rsvg_internals/src/xml2.rs                              \
+       rsvg_internals/src/xml2_load.rs
 
 RUST_EXTRA =                                           \
        Cargo.lock                                      \
diff --git a/librsvg/rsvg-load.c b/librsvg/rsvg-load.c
index bbe764be..90f06fe7 100644
--- a/librsvg/rsvg-load.c
+++ b/librsvg/rsvg-load.c
@@ -45,25 +45,22 @@ typedef struct RsvgXmlState RsvgXmlState;
 extern RsvgXmlState *rsvg_xml_state_new (RsvgHandle *handle);
 extern void rsvg_xml_state_free (RsvgXmlState *xml);
 extern gboolean rsvg_xml_state_tree_is_valid(RsvgXmlState *xml, GError **error);
-extern void rsvg_xml_state_start_element(RsvgXmlState *xml, const char *name, const char **atts);
-extern void rsvg_xml_state_end_element(RsvgXmlState *xml, const char *name);
-extern void rsvg_xml_state_characters(RsvgXmlState *xml, const char *unterminated_text, gsize len);
 extern void rsvg_xml_state_error(RsvgXmlState *xml, const char *msg);
 
-extern xmlEntityPtr rsvg_xml_state_entity_lookup(RsvgXmlState *xml,
-                                                 const char *entity_name);
-
-extern void rsvg_xml_state_entity_insert(RsvgXmlState *xml,
-                                         const char *entity_name,
-                                         xmlEntityPtr entity);
-
-extern void rsvg_xml_state_processing_instruction(RsvgXmlState *xml,
-                                                  const char *target,
-                                                  const char *data);
-
 /* Implemented in rsvg_internals/src/handle.rs */
 extern void rsvg_handle_rust_steal_result (RsvgHandleRust *raw_handle, RsvgXmlState *xml);
 
+/* Implemented in rsvg_internals/src/xml2_load.rs */
+extern xmlParserCtxtPtr rsvg_create_xml_stream_parser (RsvgXmlState  *xml,
+                                                       gboolean       unlimited_size,
+                                                       GInputStream  *stream,
+                                                       GCancellable  *cancellable,
+                                                       GError       **error);
+extern xmlParserCtxtPtr rsvg_create_xml_push_parser (RsvgXmlState *xml,
+                                                     gboolean unlimited_size,
+                                                     const char *base_uri,
+                                                     GError **error);
+
 
 /* Holds the XML parsing state */
 typedef struct {
@@ -88,8 +85,6 @@ struct RsvgLoad {
     XmlState xml;
 };
 
-static xmlSAXHandler get_xml2_sax_handler (void);
-
 RsvgLoad *
 rsvg_load_new (RsvgHandle *handle, gboolean unlimited_size)
 {
@@ -153,124 +148,6 @@ rsvg_load_finish_load (RsvgLoad *load, GError **error)
     return was_successful;
 }
 
-static void
-set_xml_parse_options(xmlParserCtxtPtr xml_parser,
-                      gboolean unlimited_size)
-{
-    int options;
-
-    options = (XML_PARSE_NONET |
-               XML_PARSE_BIG_LINES);
-
-    if (unlimited_size) {
-        options |= XML_PARSE_HUGE;
-    }
-
-    xmlCtxtUseOptions (xml_parser, options);
-
-    /* if false, external entities work, but internal ones don't. if true, internal entities
-       work, but external ones don't. favor internal entities, in order to not cause a
-       regression */
-    xml_parser->replaceEntities = TRUE;
-}
-
-static xmlParserCtxtPtr
-rsvg_create_xml_push_parser (RsvgXmlState *xml,
-                             gboolean unlimited_size,
-                             const char *base_uri)
-{
-    xmlParserCtxtPtr parser;
-    xmlSAXHandler sax_handler = get_xml2_sax_handler ();
-
-    parser = xmlCreatePushParserCtxt (&sax_handler, xml, NULL, 0, base_uri);
-    set_xml_parse_options (parser, unlimited_size);
-
-    return parser;
-}
-
-typedef struct {
-    GInputStream *stream;
-    GCancellable *cancellable;
-    GError      **error;
-} RsvgXmlInputStreamContext;
-
-/* this should use gsize, but libxml2 is borked */
-static int
-context_read (void *data,
-              char *buffer,
-              int   len)
-{
-    RsvgXmlInputStreamContext *context = data;
-    gssize n_read;
-
-    if (*(context->error))
-        return -1;
-
-    n_read = g_input_stream_read (context->stream, buffer, (gsize) len,
-                                  context->cancellable,
-                                  context->error);
-    if (n_read < 0)
-        return -1;
-
-    return (int) n_read;
-}
-
-static int
-context_close (void *data)
-{
-    RsvgXmlInputStreamContext *context = data;
-    gboolean ret;
-
-    /* Don't overwrite a previous error */
-    ret = g_input_stream_close (context->stream, context->cancellable,
-                                *(context->error) == NULL ? context->error : NULL);
-
-    g_object_unref (context->stream);
-    if (context->cancellable)
-        g_object_unref (context->cancellable);
-    g_slice_free (RsvgXmlInputStreamContext, context);
-
-    return ret ? 0 : -1;
-}
-
-static xmlParserCtxtPtr
-rsvg_create_xml_stream_parser (RsvgXmlState  *xml,
-                               gboolean       unlimited_size,
-                               GInputStream  *stream,
-                               GCancellable  *cancellable,
-                               GError       **error)
-{
-    RsvgXmlInputStreamContext *context;
-    xmlParserCtxtPtr parser;
-    xmlSAXHandler sax_handler = get_xml2_sax_handler ();
-
-    g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL);
-    g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
-    g_return_val_if_fail (error != NULL, NULL);
-
-    context = g_slice_new (RsvgXmlInputStreamContext);
-    context->stream = g_object_ref (stream);
-    context->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-    context->error = error;
-
-    parser = xmlCreateIOParserCtxt (&sax_handler,
-                                    xml,
-                                    context_read,
-                                    context_close,
-                                    context,
-                                    XML_CHAR_ENCODING_NONE);
-
-    if (!parser) {
-        g_set_error (error, rsvg_error_quark (), 0, _("Error creating XML parser"));
-
-        /* on error, xmlCreateIOParserCtxt() frees our context via the context_close function */
-    } else {
-        set_xml_parse_options (parser, unlimited_size);
-    }
-
-    return parser;
-}
-
 gboolean
 rsvg_load_handle_xml_xinclude (RsvgHandle *handle, const char *href)
 {
@@ -309,77 +186,13 @@ rsvg_load_handle_xml_xinclude (RsvgHandle *handle, const char *href)
 
 /* end xinclude */
 
-static void
-sax_start_element_cb (void *data, const xmlChar *name, const xmlChar **atts)
-{
-    RsvgXmlState *xml = data;
-
-    rsvg_xml_state_start_element (xml, (const char *) name, (const char **) atts);
-}
-
-static void
-sax_end_element_cb (void *data, const xmlChar *name)
-{
-    RsvgXmlState *xml = data;
-
-    rsvg_xml_state_end_element (xml, (const char *) name);
-}
-
-static void
-sax_characters_cb (void *data, const xmlChar * ch, int len)
-{
-    RsvgXmlState *xml = data;
-
-    rsvg_xml_state_characters (xml, (const char *) ch, (gsize) len);
-}
-
-static xmlEntityPtr
-sax_get_entity_cb (void *data, const xmlChar * name)
-{
-    RsvgXmlState *xml = data;
-
-    return rsvg_xml_state_entity_lookup (xml, (const char *) name);
-}
-
-static void
-sax_entity_decl_cb (void *data, const xmlChar * name, int type,
-                    const xmlChar * publicId, const xmlChar * systemId, xmlChar * content)
-{
-    RsvgXmlState *xml = data;
-    xmlEntityPtr entity;
-
-    if (type != XML_INTERNAL_GENERAL_ENTITY) {
-        /* We don't allow loading external entities; we don't support defining
-        * parameter entities in the DTD, and libxml2 should handle internal
-        * predefined entities by itself (e.g. "&amp;").
-        */
-        return;
-    }
-
-    entity = xmlNewEntity (NULL, name, type, NULL, NULL, content);
-
-    rsvg_xml_state_entity_insert (xml, (const char *) name, entity);
-}
-
-static void
-sax_unparsed_entity_decl_cb (void *data,
-                             const xmlChar * name,
-                             const xmlChar * publicId,
-                             const xmlChar * systemId, const xmlChar * notationName)
-{
-    sax_entity_decl_cb (data, name, XML_INTERNAL_GENERAL_ENTITY, publicId, systemId, NULL);
-}
-
-static xmlEntityPtr
-sax_get_parameter_entity_cb (void *data, const xmlChar * name)
-{
-    RsvgXmlState *xml = data;
-
-    return rsvg_xml_state_entity_lookup (xml, (const char *) name);
-}
+/* This one is defined in the C code, because the prototype has varargs
+ * and we can't handle those from Rust :(
+ */
+G_GNUC_INTERNAL void rsvg_sax_error_cb (void *data, const char *msg, ...);
 
-static void
-sax_error_cb (void *data, const char *msg, ...)
+void
+rsvg_sax_error_cb (void *data, const char *msg, ...)
 {
     RsvgXmlState *xml = data;
     va_list args;
@@ -394,14 +207,6 @@ sax_error_cb (void *data, const char *msg, ...)
     g_free (buf);
 }
 
-static void
-sax_processing_instruction_cb (void *user_data, const xmlChar * target, const xmlChar * data)
-{
-    RsvgXmlState *xml = user_data;
-
-    rsvg_xml_state_processing_instruction (xml, (const char *) target, (const char *) data);
-}
-
 static void
 set_error_from_xml (GError **error, xmlParserCtxtPtr ctxt)
 {
@@ -431,13 +236,18 @@ write_impl (RsvgLoad *load, const guchar * buf, gsize count, GError **error)
     if (load->xml.ctxt == NULL) {
         load->xml.ctxt = rsvg_create_xml_push_parser (load->xml.rust_state,
                                                       load->unlimited_size,
-                                                      rsvg_handle_get_base_uri (load->handle));
+                                                      rsvg_handle_get_base_uri (load->handle),
+                                                      &real_error);
     }
 
-    result = xmlParseChunk (load->xml.ctxt, (char *) buf, count, 0);
-    if (result != 0) {
-        set_error_from_xml (error, load->xml.ctxt);
-        return FALSE;
+    if (load->xml.ctxt != NULL) {
+        result = xmlParseChunk (load->xml.ctxt, (char *) buf, count, 0);
+        if (result != 0) {
+            set_error_from_xml (error, load->xml.ctxt);
+            return FALSE;
+        }
+    } else {
+        g_assert (real_error != NULL);
     }
 
     load->error = NULL;
@@ -645,24 +455,3 @@ rsvg_load_close (RsvgLoad *load, GError **error)
 
     return res;
 }
-
-static xmlSAXHandler
-get_xml2_sax_handler (void)
-{
-    xmlSAXHandler sax_handler;
-
-    memset (&sax_handler, 0, sizeof (sax_handler));
-
-    sax_handler.getEntity = sax_get_entity_cb;
-    sax_handler.entityDecl = sax_entity_decl_cb;
-    sax_handler.unparsedEntityDecl = sax_unparsed_entity_decl_cb;
-    sax_handler.getParameterEntity = sax_get_parameter_entity_cb;
-    sax_handler.characters = sax_characters_cb;
-    sax_handler.error = sax_error_cb;
-    sax_handler.cdataBlock = sax_characters_cb;
-    sax_handler.startElement = sax_start_element_cb;
-    sax_handler.endElement = sax_end_element_cb;
-    sax_handler.processingInstruction = sax_processing_instruction_cb;
-
-    return sax_handler;
-}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 06efa3b1..a4e166a8 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -64,18 +64,14 @@ pub use node::rsvg_node_unref;
 pub use structure::rsvg_node_svg_get_size;
 
 pub use xml::{
-    rsvg_xml_state_characters,
-    rsvg_xml_state_end_element,
-    rsvg_xml_state_entity_insert,
-    rsvg_xml_state_entity_lookup,
     rsvg_xml_state_error,
     rsvg_xml_state_free,
     rsvg_xml_state_new,
-    rsvg_xml_state_processing_instruction,
-    rsvg_xml_state_start_element,
     rsvg_xml_state_tree_is_valid,
 };
 
+pub use xml2_load::{rsvg_create_xml_push_parser, rsvg_create_xml_stream_parser};
+
 #[macro_use]
 mod log;
 
@@ -139,3 +135,4 @@ mod viewbox;
 mod viewport;
 mod xml;
 mod xml2;
+mod xml2_load;
diff --git a/rsvg_internals/src/property_bag.rs b/rsvg_internals/src/property_bag.rs
index 07a6de39..96ac0fe6 100644
--- a/rsvg_internals/src/property_bag.rs
+++ b/rsvg_internals/src/property_bag.rs
@@ -138,7 +138,6 @@ impl<'a> Iterator for PropertyBagCStrIter<'a> {
 mod tests {
     use super::*;
     use std::ffi::CString;
-    use std::mem;
     use std::ptr;
 
     #[test]
diff --git a/rsvg_internals/src/xml.rs b/rsvg_internals/src/xml.rs
index f72c65fb..1b6e8b8e 100644
--- a/rsvg_internals/src/xml.rs
+++ b/rsvg_internals/src/xml.rs
@@ -2,10 +2,8 @@ use encoding::label::encoding_from_whatwg_label;
 use encoding::DecoderTrap;
 use glib::translate::*;
 use libc;
-use std;
 use std::collections::HashMap;
 use std::mem;
-use std::ptr;
 use std::rc::Rc;
 use std::str;
 use xml_rs::{reader::XmlEvent, ParserConfig};
@@ -24,7 +22,6 @@ use style::NodeStyle;
 use svg::Svg;
 use text::NodeChars;
 use tree::Tree;
-use util::utf8_cstr;
 
 #[derive(Clone)]
 enum ContextKind {
@@ -595,71 +592,6 @@ pub extern "C" fn rsvg_xml_state_free(xml: *mut RsvgXmlState) {
     }
 }
 
-#[no_mangle]
-pub extern "C" fn rsvg_xml_state_start_element(
-    xml: *mut RsvgXmlState,
-    name: *const libc::c_char,
-    atts: *const *const libc::c_char,
-) {
-    assert!(!xml.is_null());
-    let xml = unsafe { &mut *(xml as *mut XmlState) };
-
-    assert!(!name.is_null());
-    let name = unsafe { utf8_cstr(name) };
-
-    let pbag = unsafe { PropertyBag::new_from_key_value_pairs(atts) };
-
-    xml.start_element(name, &pbag);
-}
-
-#[no_mangle]
-pub extern "C" fn rsvg_xml_state_end_element(xml: *mut RsvgXmlState, name: *const libc::c_char) {
-    assert!(!xml.is_null());
-    let xml = unsafe { &mut *(xml as *mut XmlState) };
-
-    assert!(!name.is_null());
-    let name = unsafe { utf8_cstr(name) };
-
-    xml.end_element(name);
-}
-
-#[no_mangle]
-pub extern "C" fn rsvg_xml_state_characters(
-    xml: *mut RsvgXmlState,
-    unterminated_text: *const libc::c_char,
-    len: usize,
-) {
-    assert!(!xml.is_null());
-    let xml = unsafe { &mut *(xml as *mut XmlState) };
-
-    assert!(!unterminated_text.is_null());
-
-    // libxml2 already validated the incoming string as UTF-8.  Note that
-    // it is *not* nul-terminated; this is why we create a byte slice first.
-    let bytes = unsafe { std::slice::from_raw_parts(unterminated_text as *const u8, len) };
-    let utf8 = unsafe { str::from_utf8_unchecked(bytes) };
-
-    xml.characters(utf8);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_xml_state_processing_instruction(
-    xml: *mut RsvgXmlState,
-    target: *const libc::c_char,
-    data: *const libc::c_char,
-) {
-    assert!(!xml.is_null());
-    let xml = &mut *(xml as *mut XmlState);
-
-    assert!(!target.is_null());
-    let target = utf8_cstr(target);
-
-    assert!(!data.is_null());
-    let data = utf8_cstr(data);
-
-    xml.processing_instruction(target, data);
-}
-
 #[no_mangle]
 pub unsafe extern "C" fn rsvg_xml_state_error(xml: *mut RsvgXmlState, msg: *const libc::c_char) {
     assert!(!xml.is_null());
@@ -673,37 +605,6 @@ pub unsafe extern "C" fn rsvg_xml_state_error(xml: *mut RsvgXmlState, msg: *cons
     xml.error(&msg);
 }
 
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_xml_state_entity_lookup(
-    xml: *const RsvgXmlState,
-    entity_name: *const libc::c_char,
-) -> XmlEntityPtr {
-    assert!(!xml.is_null());
-    let xml = &*(xml as *mut XmlState);
-
-    assert!(!entity_name.is_null());
-    let entity_name = utf8_cstr(entity_name);
-
-    xml.entity_lookup(entity_name).unwrap_or(ptr::null_mut())
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_xml_state_entity_insert(
-    xml: *mut RsvgXmlState,
-    entity_name: *const libc::c_char,
-    entity: XmlEntityPtr,
-) {
-    assert!(!xml.is_null());
-    let xml = &mut *(xml as *mut XmlState);
-
-    assert!(!entity_name.is_null());
-    let entity_name = utf8_cstr(entity_name);
-
-    assert!(!entity.is_null());
-
-    xml.entity_insert(entity_name, entity);
-}
-
 #[no_mangle]
 pub unsafe extern "C" fn rsvg_xml_state_tree_is_valid(
     xml: *mut RsvgXmlState,
diff --git a/rsvg_internals/src/xml2.rs b/rsvg_internals/src/xml2.rs
index b1ac7362..25d2e058 100644
--- a/rsvg_internals/src/xml2.rs
+++ b/rsvg_internals/src/xml2.rs
@@ -152,7 +152,7 @@ pub type xmlErrorPtr = *mut xmlError;
 
 pub type xmlInputReadCallback = Option<unsafe extern "C" fn(
     context: *mut libc::c_void,
-    buffer: *const libc::c_char,
+    buffer: *mut libc::c_char,
     len: libc::c_int,
 ) -> libc::c_int>;
 
@@ -168,7 +168,7 @@ extern "C" {
         user_data: *mut libc::c_void,
         chunk: *const libc::c_char,
         size: libc::c_int,
-        filename: *const libc::c_int,
+        filename: *const libc::c_char,
     ) -> xmlParserCtxtPtr;
 
     pub fn xmlCreateIOParserCtxt(
diff --git a/rsvg_internals/src/xml2_load.rs b/rsvg_internals/src/xml2_load.rs
new file mode 100644
index 00000000..abf6ca77
--- /dev/null
+++ b/rsvg_internals/src/xml2_load.rs
@@ -0,0 +1,298 @@
+// This file provides functions to create a libxml2 xmlParserCtxtPtr, configured
+// to read from a gio::InputStream, and to maintain its loading data in an XmlState.
+
+use gio;
+use gio::prelude::*;
+use gio_sys;
+use glib_sys;
+use std::mem;
+use std::ptr;
+use std::slice;
+use std::str;
+
+use glib::translate::*;
+
+use error::set_gerror;
+use property_bag::PropertyBag;
+use util::utf8_cstr;
+use xml::{RsvgXmlState, XmlState};
+use xml2::*;
+
+extern "C" {
+    fn rsvg_sax_error_cb(data: *mut libc::c_void);
+}
+
+fn get_xml2_sax_handler() -> xmlSAXHandler {
+    let mut h: xmlSAXHandler = unsafe { mem::zeroed() };
+
+    h.getEntity = Some(sax_get_entity_cb);
+    h.entityDecl = Some(sax_entity_decl_cb);
+    h.unparsedEntityDecl = Some(sax_unparsed_entity_decl_cb);
+    h.getParameterEntity = Some(sax_get_parameter_entity_cb);
+    h.characters = Some(sax_characters_cb);
+    h.cdataBlock = Some(sax_characters_cb);
+    h.startElement = Some(sax_start_element_cb);
+    h.endElement = Some(sax_end_element_cb);
+    h.processingInstruction = Some(sax_processing_instruction_cb);
+
+    // This one is defined in the C code, because the prototype has varargs
+    // and we can't handle those from Rust :(
+    h.error = rsvg_sax_error_cb as *mut _;
+
+    h
+}
+
+unsafe extern "C" fn sax_get_entity_cb(
+    ctx: *mut libc::c_void,
+    name: *const libc::c_char,
+) -> xmlEntityPtr {
+    let xml = &*(ctx as *mut XmlState);
+
+    assert!(!name.is_null());
+    let name = utf8_cstr(name);
+
+    xml.entity_lookup(name).unwrap_or(ptr::null_mut())
+}
+
+unsafe extern "C" fn sax_entity_decl_cb(
+    ctx: *mut libc::c_void,
+    name: *const libc::c_char,
+    type_: libc::c_int,
+    _public_id: *const libc::c_char,
+    _system_id: *const libc::c_char,
+    content: *const libc::c_char,
+) {
+    let xml = &mut *(ctx as *mut XmlState);
+
+    assert!(!name.is_null());
+
+    if type_ != XML_INTERNAL_GENERAL_ENTITY {
+        // We don't allow loading external entities; we don't support
+        // defining parameter entities in the DTD, and libxml2 should
+        // handle internal predefined entities by itself (e.g. "&amp;").
+        return;
+    }
+
+    let entity = xmlNewEntity(
+        ptr::null_mut(),
+        name,
+        type_,
+        ptr::null(),
+        ptr::null(),
+        content,
+    );
+    assert!(!entity.is_null());
+
+    let name = utf8_cstr(name);
+    xml.entity_insert(name, entity);
+}
+
+unsafe extern "C" fn sax_unparsed_entity_decl_cb(
+    ctx: *mut libc::c_void,
+    name: *const libc::c_char,
+    public_id: *const libc::c_char,
+    system_id: *const libc::c_char,
+    _notation_name: *const libc::c_char,
+) {
+    sax_entity_decl_cb(
+        ctx,
+        name,
+        XML_INTERNAL_GENERAL_ENTITY,
+        public_id,
+        system_id,
+        ptr::null(),
+    );
+}
+
+unsafe extern "C" fn sax_start_element_cb(
+    ctx: *mut libc::c_void,
+    name: *const libc::c_char,
+    atts: *const *const libc::c_char,
+) {
+    let xml = &mut *(ctx as *mut XmlState);
+
+    assert!(!name.is_null());
+    let name = utf8_cstr(name);
+
+    let pbag = PropertyBag::new_from_key_value_pairs(atts);
+
+    xml.start_element(name, &pbag);
+}
+
+unsafe extern "C" fn sax_end_element_cb(ctx: *mut libc::c_void, name: *const libc::c_char) {
+    let xml = &mut *(ctx as *mut XmlState);
+
+    assert!(!name.is_null());
+    let name = utf8_cstr(name);
+
+    xml.end_element(name);
+}
+
+unsafe extern "C" fn sax_characters_cb(
+    ctx: *mut libc::c_void,
+    unterminated_text: *const libc::c_char,
+    len: libc::c_int,
+) {
+    let xml = &mut *(ctx as *mut XmlState);
+
+    assert!(!unterminated_text.is_null());
+    assert!(len >= 0);
+
+    // libxml2 already validated the incoming string as UTF-8.  Note that
+    // it is *not* nul-terminated; this is why we create a byte slice first.
+    let bytes = std::slice::from_raw_parts(unterminated_text as *const u8, len as usize);
+    let utf8 = str::from_utf8_unchecked(bytes);
+
+    xml.characters(utf8);
+}
+
+unsafe extern "C" fn sax_processing_instruction_cb(
+    ctx: *mut libc::c_void,
+    target: *const libc::c_char,
+    data: *const libc::c_char,
+) {
+    let xml = &mut *(ctx as *mut XmlState);
+
+    assert!(!target.is_null());
+    let target = utf8_cstr(target);
+
+    assert!(!data.is_null());
+    let data = utf8_cstr(data);
+
+    xml.processing_instruction(target, data);
+}
+
+unsafe extern "C" fn sax_get_parameter_entity_cb(
+    ctx: *mut libc::c_void,
+    name: *const libc::c_char,
+) -> xmlEntityPtr {
+    sax_get_entity_cb(ctx, name)
+}
+
+fn set_xml_parse_options(parser: xmlParserCtxtPtr, unlimited_size: bool) {
+    let mut options: libc::c_int = XML_PARSE_NONET | XML_PARSE_BIG_LINES;
+
+    if unlimited_size {
+        options |= XML_PARSE_HUGE;
+    }
+
+    unsafe {
+        xmlCtxtUseOptions(parser, options);
+
+        // If false, external entities work, but internal ones don't. if
+        // true, internal entities work, but external ones don't. favor
+        // internal entities, in order to not cause a regression
+        (*parser).replaceEntities = 1;
+    }
+}
+
+struct StreamCtx {
+    stream: gio::InputStream,
+    cancellable: Option<gio::Cancellable>,
+    error: *mut *mut glib_sys::GError,
+}
+
+// read() callback from xmlCreateIOParserCtxt()
+unsafe extern "C" fn stream_ctx_read(
+    context: *mut libc::c_void,
+    buffer: *mut libc::c_char,
+    len: libc::c_int,
+) -> libc::c_int {
+    let ctx = &mut *(context as *mut StreamCtx);
+
+    // has the error been set already?
+    if !(*ctx.error).is_null() {
+        return -1;
+    }
+
+    let buf: &mut [u8] = slice::from_raw_parts_mut(buffer as *mut u8, len as usize);
+
+    match ctx.stream.read(buf, ctx.cancellable.as_ref()) {
+        Ok(size) => size as libc::c_int,
+
+        Err(e) => {
+            let e: *const glib_sys::GError = e.to_glib_full();
+            *ctx.error = e as *mut _;
+            -1
+        }
+    }
+}
+
+// close() callback from xmlCreateIOParserCtxt()
+unsafe extern "C" fn stream_ctx_close(context: *mut libc::c_void) -> libc::c_int {
+    let ctx = &mut *(context as *mut StreamCtx);
+
+    let ret = match ctx.stream.close(ctx.cancellable.as_ref()) {
+        Ok(()) => 0,
+
+        Err(e) => {
+            // don't overwrite a previous error
+            if (*ctx.error).is_null() {
+                let e: *const glib_sys::GError = e.to_glib_full();
+                *ctx.error = e as *mut _;
+            }
+
+            -1
+        }
+    };
+
+    Box::from_raw(ctx);
+
+    ret
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_create_xml_stream_parser(
+    xml: *mut RsvgXmlState,
+    unlimited_size: glib_sys::gboolean,
+    stream: *mut gio_sys::GInputStream,
+    cancellable: *mut gio_sys::GCancellable,
+    error: *mut *mut glib_sys::GError,
+) -> xmlParserCtxtPtr {
+    let ctx = Box::new(StreamCtx {
+        stream: from_glib_none(stream),
+        cancellable: from_glib_none(cancellable),
+        error,
+    });
+
+    let mut sax_handler = get_xml2_sax_handler();
+
+    let parser = xmlCreateIOParserCtxt(
+        &mut sax_handler,
+        xml as *mut _,
+        Some(stream_ctx_read),
+        Some(stream_ctx_close),
+        Box::into_raw(ctx) as *mut _,
+        XML_CHAR_ENCODING_NONE,
+    );
+
+    if parser.is_null() {
+        set_gerror(error, 0, "Error creating XML parser");
+    // on error, xmlCreateIOParserCtxt() frees our context via the
+    // stream_ctx_close function
+    } else {
+        set_xml_parse_options(parser, from_glib(unlimited_size));
+    }
+
+    parser
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_create_xml_push_parser(
+    xml: *mut RsvgXmlState,
+    unlimited_size: glib_sys::gboolean,
+    base_uri: *const libc::c_char,
+    error: *mut *mut glib_sys::GError,
+) -> xmlParserCtxtPtr {
+    let mut sax_handler = get_xml2_sax_handler();
+
+    let parser = xmlCreatePushParserCtxt(&mut sax_handler, xml as *mut _, ptr::null(), 0, base_uri);
+
+    if parser.is_null() {
+        set_gerror(error, 0, "Error creating XML parser");
+    } else {
+        set_xml_parse_options(parser, from_glib(unlimited_size));
+    }
+
+    parser
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]