Commit 1291ebc3 authored by Christian Persch's avatar Christian Persch

Split IO handling to rsvg-io.[ch]

Add rsvg-io.[ch], move the code there, clean it up, and adapt the callers.
parent 47920ba6
......@@ -31,6 +31,8 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
rsvg-defs.h \
rsvg-image.c \
rsvg-image.h \
rsvg-io.c \
rsvg-io.h \
rsvg-paint-server.c \
rsvg-paint-server.h \
rsvg-path.c \
......
......@@ -26,6 +26,7 @@
#include "config.h"
#include "rsvg.h"
#include "rsvg-io.h"
#include "rsvg-private.h"
static gboolean
......@@ -85,24 +86,23 @@ RsvgHandle *
rsvg_handle_new_from_file (const gchar * file_name, GError ** error)
{
gchar *base_uri;
GByteArray *f;
guint8 *data;
gsize data_len;
RsvgHandle *handle = NULL;
rsvg_return_val_if_fail (file_name != NULL, NULL, error);
base_uri = rsvg_get_base_uri_from_filename (file_name);
f = _rsvg_acquire_xlink_href_resource (file_name, base_uri, error);
data = _rsvg_io_acquire_data (file_name, base_uri, &data_len, error);
if (f) {
if (data) {
handle = rsvg_handle_new ();
if (handle) {
rsvg_handle_set_base_uri (handle, base_uri);
if (!rsvg_handle_fill_with_data (handle, f->data, f->len, error)) {
g_object_unref (handle);
handle = NULL;
}
rsvg_handle_set_base_uri (handle, base_uri);
if (!rsvg_handle_fill_with_data (handle, data, data_len, error)) {
g_object_unref (handle);
handle = NULL;
}
g_byte_array_free (f, TRUE);
g_free (data);
}
g_free (base_uri);
......
......@@ -33,6 +33,7 @@
#include "rsvg-shapes.h"
#include "rsvg-structure.h"
#include "rsvg-image.h"
#include "rsvg-io.h"
#include "rsvg-text.h"
#include "rsvg-filter.h"
#include "rsvg-mask.h"
......@@ -524,57 +525,81 @@ static void
rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
{
RsvgSaxHandlerXinclude *handler;
GByteArray *data;
const char *href;
const char *href, *parse;
gboolean success = FALSE;
href = rsvg_property_bag_lookup (atts, "href");
if (href) {
data = _rsvg_acquire_xlink_href_resource (href, rsvg_handle_get_base_uri (ctx), NULL);
if (data) {
const char *parse;
parse = rsvg_property_bag_lookup (atts, "parse");
if (parse && !strcmp (parse, "text")) {
const char *encoding;
char *text_data;
gsize text_data_len;
gboolean text_data_needs_free = FALSE;
encoding = rsvg_property_bag_lookup (atts, "encoding");
if (encoding) {
text_data =
g_convert ((const char *) data->data, data->len, "utf-8", encoding, NULL,
if (href == NULL)
goto fallback;
parse = rsvg_property_bag_lookup (atts, "parse");
if (parse && !strcmp (parse, "text")) {
guint8 *data;
gsize data_len;
const char *encoding;
data = _rsvg_io_acquire_data (href, rsvg_handle_get_base_uri (ctx), &data_len, NULL);
if (data == NULL)
goto fallback;
encoding = rsvg_property_bag_lookup (atts, "encoding");
if (encoding && g_ascii_strcasecmp (encoding, "UTF-8") != 0) {
char *text_data;
gsize text_data_len;
text_data = g_convert (data, data_len, "utf-8", encoding, NULL,
&text_data_len, NULL);
text_data_needs_free = TRUE;
} else {
text_data = (char *) data->data;
text_data_len = data->len;
}
g_free (data);
rsvg_characters_impl (ctx, (const xmlChar *) text_data, text_data_len);
data = text_data;
data_len = text_data_len;
}
if (text_data_needs_free)
g_free (text_data);
} else {
/* xml */
xmlDocPtr xml_doc;
xmlParserCtxtPtr xml_parser;
rsvg_characters_impl (ctx, (const xmlChar *) data, data_len);
xml_parser = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, ctx, NULL, 0, NULL);
(void) xmlParseChunk (xml_parser, (char *) data->data, data->len, 0);
(void) xmlParseChunk (xml_parser, "", 0, TRUE);
g_free (data);
} else {
/* xml */
GInputStream *stream;
GError *err = NULL;
xmlDocPtr xml_doc;
xmlParserCtxtPtr xml_parser;
xmlParserInputBufferPtr buffer;
xmlParserInputPtr input;
int result;
xml_doc = xml_parser->myDoc;
xmlFreeParserCtxt (xml_parser);
xmlFreeDoc (xml_doc);
}
stream = _rsvg_io_acquire_stream (href, rsvg_handle_get_base_uri (ctx), NULL);
if (stream == NULL)
goto fallback;
g_byte_array_free (data, TRUE);
success = TRUE;
xml_parser = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, ctx, NULL, 0, NULL);
buffer = _rsvg_xml_input_buffer_new_from_stream (stream, NULL /* cancellable */, XML_CHAR_ENCODING_NONE, &err);
g_object_unref (stream);
input = xmlNewIOInputStream (xml_parser, buffer /* adopts */, XML_CHAR_ENCODING_NONE);
if (xmlPushInput (xml_parser, input) < 0) {
g_clear_error (&err);
xmlFreeInputStream (input);
xmlFreeParserCtxt (xml_parser);
goto fallback;
}
(void) xmlParseDocument (xml_parser);
xml_doc = xml_parser->myDoc;
xmlFreeParserCtxt (xml_parser);
if (xml_doc)
xmlFreeDoc (xml_doc);
g_clear_error (&err);
}
success = TRUE;
fallback:
/* needed to handle xi:fallback */
handler = g_new0 (RsvgSaxHandlerXinclude, 1);
......@@ -776,20 +801,25 @@ rsvg_entity_decl (void *data, const xmlChar * name, int type,
resolvedPublicId = xmlBuildRelativeURI (publicId, (xmlChar*) rsvg_handle_get_base_uri (ctx));
if (type == XML_EXTERNAL_PARAMETER_ENTITY && !content) {
GByteArray *arr = NULL;
if (systemId)
arr = _rsvg_acquire_xlink_href_resource ((const char *) systemId,
rsvg_handle_get_base_uri (ctx), NULL);
else if (publicId)
arr = _rsvg_acquire_xlink_href_resource ((const char *) publicId,
rsvg_handle_get_base_uri (ctx), NULL);
if (arr) {
content = xmlCharStrndup ((const char*)arr->data, arr->len);
g_byte_array_free(arr, TRUE);
}
guint8 *entity_data;
gsize entity_data_len;
if (systemId)
entity_data = _rsvg_io_acquire_data ((const char *) systemId,
rsvg_handle_get_base_uri (ctx),
&entity_data_len,
NULL);
else if (publicId)
entity_data = _rsvg_io_acquire_data ((const char *) publicId,
rsvg_handle_get_base_uri (ctx),
&entity_data_len,
NULL);
if (entity_data) {
content = xmlCharStrndup (entity_data, entity_data_len);
g_free (entity_data);
}
}
entity = xmlNewEntity(NULL, name, type, resolvedPublicId, resolvedSystemId, content);
xmlFree(resolvedPublicId);
......@@ -852,15 +882,16 @@ rsvg_processing_instruction (void *ctx, const xmlChar * target, const xmlChar *
if (value && strcmp (value, "text/css") == 0) {
value = rsvg_property_bag_lookup (atts, "href");
if (value && value[0]) {
GByteArray *style;
style =
_rsvg_acquire_xlink_href_resource (value,
rsvg_handle_get_base_uri (handle),
NULL);
if (style) {
rsvg_parse_cssbuffer (handle, (char *) style->data, style->len);
g_byte_array_free (style, TRUE);
guint8 *style_data;
gsize style_data_len;
style_data = _rsvg_io_acquire_data (value,
rsvg_handle_get_base_uri (handle),
&style_data_len,
NULL);
if (style_data) {
rsvg_parse_cssbuffer (handle, (char *) style_data, style_data_len);
g_free (style_data);
}
}
}
......
......@@ -28,6 +28,7 @@
#include "rsvg-defs.h"
#include "rsvg-styles.h"
#include "rsvg-image.h"
#include "rsvg-io.h"
#include <glib.h>
......@@ -72,25 +73,26 @@ rsvg_defs_load_extern (const RsvgDefs * defs, const char *name)
{
RsvgHandle *handle;
gchar *filename, *base_uri;
GByteArray *chars;
guint8 *data;
gsize data_len;
filename = rsvg_get_file_path (name, defs->base_uri);
chars = _rsvg_acquire_xlink_href_resource (name, defs->base_uri, NULL);
data = _rsvg_io_acquire_data (name, defs->base_uri, &data_len, NULL);
if (chars) {
if (data) {
handle = rsvg_handle_new ();
base_uri = rsvg_get_base_uri_from_filename (filename);
rsvg_handle_set_base_uri (handle, base_uri);
g_free (base_uri);
if (rsvg_handle_write (handle, chars->data, chars->len, NULL) &&
if (rsvg_handle_write (handle, data, data_len, NULL) &&
rsvg_handle_close (handle, NULL)) {
g_hash_table_insert (defs->externs, g_strdup (name), handle);
}
g_byte_array_free (chars, TRUE);
g_free (data);
}
g_free (filename);
......
......@@ -36,6 +36,7 @@
#include "config.h"
#include "rsvg.h"
#include "rsvg-private.h"
#include "rsvg-io.h"
#include <errno.h>
#include <stdio.h>
......@@ -157,9 +158,11 @@ rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
}
static GdkPixbuf *
rsvg_pixbuf_from_stdio_file_with_size_data (GByteArray * f,
struct RsvgSizeCallbackData *data,
gchar * base_uri, GError ** error)
rsvg_pixbuf_from_stdio_file_with_size_data (guint8 *data,
gsize data_len,
struct RsvgSizeCallbackData *cb_data,
gchar * base_uri,
GError ** error)
{
RsvgHandle *handle;
GdkPixbuf *retval;
......@@ -171,10 +174,10 @@ rsvg_pixbuf_from_stdio_file_with_size_data (GByteArray * f,
return NULL;
}
rsvg_handle_set_size_callback (handle, _rsvg_size_callback, data, NULL);
rsvg_handle_set_size_callback (handle, _rsvg_size_callback, cb_data, NULL);
rsvg_handle_set_base_uri (handle, base_uri);
if (!rsvg_handle_write (handle, f->data, f->len, error)) {
if (!rsvg_handle_write (handle, data, data_len, error)) {
g_object_unref (handle);
return NULL;
}
......@@ -192,17 +195,20 @@ rsvg_pixbuf_from_stdio_file_with_size_data (GByteArray * f,
static GdkPixbuf *
rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,
struct RsvgSizeCallbackData *data, GError ** error)
struct RsvgSizeCallbackData *cb_data,
GError ** error)
{
GdkPixbuf *pixbuf;
GByteArray *f;
guint8 *data;
gsize data_len;
GString *base_uri = g_string_new (file_name);
f = _rsvg_acquire_xlink_href_resource (file_name, base_uri->str, error);
data = _rsvg_io_acquire_data (file_name, base_uri->str, &data_len, error);
if (f) {
pixbuf = rsvg_pixbuf_from_stdio_file_with_size_data (f, data, base_uri->str, error);
g_byte_array_free (f, TRUE);
if (data) {
pixbuf = rsvg_pixbuf_from_stdio_file_with_size_data (data, data_len,
cb_data, base_uri->str, error);
g_free (data);
} else {
pixbuf = NULL;
}
......
......@@ -34,170 +34,28 @@
#include <math.h>
#include <errno.h>
#include "rsvg-css.h"
#include <gio/gio.h>
static GByteArray *
rsvg_acquire_base64_resource (const char *data, GError ** error)
{
GByteArray *array = NULL;
gsize data_len, written_len;
int state = 0;
guint save = 0;
rsvg_return_val_if_fail (data != NULL, NULL, error);
while (*data)
if (*data++ == ',')
break;
data_len = strlen (data);
array = g_byte_array_sized_new (data_len / 4 * 3);
written_len = g_base64_decode_step (data, data_len, array->data,
&state, &save);
g_byte_array_set_size (array, written_len);
return array;
}
gchar *
rsvg_get_file_path (const gchar * filename, const gchar * base_uri)
{
gchar *absolute_filename;
if (g_file_test (filename, G_FILE_TEST_EXISTS) || g_path_is_absolute (filename)) {
absolute_filename = g_strdup (filename);
} else {
gchar *tmpcdir;
gchar *base_filename;
if (base_uri) {
base_filename = g_filename_from_uri (base_uri, NULL, NULL);
if (base_filename != NULL) {
tmpcdir = g_path_get_dirname (base_filename);
g_free (base_filename);
} else
return NULL;
} else
tmpcdir = g_get_current_dir ();
absolute_filename = g_build_filename (tmpcdir, filename, NULL);
g_free (tmpcdir);
}
return absolute_filename;
}
static GByteArray *
rsvg_acquire_file_resource (const char *filename, const char *base_uri, GError ** error)
{
GByteArray *array;
gchar *path;
gchar *data = NULL;
gsize length;
rsvg_return_val_if_fail (filename != NULL, NULL, error);
path = rsvg_get_file_path (filename, base_uri);
if (path == NULL)
return NULL;
if (!g_file_get_contents (path, &data, &length, error)) {
g_free (path);
return NULL;
}
array = g_byte_array_new ();
g_byte_array_append (array, (guint8 *)data, length);
g_free (data);
g_free (path);
return array;
}
static GByteArray *
rsvg_acquire_vfs_resource (const char *filename, const char *base_uri, GError ** error)
{
GByteArray *array;
GFile *file;
char *data;
gsize size;
gboolean res = FALSE;
rsvg_return_val_if_fail (filename != NULL, NULL, error);
file = g_file_new_for_uri (filename);
if (!(res = g_file_load_contents (file, NULL, &data, &size, NULL, error))) {
if (base_uri != NULL) {
GFile *base;
g_clear_error (error);
g_object_unref (file);
base = g_file_new_for_uri (base_uri);
file = g_file_resolve_relative_path (base, filename);
g_object_unref (base);
res = g_file_load_contents (file, NULL, &data, &size, NULL, error);
}
}
g_object_unref (file);
if (res) {
array = g_byte_array_new ();
g_byte_array_append (array, (guint8 *)data, size);
g_free (data);
} else {
return NULL;
}
return array;
}
GByteArray *
_rsvg_acquire_xlink_href_resource (const char *href, const char *base_uri, GError ** err)
{
GByteArray *arr = NULL;
if (!(href && *href))
return NULL;
if (!strncmp (href, "data:", 5))
arr = rsvg_acquire_base64_resource (href, NULL);
if (!arr)
arr = rsvg_acquire_file_resource (href, base_uri, NULL);
if (!arr)
arr = rsvg_acquire_vfs_resource (href, base_uri, NULL);
return arr;
}
#include "rsvg-io.h"
cairo_surface_t *
rsvg_cairo_surface_new_from_href (const char *href,
const char *base_uri,
GError **error)
{
GByteArray *arr;
guint8 *data;
gsize data_len;
GdkPixbufLoader *loader;
GdkPixbuf *pixbuf = NULL;
int res;
cairo_surface_t *surface;
arr = _rsvg_acquire_xlink_href_resource (href, base_uri, error);
if (arr == NULL)
data = _rsvg_io_acquire_data (href, base_uri, &data_len, error);
if (data == NULL)
return NULL;
loader = gdk_pixbuf_loader_new ();
res = gdk_pixbuf_loader_write (loader, arr->data, arr->len, error);
g_byte_array_free (arr, TRUE);
res = gdk_pixbuf_loader_write (loader, data, data_len, error);
g_free (data);
if (!res) {
gdk_pixbuf_loader_close (loader, NULL);
......
/*
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
Copyright (C) 2003, 2004, 2005 Caleb Moore <c.moore@student.unsw.edu.au>
Copyright © 2011, 2012 Christian Persch
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "rsvg-io.h"
#include "rsvg-private.h"
#include <string.h>
static guint8 *
rsvg_acquire_base64_data (const char *data,
const char *base_uri,
gsize *len,
GError **error)
{
guint8 *bytes;
gsize data_len, written_len;
int state = 0;
guint save = 0;
/* FIXME: be more correct! Check that is indeed a base64 data: URI */
while (*data)
if (*data++ == ',')
break;
data_len = strlen (data);
bytes = g_try_malloc (data_len / 4 * 3);
if (bytes == NULL)
return NULL;
written_len = g_base64_decode_step (data, data_len, bytes, &state, &save);
*len = written_len;
return bytes;
}
gchar *
rsvg_get_file_path (const gchar * filename, const gchar * base_uri)
{
gchar *absolute_filename;
if (g_file_test (filename, G_FILE_TEST_EXISTS) || g_path_is_absolute (filename)) {
absolute_filename = g_strdup (filename);
} else {
gchar *tmpcdir;
gchar *base_filename;
if (base_uri) {
base_filename = g_filename_from_uri (base_uri, NULL, NULL);
if (base_filename != NULL) {
tmpcdir = g_path_get_dirname (base_filename);
g_free (base_filename);
} else
return NULL;
} else
tmpcdir = g_get_current_dir ();
absolute_filename = g_build_filename (tmpcdir, filename, NULL);
g_free (tmpcdir);
}
return absolute_filename;
}
static guint8 *
rsvg_acquire_file_data (const char *filename,
const char *base_uri,
gsize *len,
GError **error)
{
GFile *file;
gchar *path, *data;
GInputStream *stream;
rsvg_return_val_if_fail (filename != NULL, NULL, error);
path = rsvg_get_file_path (filename, base_uri);
if (path == NULL)
return NULL;
if (!g_file_get_contents (path, &data, len, error))
return NULL;
return data;
}
static GInputStream *
rsvg_acquire_gvfs_stream (const char *uri,
const char *base_uri,
GError **error)
{
GFile *base, *file;
GInputStream *stream;
GError *err = NULL;
gchar *data;
file = g_file_new_for_uri (uri);
stream = (GInputStream *) g_file_read (file, NULL /* cancellable */, &err);
g_object_unref (file);
if (stream == NULL &&
g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
g_clear_error (&err);
base = g_file_new_for_uri (base_uri);
file = g_file_resolve_relative_path (base, uri);
g_object_unref (base);
stream = (GInputStream *) g_file_read (file, NULL /* cancellable */, &err);
g_object_unref (file);
}
if (stream == NULL)
g_propagate_error (error, err);
return stream;
}
static guint8 *
rsvg_acquire_gvfs_data (const char *uri,
const char *base_uri,
gsize *len,
GError **error)
{
GFile *base, *file;
GInputStream *stream;
GError *err;
gchar *data;
gboolean res;
file = g_file_new_for_uri (uri);
err = NULL;
data = NULL;
if (!(res = g_file_load_contents (file, NULL, &data, len, NULL, &err)) &&
g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
base_uri != NULL) {
g_clear_error (&err);
base = g_file_new_for_uri (base_uri);
file = g_file_resolve_relative_path (base, uri);
g_object_unref (base);
res = g_file_load_contents (file, NULL, &data, len, NULL, &err);
}
g_object_unref (file);
if (err == NULL)
return data;
g_propagate_error (error, err);
return NULL;
}
guint8 *
_rsvg_io_acquire_data (const char *href,
const char *base_uri,
gsize *len,
GError **error)
{
guint8 *data;
if (!(href && *href))
return NULL;
if (strncmp (href, "data:", 5) == 0 &&
(data = rsvg_acquire_base64_data (href, NULL, len, error)))
return data;
if ((data = rsvg_acquire_file_data (href, base_uri, len, error)))
return data;
if ((data = rsvg_acquire_gvfs_data (href, base_uri, len, error)))
return data;
return NULL;
}
GInputStream *
_rsvg_io_acquire_stream (const char *href,
const char *base_uri,
GError **error)
{
GInputStream *stream;
guint8 *data;
gsize len;
if (!(href && *href))
return NULL;
if (strncmp (href, "data:", 5) == 0 &&
(data = rsvg_acquire_base64_data (href, NULL, &len, error)))
return g_memory_input_stream_new_from_data (data, len, (GDestroyNotify) g_free);
if ((data = rsvg_acquire_file_data (href, base_uri, &len, error)))
return g_memory_input_stream_new_from_data (data, len, (GDestroyNotify) g_free);
if ((stream = rsvg_acquire_gvfs_stream (href, base_uri, error)))
return stream;
<