[librsvg] Handle: move the base_url here



commit 56f787b311b027c340bc3de4494bd6a3b09e2fb6
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Nov 26 13:34:52 2018 -0600

    Handle: move the base_url here
    
    We keep it as a RefCell<Option<Url>> for the following reasons:
    
    - Url, from the url crate, because it does validation and will let us
      resolve relative hrefs later.
    
    - Option, because the base_url may not be set at all.
    
    - RefCell - interior mutability; the handle allows setting this after
      creation.

 librsvg/rsvg-handle.c            | 42 +++++++++++++++++++---------
 librsvg/rsvg-private.h           | 12 ++++++--
 rsvg_internals/src/font_props.rs |  3 +-
 rsvg_internals/src/handle.rs     | 60 ++++++++++++++++++++++++++++++++++++----
 rsvg_internals/src/lib.rs        |  8 +++++-
 tests/api.c                      | 40 +++++++++++++++++++++++++++
 6 files changed, 142 insertions(+), 23 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index eab2d59b..1241e7e3 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -192,7 +192,6 @@ rsvg_handle_dispose (GObject *instance)
     g_clear_pointer (&self->priv->css_styles, rsvg_css_styles_free);
     g_clear_pointer (&self->priv->tree, rsvg_tree_free);
     g_clear_pointer (&self->priv->base_uri, g_free);
-    g_clear_object (&self->priv->base_gfile);
 
 #ifdef HAVE_PANGOFT2
     g_clear_pointer (&self->priv->font_config_for_testing, FcConfigDestroy);
@@ -899,19 +898,28 @@ rsvg_handle_set_base_gfile (RsvgHandle *handle,
                             GFile      *base_file)
 {
     RsvgHandlePrivate *priv;
+    char *uri;
+    GFile *real_base_file;
 
     g_return_if_fail (RSVG_IS_HANDLE (handle));
     g_return_if_fail (G_IS_FILE (base_file));
 
     priv = handle->priv;
 
-    g_object_ref (base_file);
-    if (priv->base_gfile)
-        g_object_unref (priv->base_gfile);
-    priv->base_gfile = base_file;
+    uri = g_file_get_uri (base_file);
+    rsvg_handle_rust_set_base_url (priv->rust_handle, uri);
+    g_free (uri);
+
+    /* Obtain the sanitized version */
 
+    real_base_file = rsvg_handle_rust_get_base_gfile (priv->rust_handle);
     g_free (priv->base_uri);
-    priv->base_uri = g_file_get_uri (base_file);
+
+    if (real_base_file) {
+        priv->base_uri = g_file_get_uri (real_base_file);
+    } else {
+        priv->base_uri = NULL;
+    }
 }
 
 /**
@@ -1538,15 +1546,19 @@ rsvg_handle_resolve_uri (RsvgHandle *handle,
 {
     RsvgHandlePrivate *priv = handle->priv;
     char *scheme, *resolved_uri;
+    GFile *base_gfile;
     GFile *base, *resolved;
 
     if (uri == NULL)
         return NULL;
 
+    base_gfile = rsvg_handle_rust_get_base_gfile (priv->rust_handle);
+
     scheme = g_uri_parse_scheme (uri);
     if (scheme != NULL ||
-        priv->base_gfile == NULL ||
-        (base = g_file_get_parent (priv->base_gfile)) == NULL) {
+        base_gfile == NULL ||
+        (base = g_file_get_parent (base_gfile)) == NULL) {
+        g_object_unref (base_gfile);
         g_free (scheme);
         return g_strdup (uri);
     }
@@ -1556,6 +1568,7 @@ rsvg_handle_resolve_uri (RsvgHandle *handle,
 
     g_free (scheme);
     g_object_unref (base);
+    g_object_unref (base_gfile);
     g_object_unref (resolved);
 
     return resolved_uri;
@@ -1591,14 +1604,17 @@ rsvg_realpath_utf8 (const char *filename, const char *unused)
 #endif
 
 static gboolean
-allow_load (GFile *base_gfile, const char *uri, GError **error)
+allow_load (RsvgHandle *handle, const char *uri, GError **error)
 {
+    GFile *base_gfile;
     GFile *base;
     char *path, *dir;
     char *scheme = NULL, *cpath = NULL, *cdir = NULL;
 
     g_assert (error == NULL || *error == NULL);
 
+    base_gfile = rsvg_handle_rust_get_base_gfile (handle->priv->rust_handle);
+
     scheme = g_uri_parse_scheme (uri);
 
     /* Not a valid URI */
@@ -1655,12 +1671,14 @@ allow_load (GFile *base_gfile, const char *uri, GError **error)
     /* Allow load! */
 
  allow:
+    g_object_unref (base_gfile);
     g_free (scheme);
     free (cpath);
     free (cdir);
     return TRUE;
 
  deny:
+    g_object_unref (base_gfile);
     g_free (scheme);
     free (cpath);
     free (cdir);
@@ -1685,13 +1703,12 @@ _rsvg_handle_acquire_data (RsvgHandle *handle,
                            gsize *len,
                            GError **error)
 {
-    RsvgHandlePrivate *priv = handle->priv;
     char *uri;
     char *data;
 
     uri = rsvg_handle_resolve_uri (handle, href);
 
-    if (allow_load (priv->base_gfile, uri, error)) {
+    if (allow_load (handle, uri, error)) {
         data = rsvg_io_acquire_data (uri,
                                      content_type,
                                      len,
@@ -1716,13 +1733,12 @@ _rsvg_handle_acquire_stream (RsvgHandle *handle,
                              const char *href,
                              GError **error)
 {
-    RsvgHandlePrivate *priv = handle->priv;
     char *uri;
     GInputStream *stream;
 
     uri = rsvg_handle_resolve_uri (handle, href);
 
-    if (allow_load (priv->base_gfile, uri, error)) {
+    if (allow_load (handle, uri, error)) {
         stream = rsvg_io_acquire_stream (uri, handle->priv->cancellable, error);
     } else {
         stream = NULL;
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index b79e3f53..f9a5b337 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -110,8 +110,7 @@ struct RsvgHandlePrivate {
     double dpi_x;
     double dpi_y;
 
-    gchar *base_uri;
-    GFile *base_gfile;
+    gchar *base_uri; // Keep this here; since rsvg_handle_get_base_uri() returns a const char *
 
     gboolean in_loop;          /* see get_dimension() */
 
@@ -272,6 +271,15 @@ RsvgHandleRust *rsvg_handle_rust_new (void);
 G_GNUC_INTERNAL
 void rsvg_handle_rust_free (RsvgHandleRust *raw_handle);
 
+/* Implemented in rsvg_internals/src/handle.rs */
+G_GNUC_INTERNAL
+void rsvg_handle_rust_set_base_url (RsvgHandleRust *raw_handle,
+                                    const char *uri);
+
+/* Implemented in rsvg_internals/src/handle.rs */
+G_GNUC_INTERNAL
+GFile *rsvg_handle_rust_get_base_gfile (RsvgHandleRust *raw_handle);
+
 G_GNUC_INTERNAL
 RsvgHandle *rsvg_handle_load_extern (RsvgHandle *handle,
                                      const char *uri);
diff --git a/rsvg_internals/src/font_props.rs b/rsvg_internals/src/font_props.rs
index 317bd83b..936937b6 100644
--- a/rsvg_internals/src/font_props.rs
+++ b/rsvg_internals/src/font_props.rs
@@ -169,8 +169,7 @@ impl Parse for FontWeightSpec {
                 800 => Ok(FontWeightSpec::W800),
                 900 => Ok(FontWeightSpec::W900),
                 _ => Err(()),
-            })
-        {
+            }) {
             Ok(r)
         } else {
             Err(ValueErrorKind::Parse(ParseError::new(
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index ed53bc79..720dee56 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -1,14 +1,16 @@
+use std::cell::RefCell;
 use std::ptr;
 
 use cairo::{ImageSurface, Status};
 use cairo_sys;
 use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
-use gio::InputStream;
+use gio::{File as GFile, InputStream};
 use gio_sys;
 use glib;
 use glib::translate::*;
 use glib_sys;
 use libc;
+use url::Url;
 
 use css::{self, CssStyles, RsvgCssStyles};
 use defs::{Defs, RsvgDefs};
@@ -20,7 +22,17 @@ pub enum RsvgHandle {}
 
 pub enum RsvgHandleRust {}
 
-struct Handle {}
+struct Handle {
+    base_url: RefCell<Option<Url>>,
+}
+
+impl Handle {
+    fn new() -> Handle {
+        Handle {
+            base_url: RefCell::new(None),
+        }
+    }
+}
 
 #[allow(improper_ctypes)]
 extern "C" {
@@ -252,7 +264,7 @@ pub unsafe extern "C" fn rsvg_handle_load_css(handle: *mut RsvgHandle, href: *co
 
 #[no_mangle]
 pub unsafe extern "C" fn rsvg_handle_rust_new() -> *mut RsvgHandleRust {
-    Box::into_raw(Box::new(Handle {})) as *mut RsvgHandleRust
+    Box::into_raw(Box::new(Handle::new())) as *mut RsvgHandleRust
 }
 
 #[no_mangle]
@@ -263,7 +275,45 @@ pub unsafe extern "C" fn rsvg_handle_rust_free(raw_handle: *mut RsvgHandleRust)
 }
 
 fn get_rust_handle(handle: *const RsvgHandle) -> *mut Handle {
-    unsafe {
-        rsvg_handle_get_rust(handle) as *mut Handle
+    unsafe { rsvg_handle_get_rust(handle) as *mut Handle }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_handle_rust_set_base_url(
+    raw_handle: *const RsvgHandleRust,
+    uri: *const libc::c_char,
+) {
+    let handle = &*(raw_handle as *const Handle);
+
+    assert!(!uri.is_null());
+    let uri: String = from_glib_none(uri);
+
+    let url = match Url::parse(&uri) {
+        Ok(u) => u,
+
+        Err(e) => {
+            rsvg_log!(
+                "not setting base_uri to \"{}\" since it is invalid: {}",
+                uri,
+                e
+            );
+            return;
+        }
+    };
+
+    rsvg_log!("setting base_uri to \"{}\"", url);
+    *handle.base_url.borrow_mut() = Some(url);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_handle_rust_get_base_gfile(
+    raw_handle: *const RsvgHandleRust,
+) -> *mut gio_sys::GFile {
+    let handle = &*(raw_handle as *const Handle);
+
+    match *handle.base_url.borrow() {
+        None => ptr::null_mut(),
+
+        Some(ref url) => GFile::new_for_uri(url.as_str()).to_glib_full(),
     }
 }
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 56a80575..6ad88a6b 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -46,7 +46,13 @@ pub use drawing_ctx::{
     rsvg_drawing_ctx_new,
 };
 
-pub use handle::{rsvg_handle_load_css, rsvg_handle_rust_free, rsvg_handle_rust_new};
+pub use handle::{
+    rsvg_handle_load_css,
+    rsvg_handle_rust_free,
+    rsvg_handle_rust_get_base_gfile,
+    rsvg_handle_rust_new,
+    rsvg_handle_rust_set_base_url,
+};
 
 pub use io::{
     rsvg_decode_data_uri,
diff --git a/tests/api.c b/tests/api.c
index 9ea3ae97..75d3883c 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -228,6 +228,44 @@ auto_generated (void)
     g_assert_cmpstr (q.type_name, ==, "RsvgHandleFlags");
 }
 
+static void
+base_uri (void)
+{
+    RsvgHandle *handle = rsvg_handle_new ();
+    const char *uri;
+
+    uri = rsvg_handle_get_base_uri (handle);
+    g_assert (uri == NULL);
+
+    rsvg_handle_set_base_uri (handle, "file:///foo/bar.svg");
+    uri = rsvg_handle_get_base_uri (handle);
+
+    g_assert_cmpstr (uri, ==, "file:///foo/bar.svg");
+
+    g_object_unref (handle);
+}
+
+static void
+base_gfile (void)
+{
+    RsvgHandle *handle = rsvg_handle_new ();
+    GFile *file;
+    const char *uri;
+
+    uri = rsvg_handle_get_base_uri (handle);
+    g_assert (uri == NULL);
+
+    file = g_file_new_for_uri ("file:///foo/bar.svg");
+
+    rsvg_handle_set_base_gfile (handle, file);
+    uri = rsvg_handle_get_base_uri (handle);
+
+    g_assert_cmpstr (uri, ==, "file:///foo/bar.svg");
+
+    g_object_unref (file);
+    g_object_unref (handle);
+}
+
 static void
 handle_write_close_free (void)
 {
@@ -594,6 +632,8 @@ main (int argc, char **argv)
     g_test_add_func ("/api/set_dpi", set_dpi);
     g_test_add_func ("/api/error_quark", error_quark);
     g_test_add_func ("/api/auto_generated", auto_generated);
+    g_test_add_func ("/api/base_uri", base_uri);
+    g_test_add_func ("/api/base_gfile", base_gfile);
     g_test_add_func ("/api/handle_write_close_free", handle_write_close_free);
     g_test_add_func ("/api/handle_new_from_file", handle_new_from_file);
     g_test_add_func ("/api/handle_new_from_data", handle_new_from_data);


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