[librsvg: 2/18] Notify the XmlState when libxml2 finds a parsing error



commit 48d26793711d630e20074c860b563f7650aac0f5
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Nov 22 16:50:20 2018 -0600

    Notify the XmlState when libxml2 finds a parsing error
    
    It will then keep itself in a ContextKind::FatalError state, and no-op
    if further XML events come in.

 librsvg/rsvg-load.c       |  5 ++++-
 rsvg_internals/src/lib.rs |  1 +
 rsvg_internals/src/xml.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)
---
diff --git a/librsvg/rsvg-load.c b/librsvg/rsvg-load.c
index 35fea27e..92e7833d 100644
--- a/librsvg/rsvg-load.c
+++ b/librsvg/rsvg-load.c
@@ -58,7 +58,7 @@ extern void rsvg_xml_state_steal_result(RsvgXmlState *xml,
 extern void rsvg_xml_state_start_element(RsvgXmlState *xml, RsvgHandle *handle, const char *name, 
RsvgPropertyBag atts);
 extern void rsvg_xml_state_end_element(RsvgXmlState *xml, RsvgHandle *handle, 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);
 
 /* Holds the XML parsing state */
 typedef struct {
@@ -435,6 +435,7 @@ sax_get_parameter_entity_cb (void *data, const xmlChar * name)
 static void
 sax_error_cb (void *data, const char *msg, ...)
 {
+    RsvgLoad *load = data;
     va_list args;
     char *buf;
 
@@ -442,6 +443,8 @@ sax_error_cb (void *data, const char *msg, ...)
     g_vasprintf (&buf, msg, args);
     va_end (args);
 
+    rsvg_xml_state_error (load->xml.rust_state, buf);
+
     g_free (buf);
 }
 
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index ffd5dd9a..0bdc2679 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -68,6 +68,7 @@ pub use structure::rsvg_node_svg_get_size;
 pub use xml::{
     rsvg_xml_state_characters,
     rsvg_xml_state_end_element,
+    rsvg_xml_state_error,
     rsvg_xml_state_free,
     rsvg_xml_state_new,
     rsvg_xml_state_start_element,
diff --git a/rsvg_internals/src/xml.rs b/rsvg_internals/src/xml.rs
index a5cec38a..20ca7c84 100644
--- a/rsvg_internals/src/xml.rs
+++ b/rsvg_internals/src/xml.rs
@@ -1,5 +1,6 @@
 use encoding::label::encoding_from_whatwg_label;
 use encoding::DecoderTrap;
+use glib::translate::*;
 use libc;
 use std;
 use std::mem;
@@ -36,6 +37,9 @@ enum ContextKind {
 
     // Insie <xi::fallback>
     XIncludeFallback(XIncludeContext),
+
+    // An XML parsing error was found.  We will no-op upon any further XML events.
+    FatalError,
 }
 
 #[derive(Clone)]
@@ -110,6 +114,10 @@ impl XmlState {
     pub fn start_element(&mut self, handle: *mut RsvgHandle, name: &str, pbag: &PropertyBag) {
         let context = self.context.clone();
 
+        if let ContextKind::FatalError = context.kind {
+            return;
+        }
+
         let new_context = match context.kind {
             ContextKind::Start => self.element_creation_start_element(handle, name, pbag),
             ContextKind::ElementCreation => self.element_creation_start_element(handle, name, pbag),
@@ -118,6 +126,8 @@ impl XmlState {
             ContextKind::XIncludeFallback(ref ctx) => {
                 self.xinclude_fallback_start_element(&ctx, handle, name, pbag)
             }
+
+            ContextKind::FatalError => unreachable!(),
         };
 
         self.push_context(new_context);
@@ -126,6 +136,10 @@ impl XmlState {
     pub fn end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
         let context = self.context.clone();
 
+        if let ContextKind::FatalError = context.kind {
+            return;
+        }
+
         assert!(context.element_name == name);
 
         match context.kind {
@@ -134,6 +148,7 @@ impl XmlState {
             ContextKind::XInclude(_) => (),
             ContextKind::UnsupportedXIncludeChild => (),
             ContextKind::XIncludeFallback(_) => (),
+            ContextKind::FatalError => unreachable!(),
         }
 
         // We can unwrap since start_element() always adds a context to the stack
@@ -143,15 +158,31 @@ impl XmlState {
     pub fn characters(&mut self, text: &str) {
         let context = self.context.clone();
 
+        if let ContextKind::FatalError = context.kind {
+            return;
+        }
+
         match context.kind {
             ContextKind::Start => panic!("characters: XML handler stack is empty!?"),
             ContextKind::ElementCreation => self.element_creation_characters(text),
             ContextKind::XInclude(_) => (),
             ContextKind::UnsupportedXIncludeChild => (),
             ContextKind::XIncludeFallback(ref ctx) => self.xinclude_fallback_characters(&ctx, text),
+            ContextKind::FatalError => unreachable!(),
         }
     }
 
+    pub fn error(&mut self, msg: &str) {
+        // FIXME: aggregate the errors and expose them to the public result
+
+        println!("XML error: {}", msg);
+
+        self.push_context(Context {
+            element_name: "".to_string(),
+            kind: ContextKind::FatalError,
+        });
+    }
+
     fn element_creation_start_element(
         &mut self,
         handle: *mut RsvgHandle,
@@ -473,3 +504,16 @@ pub extern "C" fn rsvg_xml_state_characters(
 
     xml.characters(utf8);
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_xml_state_error(xml: *mut RsvgXmlState, msg: *const libc::c_char) {
+    assert!(!xml.is_null());
+    let xml = &mut *(xml as *mut XmlState);
+
+    assert!(!msg.is_null());
+    // Unlike the functions that take UTF-8 validated strings from
+    // libxml2, I don't trust error messages to be validated.
+    let msg: String = from_glib_none(msg);
+
+    xml.error(&msg);
+}


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