[librsvg] xml2_load.rs: Move all the libxml2 callbacks to here; port them to Rust.
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] xml2_load.rs: Move all the libxml2 callbacks to here; port them to Rust.
- Date: Wed, 5 Dec 2018 19:12:19 +0000 (UTC)
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. "&").
- */
- 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. "&").
+ 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]