diff options
author | Alexander Larsson <alexl@src.gnome.org> | 2007-09-13 10:57:53 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2007-09-13 10:57:53 +0000 |
commit | d691783d4d1ca9822d39a816db059dd4bbedf853 (patch) | |
tree | 5a4d2cf3fb0cc3605c3495f158f47e17fa2521b5 /client/gvfsuriutils.c | |
parent | 4f8f113c9e20314eb42eac38248dd53bfde00ac1 (diff) | |
download | gvfs-d691783d4d1ca9822d39a816db059dd4bbedf853.tar.gz |
Split out daemon implementation into a module in its own subdir
Original git commit by Alexander Larsson <alex@greebo.(none)> at 1169052241 +0100
svn path=/trunk/; revision=251
Diffstat (limited to 'client/gvfsuriutils.c')
-rw-r--r-- | client/gvfsuriutils.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/client/gvfsuriutils.c b/client/gvfsuriutils.c new file mode 100644 index 00000000..8acf8055 --- /dev/null +++ b/client/gvfsuriutils.c @@ -0,0 +1,316 @@ +#include <config.h> +#include "gvfsuriutils.h" +#include <string.h> +#include <stdlib.h> + +static int +unescape_character (const char *scanner) +{ + int first_digit; + int second_digit; + + first_digit = g_ascii_xdigit_value (*scanner++); + if (first_digit < 0) + return -1; + + second_digit = g_ascii_xdigit_value (*scanner++); + if (second_digit < 0) + return -1; + + return (first_digit << 4) | second_digit; +} + +static char * +unescape_string (const gchar *escaped_string, + const gchar *escaped_string_end, + const gchar *illegal_characters) +{ + const gchar *in; + gchar *out, *result; + gint character; + + if (escaped_string == NULL) + return NULL; + + result = g_malloc (escaped_string_end - escaped_string + 1); + + out = result; + for (in = escaped_string; in < escaped_string_end; in++) { + character = *in; + if (*in == '%') { + in++; + if (escaped_string_end - in < 2) + { + g_free (result); + return NULL; + } + + character = unescape_character (in); + + /* Check for an illegal character. We consider '\0' illegal here. */ + if (character <= 0 || + (illegal_characters != NULL && + strchr (illegal_characters, (char)character) != NULL)) + { + g_free (result); + return NULL; + } + in++; /* The other char will be eaten in the loop header */ + } + *out++ = (char)character; + } + + *out = '\0'; + g_assert (out - result <= strlen (escaped_string)); + return result; +} + +void +_g_decoded_uri_free (GDecodedUri *decoded) +{ + if (decoded == NULL) + return; + + g_free (decoded->scheme); + g_free (decoded->query); + g_free (decoded->fragment); + g_free (decoded->userinfo); + g_free (decoded->host); + g_free (decoded->path); + g_free (decoded); +} + +GDecodedUri * +_g_decode_uri (const char *uri) +{ + GDecodedUri *decoded; + const char *p, *in, *hier_part_start, *hier_part_end, *query_start, *fragment_start; + char *out; + char c; + + /* From RFC 3986 Decodes: + * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + */ + + p = uri; + + /* Decode scheme: + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ + + if (!g_ascii_isalpha (*p)) + return NULL; + + while (1) + { + c = *p++; + + if (c == ':') + break; + + if (!(g_ascii_isalnum(c) || + c == '+' || + c == '-' || + c == '.')) + return NULL; + } + + decoded = g_new0 (GDecodedUri, 1); + decoded->port = -1; + + decoded->scheme = g_malloc (p - uri); + out = decoded->scheme; + for (in = uri; in < p - 1; in++) + *out++ = g_ascii_tolower (*in); + *out = 0; + + hier_part_start = p; + + query_start = strchr (p, '?'); + if (query_start) + { + hier_part_end = query_start++; + fragment_start = strchr (query_start, '#'); + if (fragment_start) + { + decoded->query = g_strndup (query_start, fragment_start - query_start); + decoded->fragment = g_strdup (fragment_start+1); + } + else + { + decoded->query = g_strdup (query_start); + decoded->fragment = NULL; + } + } + else + { + /* No query */ + decoded->query = NULL; + fragment_start = strchr (p, '#'); + if (fragment_start) + { + hier_part_end = fragment_start++; + decoded->fragment = g_strdup (fragment_start); + } + else + { + hier_part_end = p + strlen (p); + decoded->fragment = NULL; + } + } + + /* 3: + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + */ + + if (hier_part_start[0] == '/' && + hier_part_start[1] == '/') + { + const char *authority_start, *authority_end; + const char *userinfo_start, *userinfo_end; + const char *host_start, *host_end; + const char *port_start; + + authority_start = hier_part_start + 2; + /* authority is always followed by / or nothing */ + authority_end = memchr (authority_start, '/', hier_part_end - authority_start); + if (authority_end == NULL) + authority_end = hier_part_end; + + /* 3.2: + authority = [ userinfo "@" ] host [ ":" port ] + */ + + userinfo_end = memchr (authority_start, '@', authority_end - authority_start); + if (userinfo_end) + { + userinfo_start = authority_start; + decoded->userinfo = unescape_string (userinfo_start, userinfo_end, NULL); + if (decoded->userinfo == NULL) + { + _g_decoded_uri_free (decoded); + return NULL; + } + host_start = userinfo_end + 1; + } + else + host_start = authority_start; + + port_start = memchr (host_start, ':', authority_end - host_start); + if (port_start) + { + host_end = port_start++; + + decoded->port = atoi(port_start); + } + else + { + host_end = authority_end; + decoded->port = -1; + } + + decoded->host = g_strndup (host_start, host_end - host_start); + + hier_part_start = authority_end; + } + + decoded->path = unescape_string (hier_part_start, hier_part_end, "/"); + + if (decoded->path == NULL) + { + _g_decoded_uri_free (decoded); + return NULL; + } + + return decoded; +} + +#define SUB_DELIM_CHARS "!$&'()*+,;=" + +static gboolean +is_valid (char c, const char *reserved_chars_allowed) +{ + if (g_ascii_isalnum (c) || + c == '-' || + c == '.' || + c == '_' || + c == '~') + return TRUE; + + if (reserved_chars_allowed && + strchr (reserved_chars_allowed, c) != NULL) + return TRUE; + + return FALSE; +} + +static void +g_string_append_encoded (GString *string, const char *encoded, + const char *reserved_chars_allowed) +{ + char c; + static const gchar hex[16] = "0123456789ABCDEF"; + + while ((c = *encoded++) != 0) + { + if (is_valid (c, reserved_chars_allowed)) + g_string_append_c (string, c); + else + { + g_string_append_c (string, '%'); + g_string_append_c (string, hex[((guchar)c) >> 4]); + g_string_append_c (string, hex[((guchar)c) & 0xf]); + } + } +} + +char * +_g_encode_uri (GDecodedUri *decoded) +{ + GString *uri; + + uri = g_string_new (NULL); + + g_string_append (uri, decoded->scheme); + g_string_append_c (uri, ':'); + + if (decoded->host != NULL) + { + g_string_append (uri, "//"); + + if (decoded->userinfo) + { + /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */ + g_string_append_encoded (uri, decoded->userinfo, SUB_DELIM_CHARS ":"); + g_string_append_c (uri, '@'); + } + + g_string_append (uri, decoded->host); + + if (decoded->port != -1) + { + g_string_append_c (uri, ':'); + g_string_append_printf (uri, "%d", decoded->port); + } + } + + g_string_append_encoded (uri, decoded->path, SUB_DELIM_CHARS ":@/"); + + if (decoded->query) + { + g_string_append_c (uri, '?'); + g_string_append (uri, decoded->query); + } + + if (decoded->fragment) + { + g_string_append_c (uri, '#'); + g_string_append (uri, decoded->fragment); + } + + return g_string_free (uri, FALSE); +} |