[librsvg] all: Add option to parse huge SVG XML files
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] all: Add option to parse huge SVG XML files
- Date: Wed, 18 Jun 2014 18:11:10 +0000 (UTC)
commit aa1f447e2741d7b5c399ec1f8bf9cfdce81d5506
Author: Christian Persch <chpe gnome org>
Date: Wed Jun 18 20:08:34 2014 +0200
all: Add option to parse huge SVG XML files
For security reasons, newer libxml versions applies limits that huge
SVG files exceed and thus fail parsing. Add an RSVG_HANDLE_FLAG_UNLIMITED
flag that uses XML_PARSE_HUGE to allow parsing these files again.
Note: for security reasons, this flag should ONLY be used on trusted input!
https://bugzilla.gnome.org/show_bug.cgi?id=710310
Makefile.am | 5 +--
configure.in | 2 +
rsvg-base.c | 23 ++++++++++++++--
rsvg-convert.c | 76 ++++++++++++++++++++------------------------------------
rsvg-css.h | 12 +++++++-
rsvg.h | 6 +++-
test-display.c | 10 ++++++-
7 files changed, 75 insertions(+), 59 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index e881100..5c3eab6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -119,15 +119,14 @@ rsvg_convert_CPPFLAGS = \
$(AM_CPPFLAGS)
rsvg_convert_CFLAGS =\
- $(LIBRSVG_CFLAGS) \
+ $(RSVG_CONVERT_CFLAGS) \
$(AM_CFLAGS)
rsvg_convert_LDFLAGS = $(AM_LDFLAGS)
rsvg_convert_LDADD = \
$(top_builddir)/librsvg- RSVG_API_MAJOR_VERSION@.la \
- $(LIBRSVG_LIBS) \
- $(GTHREAD_LIBS) \
+ $(RSVG_CONVERT_LIBS) \
$(LIBM)
rsvg_view_3_SOURCES = \
diff --git a/configure.in b/configure.in
index 69c2a4c..ac76716 100644
--- a/configure.in
+++ b/configure.in
@@ -111,6 +111,8 @@ PKG_CHECK_MODULES([GTHREAD],[gthread-2.0 >= $GLIB_REQUIRED])
PKG_CHECK_MODULES([GMODULE],[gmodule-2.0])
+PKG_CHECK_MODULES([RSVG_CONVERT],[gio-2.0 gio-unix-2.0 gdk-pixbuf-2.0 cairo pangocairo])
+
dnl ===========================================================================
AC_CHECK_FUNCS(strtok_r)
diff --git a/rsvg-base.c b/rsvg-base.c
index b1cc71a..683d607 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -523,6 +523,23 @@ rsvg_xinclude_handler_end (RsvgSaxHandler * self, const char *name)
}
}
+static void
+_rsvg_set_xml_parse_options(xmlParserCtxtPtr xml_parser,
+ RsvgHandle *ctx)
+{
+ xml_parser->options |= XML_PARSE_NONET;
+
+ if (ctx->priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) {
+#if LIBXML_VERSION > 20632
+ xml_parser->options |= XML_PARSE_HUGE;
+#endif
+ }
+
+#if LIBXML_VERSION > 20800
+ xml_parser->options |= XML_PARSE_BIG_LINES;
+#endif
+}
+
/* http://www.w3.org/TR/xinclude/ */
static void
rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
@@ -575,7 +592,7 @@ rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
goto fallback;
xml_parser = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, ctx, NULL, 0, NULL);
- xml_parser->options |= XML_PARSE_NONET;
+ _rsvg_set_xml_parse_options(xml_parser, ctx);
buffer = _rsvg_xml_input_buffer_new_from_stream (stream, NULL /* cancellable */,
XML_CHAR_ENCODING_NONE, &err);
g_object_unref (stream);
@@ -1115,7 +1132,7 @@ rsvg_handle_write_impl (RsvgHandle * handle, const guchar * buf, gsize count, GE
if (handle->priv->ctxt == NULL) {
handle->priv->ctxt = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, handle, NULL, 0,
rsvg_handle_get_base_uri (handle));
- handle->priv->ctxt->options |= XML_PARSE_NONET;
+ _rsvg_set_xml_parse_options(handle->priv->ctxt, handle);
/* if false, external entities work, but internal ones don't. if true, internal entities
work, but external ones don't. favor internal entities, in order to not cause a
@@ -1773,7 +1790,7 @@ rsvg_handle_read_stream_sync (RsvgHandle *handle,
if (priv->ctxt == NULL) {
priv->ctxt = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, handle, NULL, 0,
rsvg_handle_get_base_uri (handle));
- priv->ctxt->options |= XML_PARSE_NONET;
+ _rsvg_set_xml_parse_options(priv->ctxt, handle);
/* if false, external entities work, but internal ones don't. if true, internal entities
work, but external ones don't. favor internal entities, in order to not cause a
diff --git a/rsvg-convert.c b/rsvg-convert.c
index be86b45..276e789 100644
--- a/rsvg-convert.c
+++ b/rsvg-convert.c
@@ -34,10 +34,12 @@
#include <stdlib.h>
#include <string.h>
#include <locale.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gunixinputstream.h>
#include "rsvg-css.h"
#include "rsvg.h"
-#include "rsvg-private.h"
#include "rsvg-size-callback.h"
#ifdef CAIRO_HAS_PS_SURFACE
@@ -65,44 +67,6 @@ display_error (GError * err)
}
}
-static RsvgHandle *
-rsvg_handle_new_from_stdio_file (FILE * f, GError ** error)
-{
- RsvgHandle *handle;
- gchar *current_dir;
- gchar *base_uri;
-
- handle = rsvg_handle_new ();
-
- while (!feof (f)) {
- guchar buffer[4096];
- gsize length = fread (buffer, 1, sizeof (buffer), f);
-
- if (length > 0) {
- if (!rsvg_handle_write (handle, buffer, length, error)) {
- g_object_unref (handle);
- return NULL;
- }
- } else if (ferror (f)) {
- g_object_unref (handle);
- return NULL;
- }
- }
-
- if (!rsvg_handle_close (handle, error)) {
- g_object_unref (handle);
- return NULL;
- }
-
- current_dir = g_get_current_dir ();
- base_uri = g_build_filename (current_dir, "file.svg", NULL);
- rsvg_handle_set_base_uri (handle, base_uri);
- g_free (base_uri);
- g_free (current_dir);
-
- return handle;
-}
-
static void
rsvg_cairo_size_callback (int *width, int *height, gpointer data)
{
@@ -136,8 +100,8 @@ main (int argc, char **argv)
int keep_aspect_ratio = FALSE;
guint32 background_color = 0;
char *background_color_str = NULL;
- char *base_uri = NULL;
gboolean using_stdin = FALSE;
+ gboolean unlimited = FALSE;
GError *error = NULL;
int i;
@@ -146,6 +110,7 @@ main (int argc, char **argv)
RsvgHandle *rsvg;
cairo_surface_t *surface = NULL;
cairo_t *cr = NULL;
+ RsvgHandleFlags flags = RSVG_HANDLE_FLAGS_NONE;
RsvgDimensionData dimensions;
FILE *output_file = stdout;
@@ -172,8 +137,8 @@ main (int argc, char **argv)
N_("whether to preserve the aspect ratio [optional; defaults to FALSE]"), NULL},
{"background-color", 'b', 0, G_OPTION_ARG_STRING, &background_color_str,
N_("set the background color [optional; defaults to None]"), N_("[black, white, #abccee,
#aaa...]")},
+ {"unlimited", 'u', 0, G_OPTION_ARG_NONE, &unlimited, N_("Allow huge SVG files"), NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &bVersion, N_("show version information"), NULL},
- {"base-uri", 'b', 0, G_OPTION_ARG_STRING, &base_uri, N_("base uri"), NULL},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("[FILE...]")},
{NULL}
};
@@ -227,23 +192,36 @@ main (int argc, char **argv)
rsvg_set_default_dpi_x_y (dpi_x, dpi_y);
+ if (unlimited)
+ flags |= RSVG_HANDLE_FLAG_UNLIMITED;
+
for (i = 0; i < n_args; i++) {
+ GFile *file;
+ GInputStream *stream;
+
+ if (using_stdin) {
+ file = NULL;
+ stream = g_unix_input_stream_new (STDIN_FILENO, FALSE);
+ } else {
+ file = g_file_new_for_commandline_arg (args[i]);
+ stream = (GInputStream *) g_file_read (file, NULL, &error);
+ if (stream == NULL)
+ goto done;
+ }
- if (using_stdin)
- rsvg = rsvg_handle_new_from_stdio_file (stdin, &error);
- else
- rsvg = rsvg_handle_new_from_file (args[i], &error);
+ rsvg = rsvg_handle_new_from_stream_sync (stream, file, flags, NULL, &error);
- if (!rsvg) {
+ done:
+ g_clear_object (&stream);
+ g_clear_object (&file);
+
+ if (error != NULL) {
fprintf (stderr, _("Error reading SVG:"));
display_error (error);
fprintf (stderr, "\n");
exit (1);
}
- if (base_uri)
- rsvg_handle_set_base_uri (rsvg, base_uri);
-
/* in the case of multi-page output, all subsequent SVGs are scaled to the first's size */
rsvg_handle_set_size_callback (rsvg, rsvg_cairo_size_callback, &dimensions, NULL);
diff --git a/rsvg-css.h b/rsvg-css.h
index f6db946..6abeba9 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -27,8 +27,11 @@
#define RSVG_CSS_H
#include <glib.h>
+
+#ifdef RSVG_COMPILATION
#include <pango/pango.h>
#include "rsvg-private.h"
+#endif
G_BEGIN_DECLS
@@ -44,10 +47,13 @@ G_BEGIN_DECLS
#define RSVG_ASPECT_RATIO_XMAX_YMAX (1 << 8)
#define RSVG_ASPECT_RATIO_SLICE (1 << 31)
+/* This one is semi-public for mis-use in rsvg-convert */
+guint32 rsvg_css_parse_color (const char *str, gboolean * inherit);
+
+#ifdef RSVG_COMPILATION
+
G_GNUC_INTERNAL
int rsvg_css_parse_aspect_ratio (const char *str);
-/* for some reason this one's public... */
-guint32 rsvg_css_parse_color (const char *str, gboolean * inherit);
G_GNUC_INTERNAL
guint rsvg_css_parse_opacity (const char *str);
G_GNUC_INTERNAL
@@ -79,6 +85,8 @@ gboolean rsvg_css_parse_overflow (const char *str, gboolean * inherit
G_GNUC_INTERNAL
char **rsvg_css_parse_xml_attribute_string (const char *attribute_string);
+#endif /* RSVG_COMPILATION */
+
G_END_DECLS
#endif
diff --git a/rsvg.h b/rsvg.h
index ebcdb61..801008b 100644
--- a/rsvg.h
+++ b/rsvg.h
@@ -155,10 +155,14 @@ gboolean rsvg_handle_has_sub (RsvgHandle * handle, const char *id);
/**
* RsvgHandleFlags:
* @RSVG_HANDLE_FLAGS_NONE: none
+ * @RSVG_HANDLE_FLAG_UNLIMITED: Allow any SVG XML without size limitations.
+ * For security reasons, this should only be used for trusted input!
+ * Since: 2.40.3
*/
typedef enum /*< flags >*/
{
- RSVG_HANDLE_FLAGS_NONE = 0
+ RSVG_HANDLE_FLAGS_NONE = 0,
+ RSVG_HANDLE_FLAG_UNLIMITED = 1 << 0
} RsvgHandleFlags;
RsvgHandle *rsvg_handle_new_with_flags (RsvgHandleFlags flags);
diff --git a/test-display.c b/test-display.c
index 4b8929b..e16414d 100644
--- a/test-display.c
+++ b/test-display.c
@@ -612,6 +612,7 @@ main (int argc, char **argv)
char *bg_color = NULL;
char *base_uri = NULL;
gboolean keep_aspect_ratio = FALSE;
+ gboolean unlimited = FALSE;
char *id = NULL;
GInputStream *input;
GFileInfo *file_info;
@@ -622,6 +623,8 @@ main (int argc, char **argv)
int from_stdin = 0;
ViewerCbInfo info;
+ RsvgHandleFlags flags = RSVG_HANDLE_FLAGS_NONE;
+
char **args = NULL;
gint n_args = 0;
@@ -646,6 +649,8 @@ main (int argc, char **argv)
N_("<string>")},
{"keep-aspect", 'k', 0, G_OPTION_ARG_NONE, &keep_aspect_ratio,
N_("Preserve the image's aspect ratio"), NULL},
+ {"unlimited", 'u', 0, G_OPTION_ARG_NONE, &unlimited,
+ N_("Allow huge SVG files"), NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &bVersion, N_("Show version information"), NULL},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("[FILE...]")},
{NULL}
@@ -688,6 +693,9 @@ main (int argc, char **argv)
compressed = FALSE;
+ if (unlimited)
+ flags |= RSVG_HANDLE_FLAG_UNLIMITED;
+
if (from_stdin) {
#if 0 // defined (G_OS_UNIX)
input = g_unix_input_stream_new (STDIN_FILENO, FALSE);
@@ -749,7 +757,7 @@ main (int argc, char **argv)
info.handle = rsvg_handle_new_from_stream_sync (input,
base_file,
- RSVG_HANDLE_FLAGS_NONE,
+ flags,
NULL /* cancellable */,
&err);
if (base_file != NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]