[librsvg: 2/3] Port data: url parsing to Rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/3] Port data: url parsing to Rust
- Date: Sun, 18 Nov 2018 10:36:31 +0000 (UTC)
commit d9464d20108ee6adb322cfa12fd849d637e5d783
Author: Federico Mena Quintero <federico gnome org>
Date: Sun Nov 18 03:23:39 2018 -0600
Port data: url parsing to Rust
This uses the data-url crate. One change in behavior is that data-url
is strict about data: URLs having a MIME-type chunk in them. This
will be an apparent regression from issue #152, which requested that
image data be sniffed if a data: URL doesn't have a MIME-type.
However, https://fetch.spec.whatwg.org/#data-urls indeed indicates
that data: URLs without a MIME-type are invalid.
This removes the test files for issue #152, since they are expected to
fail now.
Cargo.lock | 10 +++
Makefile.am | 1 +
librsvg/rsvg-io.c | 95 +--------------------
rsvg_internals/Cargo.toml | 1 +
rsvg_internals/src/error.rs | 23 +++++
rsvg_internals/src/io.rs | 63 ++++++++++++++
rsvg_internals/src/lib.rs | 4 +
.../bugs/152-image-data-with-no-mimetype-ref.png | Bin 184 -> 0 bytes
.../bugs/152-image-data-with-no-mimetype.svg | 7 --
9 files changed, 105 insertions(+), 99 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 1c0a1651..37be5da3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -276,6 +276,14 @@ dependencies = [
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "data-url"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "downcast-rs"
version = "1.0.3"
@@ -929,6 +937,7 @@ dependencies = [
"cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"criterion 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1252,6 +1261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cssparser-macros 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" =
"b16e382d9b983fdb9ac6a36b37fdeb84ce3ea81f749febfee3463cfa7f24275e"
"checksum csv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" =
"6d54f6b0fd69128a2894b1a3e57af5849a0963c1cc77b165d30b896e40296452"
"checksum csv-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" =
"4dd8e6d86f7ba48b4276ef1317edc8cc36167546d8972feb4a2b5fec0b374105"
+"checksum data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c"
"checksum downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" =
"18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" =
"6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum dtoa-short 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" =
"59020b8513b76630c49d918c33db9f4c91638e7d3404a28084083b87e33f76f2"
diff --git a/Makefile.am b/Makefile.am
index 2b5a2827..31987c62 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -84,6 +84,7 @@ RUST_SRC = \
rsvg_internals/src/gradient.rs \
rsvg_internals/src/handle.rs \
rsvg_internals/src/image.rs \
+ rsvg_internals/src/io.rs \
rsvg_internals/src/iri.rs \
rsvg_internals/src/length.rs \
rsvg_internals/src/lib.rs \
diff --git a/librsvg/rsvg-io.c b/librsvg/rsvg-io.c
index de6d61f8..965be423 100644
--- a/librsvg/rsvg-io.c
+++ b/librsvg/rsvg-io.c
@@ -28,101 +28,12 @@
#include <string.h>
-/* Copied from soup-request-data.c (LGPL2+):
- * Copyright (C) 2009, 2010 Red Hat, Inc.
- * Copyright (C) 2010 Igalia, S.L.
- * and from soup-uri.c:
- * Copyright 1999-2003 Ximian, Inc.
- */
-
-#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
-#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
-
-static char *
-uri_decoded_copy (const char *part,
- gsize length)
-{
- unsigned char *s, *d;
- char *decoded = g_strndup (part, length);
-
- s = d = (unsigned char *)decoded;
- do {
- if (*s == '%') {
- if (!g_ascii_isxdigit (s[1]) ||
- !g_ascii_isxdigit (s[2])) {
- *d++ = *s;
- continue;
- }
- *d++ = HEXCHAR (s);
- s += 2;
- } else {
- *d++ = *s;
- }
- } while (*s++);
-
- return decoded;
-}
-
-#define BASE64_INDICATOR ";base64"
-#define BASE64_INDICATOR_LEN (sizeof (";base64") - 1)
-
-static char *
+/* Defined in rsvg_internals/src/io.rs */
+extern char *
rsvg_decode_data_uri (const char *uri,
char **out_mime_type,
gsize *out_len,
- GError **error)
-{
- const char *comma, *start, *end;
- char *mime_type;
- char *data;
- gsize data_len;
- gboolean base64 = FALSE;
-
- g_assert (out_len != NULL);
- g_assert (strncmp (uri, "data:", 5) == 0);
-
- mime_type = NULL;
- start = uri + 5;
- comma = strchr (start, ',');
-
- if (comma && comma != start) {
- /* Deal with MIME type / params */
- if (comma >= start + BASE64_INDICATOR_LEN &&
- !g_ascii_strncasecmp (comma - BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
- end = comma - BASE64_INDICATOR_LEN;
- base64 = TRUE;
- } else {
- end = comma;
- }
-
- if (end != start) {
- mime_type = uri_decoded_copy (start, end - start);
- }
- }
-
- if (comma)
- start = comma + 1;
-
- if (*start) {
- data = uri_decoded_copy (start, strlen (start));
-
- if (base64)
- data = (char *) g_base64_decode_inplace (data, &data_len);
- else
- data_len = strlen (data);
- } else {
- data = NULL;
- data_len = 0;
- }
-
- if (out_mime_type)
- *out_mime_type = mime_type;
- else
- g_free (mime_type);
-
- *out_len = data_len;
- return data;
-}
+ GError **error);
static char *
rsvg_acquire_file_data (const char *uri,
diff --git a/rsvg_internals/Cargo.toml b/rsvg_internals/Cargo.toml
index 56826122..b6e8d44f 100644
--- a/rsvg_internals/Cargo.toml
+++ b/rsvg_internals/Cargo.toml
@@ -23,6 +23,7 @@ phf_codegen = "0.7.21"
cairo-rs = "0.5.0"
cairo-sys-rs = "0.7.0"
cssparser = "0.25.1"
+data-url = "0.1"
downcast-rs = "^1.0.0"
encoding = "0.2.33"
float-cmp = "0.4.0"
diff --git a/rsvg_internals/src/error.rs b/rsvg_internals/src/error.rs
index 4ced1898..5e5505ea 100644
--- a/rsvg_internals/src/error.rs
+++ b/rsvg_internals/src/error.rs
@@ -4,6 +4,9 @@ use std::fmt;
use cairo;
use cssparser::BasicParseError;
use glib;
+use glib::translate::*;
+use glib_sys;
+use libc;
use attributes::Attribute;
use parsers::ParseError;
@@ -103,6 +106,8 @@ impl From<cairo::Status> for RenderingError {
#[derive(Clone)]
pub enum LoadingError {
+ // Could not parse data: URL
+ BadDataUrl,
Cairo(cairo::Status),
EmptyData,
Glib(glib::Error),
@@ -123,6 +128,24 @@ impl From<glib::Error> for LoadingError {
}
}
+extern "C" {
+ fn rsvg_error_quark() -> glib_sys::GQuark;
+}
+
+pub fn set_gerror(err: *mut *mut glib_sys::GError, code: u32, msg: &str) {
+ unsafe {
+ // this is RSVG_ERROR_FAILED, the only error code available in RsvgError
+ assert!(code == 0);
+
+ glib_sys::g_set_error_literal(
+ err,
+ rsvg_error_quark(),
+ code as libc::c_int,
+ msg.to_glib_none().0,
+ );
+ }
+}
+
#[cfg(test)]
pub fn is_parse_error<T>(r: &Result<T, ValueErrorKind>) -> bool {
match *r {
diff --git a/rsvg_internals/src/io.rs b/rsvg_internals/src/io.rs
new file mode 100644
index 00000000..d534ae2e
--- /dev/null
+++ b/rsvg_internals/src/io.rs
@@ -0,0 +1,63 @@
+use data_url;
+use glib_sys;
+use libc;
+
+use glib::translate::*;
+use std::ptr;
+
+use error::{set_gerror, LoadingError};
+use handle::BinaryData;
+use util::utf8_cstr;
+
+fn decode_data_uri(uri: &str) -> Result<BinaryData, LoadingError> {
+ let data_url = data_url::DataUrl::process(uri).map_err(|_| LoadingError::BadDataUrl)?;
+
+ let mime_type = data_url.mime_type().to_string();
+
+ let (bytes, _fragment_id) = data_url
+ .decode_to_vec()
+ .map_err(|_| LoadingError::BadDataUrl)?;
+
+ Ok(BinaryData {
+ data: bytes,
+ content_type: Some(mime_type),
+ })
+}
+
+#[no_mangle]
+pub fn rsvg_decode_data_uri(
+ uri: *const libc::c_char,
+ out_mime_type: *mut *mut libc::c_char,
+ out_size: *mut usize,
+ error: *mut *mut glib_sys::GError,
+) -> *mut libc::c_char {
+ unsafe {
+ assert!(!out_mime_type.is_null());
+ assert!(!out_size.is_null());
+
+ let uri = utf8_cstr(uri);
+
+ match decode_data_uri(uri) {
+ Ok(binary_data) => {
+ *out_mime_type = binary_data.content_type.to_glib_full();
+ *out_size = binary_data.data.len();
+
+ if !error.is_null() {
+ *error = ptr::null_mut();
+ }
+
+ ToGlibContainerFromSlice::to_glib_full_from_slice(&binary_data.data)
+ as *mut libc::c_char
+ }
+
+ Err(_) => {
+ *out_mime_type = ptr::null_mut();
+ *out_size = 0;
+
+ set_gerror(error, 0, "could not decode data: URL");
+
+ ptr::null_mut()
+ }
+ }
+ }
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 520d7e68..627ddf0f 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -5,6 +5,7 @@
extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
+extern crate data_url;
extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
@@ -42,6 +43,8 @@ pub use drawing_ctx::{
rsvg_drawing_ctx_new,
};
+pub use io::rsvg_decode_data_uri;
+
pub use node::rsvg_node_unref;
pub use tree::{
@@ -99,6 +102,7 @@ mod font_props;
mod gradient;
mod handle;
mod image;
+mod io;
mod iri;
mod length;
mod link;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]