[librsvg: 4/5] (#335): Return an error when the toplevel element is not <svg>



commit 9045723a23ac609e783f7932ebee9b9b1c7253fd
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Sep 13 10:16:49 2018 -0500

    (#335): Return an error when the toplevel element is not <svg>
    
    We add a simple validation function for the root of the tree.
    
    https://gitlab.gnome.org/GNOME/librsvg/issues/335

 librsvg/rsvg-handle.c      | 42 ++++++++++++++++++++++++++++++++++++++----
 librsvg/rsvg-private.h     |  4 ++++
 rsvg_internals/src/lib.rs  |  1 +
 rsvg_internals/src/tree.rs | 14 +++++++++++++-
 4 files changed, 56 insertions(+), 5 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 72bcf492..25eca410 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -654,7 +654,9 @@ rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **
 {
     RsvgHandlePrivate *priv;
 
+    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     rsvg_return_val_if_fail (handle, FALSE, error);
+
     priv = handle->priv;
 
     rsvg_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START
@@ -673,19 +675,49 @@ rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **
 }
 
 static gboolean
-finish_load (RsvgHandle *handle, gboolean was_successful)
+tree_is_valid (RsvgTree *tree, GError **error)
 {
+    if (!tree) {
+        g_set_error (error, RSVG_ERROR, RSVG_ERROR_FAILED, _("SVG has no elements"));
+        return FALSE;
+    }
+
+    if (!rsvg_tree_root_is_svg (tree)) {
+        g_set_error (error, RSVG_ERROR, RSVG_ERROR_FAILED, _("root element is not <svg>"));
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+finish_load (RsvgHandle *handle, gboolean was_successful, GError **error)
+{
+    RsvgTree *tree = NULL;
+
     g_assert (handle->priv->load != NULL);
     g_assert (handle->priv->tree == NULL);
 
     if (was_successful) {
+        g_assert (error == NULL || *error == NULL);
+
+        tree = rsvg_load_steal_tree (handle->priv->load);
+        was_successful = tree_is_valid (tree, error);
+        if (!was_successful) {
+            rsvg_tree_free (tree);
+            tree = NULL;
+        }
+    }
+
+    if (was_successful) {
+        g_assert (tree != NULL);
         handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_OK;
-        handle->priv->tree = rsvg_load_steal_tree (handle->priv->load);
     } else {
         handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_ERROR;
     }
 
     g_clear_pointer (&handle->priv->load, rsvg_load_free);
+    handle->priv->tree = tree;
 
     return was_successful;
 }
@@ -708,7 +740,9 @@ rsvg_handle_close (RsvgHandle *handle, GError **error)
     gboolean read_successfully;
     gboolean result;
 
+    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     rsvg_return_val_if_fail (handle, FALSE, error);
+
     priv = handle->priv;
 
     if (priv->hstate == RSVG_HANDLE_STATE_CLOSED_OK
@@ -718,7 +752,7 @@ rsvg_handle_close (RsvgHandle *handle, GError **error)
     }
 
     read_successfully = rsvg_load_close (priv->load, error);
-    result = finish_load (handle, read_successfully);
+    result = finish_load (handle, read_successfully, error);
 
     return result;
 }
@@ -769,7 +803,7 @@ rsvg_handle_read_stream_sync (RsvgHandle   *handle,
     priv->load = rsvg_load_new (handle, (priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) != 0);
 
     read_successfully = rsvg_load_read_stream_sync (priv->load, stream, cancellable, error);
-    result = finish_load (handle, read_successfully);
+    result = finish_load (handle, read_successfully, error);
 
     priv->load = saved_load;
 
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index 4e681a0e..4efdebbe 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -180,6 +180,10 @@ RsvgNode *rsvg_tree_get_root (RsvgTree *tree);
 G_GNUC_INTERNAL
 gboolean rsvg_tree_is_root (RsvgTree *tree, RsvgNode *node);
 
+/* Implemented in rsvg_internals/src/tree.rs */
+G_GNUC_INTERNAL
+gboolean rsvg_tree_root_is_svg (RsvgTree *tree);
+
 /* Implemented in rsvg_internals/src/tree.rs */
 G_GNUC_INTERNAL
 void rsvg_tree_cascade (RsvgTree *tree);
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 5716a93c..c9ff411a 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -57,6 +57,7 @@ pub use tree::{
     rsvg_tree_get_root,
     rsvg_tree_is_root,
     rsvg_tree_new,
+    rsvg_tree_root_is_svg,
 };
 
 pub use parsers::rsvg_css_parse_number_optional_number;
diff --git a/rsvg_internals/src/tree.rs b/rsvg_internals/src/tree.rs
index 2c68e8f6..4345cc5d 100644
--- a/rsvg_internals/src/tree.rs
+++ b/rsvg_internals/src/tree.rs
@@ -4,7 +4,7 @@ use glib_sys;
 use std::cell::Cell;
 use std::rc::Rc;
 
-use node::{box_node, Node, RsvgNode};
+use node::{box_node, Node, NodeType, RsvgNode};
 use state::ComputedValues;
 
 pub enum RsvgTree {}
@@ -29,6 +29,10 @@ impl Tree {
             self.root.cascade(&values);
         }
     }
+
+    fn root_is_svg(&self) -> bool {
+        self.root.get_type() == NodeType::Svg
+    }
 }
 
 #[no_mangle]
@@ -76,3 +80,11 @@ pub extern "C" fn rsvg_tree_is_root(
 
     Rc::ptr_eq(&tree.root, node).to_glib()
 }
+
+#[no_mangle]
+pub extern "C" fn rsvg_tree_root_is_svg(tree: *const RsvgTree) -> glib_sys::gboolean {
+    assert!(!tree.is_null());
+    let tree = unsafe { &*(tree as *const Tree) };
+
+    tree.root_is_svg().to_glib()
+}


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