rsvg-base.c 6.24 KB
Newer Older
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim: set sw=4 sts=4 expandtab: */
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
   rsvg.c: SAX-based renderer for SVG files into a GdkPixbuf.

   Copyright (C) 2000 Eazel, Inc.
   Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>

   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.

   Author: Raph Levien <raph@artofcode.com>
*/

#include "config.h"
28
#define _GNU_SOURCE 1
29 30 31 32

#include "rsvg-private.h"
#include "rsvg-css.h"
#include "rsvg-styles.h"
33
#include "rsvg-io.h"
34

Christian Persch's avatar
Christian Persch committed
35 36
#include <gio/gio.h>

37 38 39
#include <math.h>
#include <string.h>
#include <stdarg.h>
40 41
#include <limits.h>
#include <stdlib.h>
42

43
#ifdef G_OS_WIN32
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static char *
rsvg_realpath_utf8 (const char *filename, const char *unused)
{
    wchar_t *wfilename;
    wchar_t *wfull;
    char *full;

    wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
    if (!wfilename)
        return NULL;

    wfull = _wfullpath (NULL, wfilename, 0);
    g_free (wfilename);
    if (!wfull)
        return NULL;

    full = g_utf16_to_utf8 (wfull, -1, NULL, NULL, NULL);
    free (wfull);

    if (!full)
        return NULL;

    return full;
}

#define realpath(a,b) rsvg_realpath_utf8 (a, b)
70 71
#endif

72 73 74 75 76
/*
 * This is configurable at runtime
 */
#define RSVG_DEFAULT_DPI_X 90.0
#define RSVG_DEFAULT_DPI_Y 90.0
77 78

G_GNUC_INTERNAL
79
double rsvg_internal_dpi_x = RSVG_DEFAULT_DPI_X;
80
G_GNUC_INTERNAL
81
double rsvg_internal_dpi_y = RSVG_DEFAULT_DPI_Y;
82 83

/**
84
 * rsvg_error_quark:
85 86 87 88 89 90 91 92
 *
 * The error domain for RSVG
 *
 * Returns: The error domain
 */
GQuark
rsvg_error_quark (void)
{
93 94 95
    /* don't use from_static_string(), since librsvg might be used in a module
       that's ultimately unloaded */
    return g_quark_from_string ("rsvg-error-quark");
96 97
}

98
/**
99
 * rsvg_set_default_dpi:
100 101
 * @dpi: Dots Per Inch (aka Pixels Per Inch)
 *
102 103
 * Do not use this function.  Create an #RsvgHandle and call
 * rsvg_handle_set_dpi() on it instead.
104 105
 *
 * Since: 2.8
106 107 108 109 110
 *
 * Deprecated: 2.42.3: This function used to set a global default DPI.  However,
 * it only worked if it was called before any #RsvgHandle objects had been
 * created; it would not work after that.  To avoid global mutable state, please
 * use rsvg_handle_set_dpi() instead.
111 112 113 114
 */
void
rsvg_set_default_dpi (double dpi)
{
115
    rsvg_set_default_dpi_x_y (dpi, dpi);
116 117
}

118
/**
119
 * rsvg_set_default_dpi_x_y:
120 121 122
 * @dpi_x: Dots Per Inch (aka Pixels Per Inch)
 * @dpi_y: Dots Per Inch (aka Pixels Per Inch)
 *
123 124
 * Do not use this function.  Create an #RsvgHandle and call
 * rsvg_handle_set_dpi_x_y() on it instead.
125 126
 *
 * Since: 2.8
127 128 129 130 131
 *
 * Deprecated: 2.42.3: This function used to set a global default DPI.  However,
 * it only worked if it was called before any #RsvgHandle objects had been
 * created; it would not work after that.  To avoid global mutable state, please
 * use rsvg_handle_set_dpi() instead.
132 133
 */
void
134
rsvg_set_default_dpi_x_y (double dpi_x, double dpi_y)
135
{
136 137 138 139
    if (dpi_x <= 0.)
        rsvg_internal_dpi_x = RSVG_DEFAULT_DPI_X;
    else
        rsvg_internal_dpi_x = dpi_x;
140

141 142 143 144
    if (dpi_y <= 0.)
        rsvg_internal_dpi_y = RSVG_DEFAULT_DPI_Y;
    else
        rsvg_internal_dpi_y = dpi_y;
145 146 147 148 149
}

/**
 * rsvg_init:
 *
150 151
 * This function does nothing.
 *
152
 * Since: 2.9
153
 * Deprecated: 2.36: There is no need to initialize librsvg.
154
 **/
155
void
156 157 158 159 160 161 162
rsvg_init (void)
{
}

/**
 * rsvg_term:
 *
163 164
 * This function does nothing.
 *
165
 * Since: 2.9
166
 * Deprecated: 2.36: There is no need to de-initialize librsvg.
167 168 169
 **/
void
rsvg_term (void)
170 171 172 173 174 175 176 177 178 179 180 181 182
{
}

/**
 * rsvg_cleanup:
 *
 * This function should not be called from normal programs.
 * See xmlCleanupParser() for more information.
 *
 * Since: 2.36
 **/
void
rsvg_cleanup (void)
183
{
184
    xmlCleanupParser ();
185 186
}

187 188 189 190
void
rsvg_return_if_fail_warning (const char *pretty_function, const char *expression, GError ** error)
{
    g_set_error (error, RSVG_ERROR, 0, _("%s: assertion `%s' failed"), pretty_function, expression);
191
}
192

193 194 195 196
gboolean
rsvg_allow_load (GFile       *base_gfile,
                 const char  *uri,
                 GError     **error)
197
{
198 199 200
    GFile *base;
    char *path, *dir;
    char *scheme = NULL, *cpath = NULL, *cdir = NULL;
201

202 203
    g_assert (error == NULL || *error == NULL);

204 205 206 207 208 209 210 211 212 213 214
    scheme = g_uri_parse_scheme (uri);

    /* Not a valid URI */
    if (scheme == NULL)
        goto deny;

    /* Allow loads of data: from any location */
    if (g_str_equal (scheme, "data"))
        goto allow;

    /* No base to compare to? */
215
    if (base_gfile == NULL)
216 217 218
        goto deny;

    /* Deny loads from differing URI schemes */
219
    if (!g_file_has_uri_scheme (base_gfile, scheme))
220 221 222 223 224 225 226 227 228 229
        goto deny;

    /* resource: is allowed to load anything from other resources */
    if (g_str_equal (scheme, "resource"))
        goto allow;

    /* Non-file: isn't allowed to load anything */
    if (!g_str_equal (scheme, "file"))
        goto deny;

230
    base = g_file_get_parent (base_gfile);
231 232
    if (base == NULL)
        goto deny;
233

234 235 236
    dir = g_file_get_path (base);
    g_object_unref (base);

237
    cdir = realpath (dir, NULL);
238 239 240 241 242 243 244 245
    g_free (dir);
    if (cdir == NULL)
        goto deny;

    path = g_filename_from_uri (uri, NULL, NULL);
    if (path == NULL)
        goto deny;

246
    cpath = realpath (path, NULL);
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    g_free (path);

    if (cpath == NULL)
        goto deny;

    /* Now check that @cpath is below @cdir */
    if (!g_str_has_prefix (cpath, cdir) ||
        cpath[strlen (cdir)] != G_DIR_SEPARATOR)
        goto deny;

    /* Allow load! */

 allow:
    g_free (scheme);
    free (cpath);
    free (cdir);
263
    return TRUE;
264 265 266 267 268 269 270 271 272

 deny:
    g_free (scheme);
    free (cpath);
    free (cdir);

    g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
                 "File may not link to URI \"%s\"", uri);
    return FALSE;
273
}