[librsvg] load.rs: Port all of RsvgLoad to Rust. Yay!



commit 018e5a677ed14a0bf216a93f3cfa2a9de92e602e
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Dec 10 17:38:45 2018 -0600

    load.rs: Port all of RsvgLoad to Rust.  Yay!
    
    The only remaining function in rsvg-load.[ch], rsvg_sax_error_cb(), is
    in rsvg-handle.c now.

 Makefile.am                     |   3 +-
 librsvg/rsvg-handle.c           |  41 +++++++++--
 librsvg/rsvg-load.c             | 159 ----------------------------------------
 librsvg/rsvg-load.h             |  40 ----------
 rsvg_internals/src/lib.rs       |   7 +-
 rsvg_internals/src/load.rs      | 158 +++++++++++++++++++++++++++++++++++++++
 rsvg_internals/src/xml2.rs      |  15 ----
 rsvg_internals/src/xml2_load.rs |   2 +-
 8 files changed, 199 insertions(+), 226 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index f1ddc052..03a5545b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,8 +28,6 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
        librsvg/rsvg-cairo.h                    \
        librsvg/rsvg-css.h                      \
        librsvg/rsvg-handle.c                   \
-       librsvg/rsvg-load.c                     \
-       librsvg/rsvg-load.h                     \
        librsvg/rsvg-pixbuf.c                   \
        librsvg/rsvg-private.h                  \
        librsvg/rsvg-size-callback.c            \
@@ -88,6 +86,7 @@ RUST_SRC =                                                    \
        rsvg_internals/src/iri.rs                               \
        rsvg_internals/src/length.rs                            \
        rsvg_internals/src/lib.rs                               \
+       rsvg_internals/src/load.rs                              \
        rsvg_internals/src/log.rs                               \
        rsvg_internals/src/link.rs                              \
        rsvg_internals/src/marker.rs                            \
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 589996f7..5f896e69 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -124,7 +124,7 @@
 #include <limits.h>
 #include <stdlib.h>
 
-#include "rsvg-load.h"
+#include <glib/gprintf.h>
 #include "rsvg-private.h"
 
 /* Implemented in rsvg_internals/src/handle.rs */
@@ -146,6 +146,13 @@ extern void rsvg_handle_rust_steal_result (RsvgHandleRust *raw_handle, RsvgXmlSt
 extern void rsvg_xml_state_free (RsvgXmlState *xml);
 extern gboolean rsvg_xml_state_tree_is_valid(RsvgXmlState *xml, GError **error);
 
+/* Implemented in rsvg_internals/src/load.rs */
+extern RsvgLoad *rsvg_load_new (RsvgXmlState *xml, gboolean unlimited_size) G_GNUC_WARN_UNUSED_RESULT;
+extern RsvgXmlState *rsvg_load_free (RsvgLoad *load) G_GNUC_WARN_UNUSED_RESULT;
+extern void rsvg_load_write (RsvgLoad *load, const guchar *buf, gsize count);
+extern gboolean rsvg_load_close (RsvgLoad *load, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+
 /* Implemented in rust/src/node.rs */
 /* Call this as node = rsvg_node_unref (node);  Then node will be NULL and you don't own it anymore! */
 extern RsvgNode *rsvg_node_unref (RsvgNode *node);
@@ -676,10 +683,9 @@ rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **
 
     priv = handle->priv;
 
-    rsvg_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START
-                             || priv->hstate == RSVG_HANDLE_STATE_LOADING,
-                             FALSE,
-                             error);
+    g_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START
+                          || priv->hstate == RSVG_HANDLE_STATE_LOADING,
+                          FALSE);
 
     if (priv->hstate == RSVG_HANDLE_STATE_START) {
         priv->hstate = RSVG_HANDLE_STATE_LOADING;
@@ -689,7 +695,9 @@ rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **
 
     g_assert (priv->hstate == RSVG_HANDLE_STATE_LOADING);
 
-    return rsvg_load_write (priv->load, buf, count, error);
+    rsvg_load_write (priv->load, buf, count);
+
+    return TRUE;
 }
 
 static gboolean
@@ -1636,3 +1644,24 @@ rsvg_handle_internal_set_testing (RsvgHandle *handle, gboolean testing)
 
     rsvg_handle_update_font_map_for_testing (handle);
 }
+
+/* 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, ...);
+
+void
+rsvg_sax_error_cb (void *data, const char *msg, ...)
+{
+    RsvgXmlState *xml = data;
+    va_list args;
+    char *buf;
+
+    va_start (args, msg);
+    g_vasprintf (&buf, msg, args);
+    va_end (args);
+
+    rsvg_xml_state_error (xml, buf);
+
+    g_free (buf);
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 8e2d507b..f1fc4264 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -61,6 +61,8 @@ pub use handle::{
     rsvg_handle_rust_steal_result,
 };
 
+pub use load::{rsvg_load_close, rsvg_load_free, rsvg_load_new, rsvg_load_write};
+
 pub use node::rsvg_node_unref;
 
 pub use structure::rsvg_node_svg_get_size;
@@ -72,9 +74,7 @@ pub use xml::{
     rsvg_xml_state_tree_is_valid,
 };
 
-pub use xml2_load::{
-    rsvg_xml_state_load_from_possibly_compressed_stream,
-};
+pub use xml2_load::rsvg_xml_state_load_from_possibly_compressed_stream;
 
 #[macro_use]
 mod log;
@@ -111,6 +111,7 @@ mod io;
 mod iri;
 mod length;
 mod link;
+mod load;
 mod marker;
 mod mask;
 mod node;
diff --git a/rsvg_internals/src/load.rs b/rsvg_internals/src/load.rs
new file mode 100644
index 00000000..69a318a4
--- /dev/null
+++ b/rsvg_internals/src/load.rs
@@ -0,0 +1,158 @@
+use gio;
+use glib::translate::*;
+use glib::{Bytes, Cast};
+use glib_sys;
+
+use std::slice;
+
+use error::set_gerror;
+use xml::XmlState;
+use xml2_load::{xml_state_load_from_possibly_compressed_stream, ParseFromStreamError};
+
+// Long-lived loading context for the deprecated I/O API
+//
+// rsvg_handle_write() and rsvg_handle_close() are old-style functions to
+// feed an RsvgHandle with data.  Current code prefers the stream APIs,
+// rsvg_handle_new_from_stream_sync() and similar.
+//
+// This struct maintains the loading context while an RsvgHandle is being
+// populated with data, in case the caller is using write()/close().
+pub struct LoadContext<'a> {
+    unlimited_size: bool,
+
+    state: LoadState,
+
+    buffer: Vec<u8>,
+
+    xml: &'a mut XmlState,
+}
+
+#[derive(Copy, Clone)]
+enum LoadState {
+    Start,
+    Reading,
+    Closed,
+}
+
+impl<'a> LoadContext<'a> {
+    pub fn new(xml: &mut XmlState, unlimited_size: bool) -> LoadContext {
+        LoadContext {
+            unlimited_size,
+            state: LoadState::Start,
+            buffer: Vec::new(),
+            xml,
+        }
+    }
+
+    pub fn write(&mut self, buf: &[u8]) {
+        let state = self.state;
+
+        self.state = match state {
+            LoadState::Start => LoadState::Reading,
+            LoadState::Reading => LoadState::Reading,
+
+            _ => unreachable!(),
+        };
+
+        self.buffer.extend_from_slice(buf);
+    }
+
+    pub fn close(&mut self) -> Result<(), ParseFromStreamError> {
+        let state = self.state;
+
+        match state {
+            LoadState::Start | LoadState::Closed => {
+                self.state = LoadState::Closed;
+                Ok(())
+            }
+
+            LoadState::Reading => {
+                self.state = LoadState::Closed;
+
+                let bytes = Bytes::from(&self.buffer);
+                let stream = gio::MemoryInputStream::new_from_bytes(&bytes);
+
+                xml_state_load_from_possibly_compressed_stream(
+                    &mut self.xml,
+                    self.unlimited_size,
+                    stream.upcast(),
+                    None,
+                )
+            }
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_load_new<'a>(
+    raw_xml: *mut XmlState,
+    unlimited_size: glib_sys::gboolean,
+) -> *mut LoadContext<'a> {
+    assert!(!raw_xml.is_null());
+
+    let xml = &mut *raw_xml;
+    let unlimited_size = from_glib(unlimited_size);
+
+    Box::into_raw(Box::new(LoadContext::new(xml, unlimited_size)))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_load_free(raw_load_ctx: *mut LoadContext) -> *mut XmlState {
+    assert!(!raw_load_ctx.is_null());
+
+    let load_ctx = &mut *raw_load_ctx;
+
+    let xml = load_ctx.xml as *mut _;
+
+    Box::from_raw(raw_load_ctx);
+
+    xml
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_load_write(
+    raw_load_ctx: *mut LoadContext,
+    buf: *const u8,
+    size: usize,
+) {
+    assert!(!raw_load_ctx.is_null());
+
+    let load_ctx = &mut *raw_load_ctx;
+    let slice = slice::from_raw_parts(buf, size);
+
+    load_ctx.write(slice);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_load_close(
+    raw_load_ctx: *mut LoadContext,
+    error: *mut *mut glib_sys::GError,
+) -> glib_sys::gboolean {
+    assert!(!raw_load_ctx.is_null());
+
+    let load_ctx = &mut *raw_load_ctx;
+
+    match load_ctx.close() {
+        Ok(()) => true.to_glib(),
+
+        Err(e) => {
+            match e {
+                ParseFromStreamError::CouldNotCreateParser => {
+                    set_gerror(error, 0, "Error creating XML parser");
+                }
+
+                ParseFromStreamError::IoError(e) => {
+                    if !error.is_null() {
+                        *error = e.to_glib_full() as *mut _;
+                    }
+                }
+
+                ParseFromStreamError::XmlParseError(s) => {
+                    set_gerror(error, 0, &s);
+                }
+            }
+
+            false.to_glib()
+        }
+    }
+}
diff --git a/rsvg_internals/src/xml2.rs b/rsvg_internals/src/xml2.rs
index 25d2e058..4525fc4b 100644
--- a/rsvg_internals/src/xml2.rs
+++ b/rsvg_internals/src/xml2.rs
@@ -163,14 +163,6 @@ pub type xmlInputCloseCallback = Option<unsafe extern "C" fn(
 pub type xmlCharEncoding = libc::c_int;
 
 extern "C" {
-    pub fn xmlCreatePushParserCtxt(
-        sax: xmlSAXHandlerPtr,
-        user_data: *mut libc::c_void,
-        chunk: *const libc::c_char,
-        size: libc::c_int,
-        filename: *const libc::c_char,
-    ) -> xmlParserCtxtPtr;
-
     pub fn xmlCreateIOParserCtxt(
         sax: xmlSAXHandlerPtr,
         user_data: *mut libc::c_void,
@@ -180,13 +172,6 @@ extern "C" {
         enc: xmlCharEncoding,
     ) -> xmlParserCtxtPtr;
 
-    pub fn xmlParseChunk(
-        ctxt: xmlParserCtxtPtr,
-        chunk: *const libc::c_char,
-        size: libc::c_int,
-        terminate: libc::c_int,
-    ) -> libc::c_int;
-
     pub fn xmlParseDocument(ctxt: xmlParserCtxtPtr) -> libc::c_int;
 
     pub fn xmlFreeDoc(doc: xmlDocPtr);
diff --git a/rsvg_internals/src/xml2_load.rs b/rsvg_internals/src/xml2_load.rs
index 9cf822fb..63eb61a0 100644
--- a/rsvg_internals/src/xml2_load.rs
+++ b/rsvg_internals/src/xml2_load.rs
@@ -410,7 +410,7 @@ pub fn xml_state_parse_from_stream(
         .and_then(|parser| parser.parse())
 }
 
-fn xml_state_load_from_possibly_compressed_stream(
+pub fn xml_state_load_from_possibly_compressed_stream(
     xml: &mut XmlState,
     unlimited_size: bool,
     stream: gio::InputStream,


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