1/* GStreamer data:// uri source element
2 * Copyright (C) 2009 Igalia S.L
3 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21/*<private>
22 * # Data URLs
23 *
24 * These function allow encoding and decoding of data: URLs, see
25 * [RFC 2397](http://tools.ietf.org/html/rfc2397) for more information.
26 */
27
28#include "config.h"
29
30#include "gtkcssdataurlprivate.h"
31
32#include "../gtkintl.h"
33
34#include <string.h>
35
36/*<private>
37 * gtk_css_data_url_parse:
38 * @url: the URL to parse
39 * @out_mimetype: (out nullable optional): Return location to set the contained
40 * mime type to. If no mime type was specified, this value is set to %NULL.
41 * @error: error location
42 *
43 * Decodes a data URL according to RFC2397 and returns the decoded data.
44 *
45 * Returns: a new `GBytes` with the decoded data
46 */
47GBytes *
48gtk_css_data_url_parse (const char *url,
49 char **out_mimetype,
50 GError **error)
51{
52 char *mimetype = NULL;
53 const char *parameters_start;
54 const char *data_start;
55 GBytes *bytes;
56 gboolean base64 = FALSE;
57 char *charset = NULL;
58 gpointer bdata;
59 gsize bsize;
60
61 /* url must be an URI as defined in RFC 2397
62 * data:[<mediatype>][;base64],<data>
63 */
64 if (g_ascii_strncasecmp (s1: "data:", s2: url, n: 5) != 0)
65 {
66 g_set_error (err: error,
67 G_IO_ERROR,
68 code: G_IO_ERROR_INVALID_FILENAME,
69 _("Not a data: URL"));
70 return NULL;
71 }
72
73 url += 5;
74
75 parameters_start = strchr (s: url, c: ';');
76 data_start = strchr (s: url, c: ',');
77 if (data_start == NULL)
78 {
79 g_set_error (err: error,
80 G_IO_ERROR,
81 code: G_IO_ERROR_INVALID_FILENAME,
82 _("Malformed data: URL"));
83 return NULL;
84 }
85 if (parameters_start > data_start)
86 parameters_start = NULL;
87
88 if (data_start != url && parameters_start != url)
89 {
90 mimetype = g_strndup (str: url,
91 n: (parameters_start ? parameters_start
92 : data_start) - url);
93 }
94 else
95 {
96 mimetype = NULL;
97 }
98
99 if (parameters_start != NULL)
100 {
101 char *parameters_str;
102 char **parameters;
103 guint i;
104
105 parameters_str = g_strndup (str: parameters_start + 1, n: data_start - parameters_start - 1);
106 parameters = g_strsplit (string: parameters_str, delimiter: ";", max_tokens: -1);
107
108 for (i = 0; parameters[i] != NULL; i++)
109 {
110 if (g_ascii_strcasecmp (s1: "base64", s2: parameters[i]) == 0)
111 {
112 base64 = TRUE;
113 }
114 else if (g_ascii_strncasecmp (s1: "charset=", s2: parameters[i], n: 8) == 0)
115 {
116 g_free (mem: charset);
117 charset = g_strdup (str: parameters[i] + 8);
118 }
119 }
120 g_free (mem: parameters_str);
121 g_strfreev (str_array: parameters);
122 }
123
124 /* Skip comma */
125 data_start += 1;
126 if (base64)
127 {
128 bdata = g_base64_decode (text: data_start, out_len: &bsize);
129 }
130 else
131 {
132 /* URI encoded, i.e. "percent" encoding */
133 /* XXX: This doesn't allow nul bytes */
134 bdata = g_uri_unescape_string (escaped_string: data_start, NULL);
135 if (bdata == NULL)
136 {
137 g_set_error (err: error,
138 G_IO_ERROR,
139 code: G_IO_ERROR_INVALID_FILENAME,
140 _("Could not unescape string"));
141 g_free (mem: mimetype);
142 return NULL;
143 }
144 bsize = strlen (s: bdata);
145 }
146
147 /* Convert to UTF8 */
148 if ((mimetype == NULL || g_ascii_strcasecmp (s1: "text/plain", s2: mimetype) == 0) &&
149 charset && g_ascii_strcasecmp (s1: "US-ASCII", s2: charset) != 0
150 && g_ascii_strcasecmp (s1: "UTF-8", s2: charset) != 0)
151 {
152 gsize read;
153 gsize written;
154 gpointer data;
155 GError *local_error = NULL;
156
157 data = g_convert_with_fallback (str: bdata, len: bsize,
158 to_codeset: "UTF-8", from_codeset: charset,
159 fallback: (char *) "*",
160 bytes_read: &read, bytes_written: &written, error: &local_error);
161 g_free (mem: bdata);
162
163 if (local_error)
164 {
165 g_propagate_error (dest: error, src: local_error);
166 g_free (mem: charset);
167 g_free (mem: data);
168 g_free (mem: mimetype);
169 return NULL;
170 }
171
172
173 bdata = data;
174 bsize = written;
175 }
176 bytes = g_bytes_new_take (data: bdata, size: bsize);
177
178 g_free (mem: charset);
179 if (out_mimetype)
180 *out_mimetype = mimetype;
181 else
182 g_free (mem: mimetype);
183
184 return bytes;
185}
186

source code of gtk/gtk/css/gtkcssdataurl.c