From 4e11203c541452f1133645e508c8878719efdae5 Mon Sep 17 00:00:00 2001 From: Alex Larsson Date: Sun, 26 Aug 2001 21:39:47 +0000 Subject: [PATCH] New functions to convert between local pahtnames and file: uris. 2001-08-26 Alex Larsson * glib/gconvert.[ch] (g_filename_from_uri, g_filename_to_uri): New functions to convert between local pahtnames and file: uris. * tests/Makefile.am: * tests/uri-test.c: Tests for the new functions. --- ChangeLog | 10 ++ ChangeLog.pre-2-0 | 10 ++ ChangeLog.pre-2-10 | 10 ++ ChangeLog.pre-2-12 | 10 ++ ChangeLog.pre-2-2 | 10 ++ ChangeLog.pre-2-4 | 10 ++ ChangeLog.pre-2-6 | 10 ++ ChangeLog.pre-2-8 | 10 ++ glib/gconvert.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++++++- glib/gconvert.h | 14 +- tests/Makefile.am | 4 +- tests/uri-test.c | 224 ++++++++++++++++++++++++++++++++ 12 files changed, 686 insertions(+), 7 deletions(-) create mode 100644 tests/uri-test.c diff --git a/ChangeLog b/ChangeLog index 3e5cb97..ab29d02 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 3e5cb97..ab29d02 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,13 @@ +2001-08-26 Alex Larsson + + * glib/gconvert.[ch] (g_filename_from_uri, + g_filename_to_uri): New functions to convert + between local pahtnames and file: uris. + + * tests/Makefile.am: + * tests/uri-test.c: + Tests for the new functions. + 2001-08-25 Alexander Larsson * glib/gstrfuncs.[ch]: diff --git a/glib/gconvert.c b/glib/gconvert.c index ae072e3..1246ea4 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -563,11 +563,24 @@ static gchar * strdup_len (const gchar *string, gssize len, gsize *bytes_written, - gsize *bytes_read) + gsize *bytes_read, + GError **error) { gsize real_len; + if (!g_utf8_validate (string, -1, NULL)) + { + if (bytes_read) + *bytes_read = 0; + if (bytes_written) + *bytes_written = 0; + + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid byte sequence in conversion input")); + return NULL; + } + if (len < 0) real_len = strlen (string); else @@ -718,7 +731,7 @@ g_locale_to_utf8 (const gchar *opsysstring, const char *charset; if (g_get_charset (&charset)) - return strdup_len (opsysstring, len, bytes_read, bytes_written); + return strdup_len (opsysstring, len, bytes_read, bytes_written, error); else return g_convert (opsysstring, len, "UTF-8", charset, bytes_read, bytes_written, error); @@ -864,7 +877,7 @@ g_locale_from_utf8 (const gchar *utf8string, const gchar *charset; if (g_get_charset (&charset)) - return strdup_len (utf8string, len, bytes_read, bytes_written); + return strdup_len (utf8string, len, bytes_read, bytes_written, error); else return g_convert (utf8string, len, charset, "UTF-8", bytes_read, bytes_written, error); @@ -907,12 +920,13 @@ g_filename_to_utf8 (const gchar *opsysstring, bytes_read, bytes_written, error); #else /* !G_PLATFORM_WIN32 */ + if (getenv ("G_BROKEN_FILENAMES")) return g_locale_to_utf8 (opsysstring, len, bytes_read, bytes_written, error); else - return strdup_len (opsysstring, len, bytes_read, bytes_written); + return strdup_len (opsysstring, len, bytes_read, bytes_written, error); #endif /* !G_PLATFORM_WIN32 */ } @@ -955,6 +969,353 @@ g_filename_from_utf8 (const gchar *utf8string, bytes_read, bytes_written, error); else - return strdup_len (utf8string, len, bytes_read, bytes_written); + return strdup_len (utf8string, len, bytes_read, bytes_written, error); #endif /* !G_PLATFORM_WIN32 */ } + +/* Test of haystack has the needle prefix, comparing case + * insensitive. haystack may be UTF-8, but needle must + * contain only ascii. */ +static gboolean +has_case_prefix (const gchar *haystack, const gchar *needle) +{ + const gchar *h, *n; + + /* Eat one character at a time. */ + h = haystack; + n = needle; + + while (*n && *h && + g_ascii_tolower (*n) == g_ascii_tolower (*h)) + { + n++; + h++; + } + + return *n == '\0'; +} + +typedef enum { + UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ + UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ + UNSAFE_PATH = 0x4, /* Allows '/' and '?' and '&' and '=' */ + UNSAFE_DOS_PATH = 0x8, /* Allows '/' and '?' and '&' and '=' and ':' */ + UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ + UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ +} UnsafeCharacterSet; + +static const guchar acceptable[96] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ + 0x00,0x3F,0x20,0x20,0x20,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x22,0x20,0x3F,0x3F,0x1C, /* 2X !"#$%&'()*+,-./ */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x2C, /* 3X 0123456789:;<=>? */ + 0x30,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 4X @ABCDEFGHIJKLMNO */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, /* 5X PQRSTUVWXYZ[\]^_ */ + 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 6X `abcdefghijklmno */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 /* 7X pqrstuvwxyz{|}~DEL */ +}; + +static const gchar hex[16] = "0123456789ABCDEF"; + +/* Note: This escape function works on file: URIs, but if you want to + * escape something else, please read RFC-2396 */ +static gchar * +g_escape_uri_string (const gchar *string, + UnsafeCharacterSet mask) +{ +#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) + + const gchar *p; + gchar *q; + gchar *result; + int c; + gint unacceptable; + UnsafeCharacterSet use_mask; + + g_return_val_if_fail (mask == UNSAFE_ALL + || mask == UNSAFE_ALLOW_PLUS + || mask == UNSAFE_PATH + || mask == UNSAFE_DOS_PATH + || mask == UNSAFE_HOST + || mask == UNSAFE_SLASHES, NULL); + + unacceptable = 0; + use_mask = mask; + for (p = string; *p != '\0'; p++) + { + c = *p; + if (!ACCEPTABLE (c)) + unacceptable++; + } + + result = g_malloc (p - string + unacceptable * 2 + 1); + + use_mask = mask; + for (q = result, p = string; *p != '\0'; p++) + { + c = (unsigned char)*p; + + if (!ACCEPTABLE (c)) + { + *q++ = '%'; /* means hex coming */ + *q++ = hex[c >> 4]; + *q++ = hex[c & 15]; + } + else + *q++ = *p; + } + + *q = '\0'; + + return result; +} + + +static gchar * +g_escape_file_uri (const gchar *hostname, + const gchar *pathname) +{ + char *escaped_hostname = NULL; + char *escaped_path; + char *res; + + if (hostname && *hostname != '\0') + { + escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST); + } + + escaped_path = g_escape_uri_string (pathname, UNSAFE_DOS_PATH); + + res = g_strconcat ("file://", + (escaped_hostname) ? escaped_hostname : "", + (*escaped_path != '/') ? "/" : "", + escaped_path, + NULL); + + g_free (escaped_hostname); + g_free (escaped_path); + + return res; +} + +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 gchar * +g_unescape_uri_string (const gchar *escaped, + const gchar *illegal_characters, + int len) +{ + const gchar *in, *in_end; + gchar *out, *result; + int character; + + if (escaped == NULL) + return NULL; + + if (len < 0) + len = strlen (escaped); + + result = g_malloc (len + 1); + + out = result; + for (in = escaped, in_end = escaped + len; in < in_end && *in != '\0'; in++) + { + character = *in; + if (character == '%') + { + character = unescape_character (in + 1); + + /* 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 += 2; + } + *out++ = character; + } + + *out = '\0'; + + g_assert (out - result <= strlen (escaped)); + + if (!g_utf8_validate (result, -1, NULL)) + { + g_free (result); + return NULL; + } + + return result; +} + +/** + * g_filename_from_uri: + * @uri: a uri describing a filename (escaped, encoded in UTF-8) + * @hostname: Location to store hostname for the URI, or %NULL. + * If there is no hostname in the URI, %NULL will be + * stored in this location. + * @error: location to store the error occuring, or %NULL to ignore + * errors. Any of the errors in #GConvertError may occur. + * + * Converts an escaped UTF-8 encoded URI to a local filename in the + * encoding used for filenames. + * + * Return value: a newly allocated string holding the resulting + * filename, or %NULL on an error. + **/ +gchar * +g_filename_from_uri (const char *uri, + char **hostname, + GError **error) +{ + const char *path_part; + const char *host_part; + char *unescaped_hostname; + char *result; + char *filename; + int offs; + + if (hostname) + *hostname = NULL; + + if (!has_case_prefix (uri, "file:/")) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NOT_LOCAL_FILE, + _("The URI `%s' does not specify a local file"), + uri); + return NULL; + } + + path_part = uri + strlen ("file:"); + + if (strchr (path_part, '#') != NULL) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_INVALID_URI, + _("The local file URI `%s' may not include a `#'"), + uri); + return NULL; + } + + if (has_case_prefix (path_part, "///")) + path_part += 2; + else if (has_case_prefix (path_part, "//")) + { + path_part += 2; + host_part = path_part; + + path_part = strchr (path_part, '/'); + + if (path_part == NULL) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_INVALID_URI, + _("The URI `%s' is invalid"), + uri); + return NULL; + } + + unescaped_hostname = g_unescape_uri_string (host_part, "", path_part - host_part); + if (unescaped_hostname == NULL) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_INVALID_URI, + _("The hostname of the URI `%s' is contains invalidly escaped characters"), + uri); + return NULL; + } + + if (hostname) + *hostname = unescaped_hostname; + else + g_free (unescaped_hostname); + } + + filename = g_unescape_uri_string (path_part, "/", -1); + + if (filename == NULL) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_INVALID_URI, + _("The URI `%s' is contains invalidly escaped characters"), + uri); + return NULL; + } + + /* DOS uri's are like "file://host/c:\foo", so we need to check if we need to + * drop the initial slash */ + offs = 0; + if (g_path_is_absolute (filename+1)) + offs = 1; + + result = g_filename_from_utf8 (filename + offs, -1, NULL, NULL, error); + g_free (filename); + + return result; +} + +/** + * g_filename_to_uri: + * @filename: an absolute filename specified in the encoding + * used for filenames by the operating system. + * @hostname: A UTF-8 encoded hostname, or %NULL for none. + * @error: location to store the error occuring, or %NULL to ignore + * errors. Any of the errors in #GConvertError may occur. + * + * Converts an absolute filename to an escaped UTF-8 encoded URI. + * + * Return value: a newly allocated string holding the resulting + * URI, or %NULL on an error. + **/ +gchar * +g_filename_to_uri (const char *filename, + char *hostname, + GError **error) +{ + char *escaped_uri; + char *utf8_filename; + + g_return_val_if_fail (filename != NULL, NULL); + + if (!g_path_is_absolute (filename)) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH, + _("The pathname '%s' is not an absolute path"), + filename); + return NULL; + } + + utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, error); + if (utf8_filename == NULL) + return NULL; + + if (hostname && + !g_utf8_validate (hostname, -1, NULL)) + { + g_free (utf8_filename); + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid byte sequence in hostname")); + return NULL; + } + + escaped_uri = g_escape_file_uri (hostname, + utf8_filename); + g_free (utf8_filename); + + return escaped_uri; +} + diff --git a/glib/gconvert.h b/glib/gconvert.h index 4f515d3..280feda 100644 --- a/glib/gconvert.h +++ b/glib/gconvert.h @@ -37,7 +37,10 @@ typedef enum G_CONVERT_ERROR_NO_CONVERSION, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, G_CONVERT_ERROR_FAILED, - G_CONVERT_ERROR_PARTIAL_INPUT + G_CONVERT_ERROR_PARTIAL_INPUT, + G_CONVERT_ERROR_NOT_LOCAL_FILE, + G_CONVERT_ERROR_INVALID_URI, + G_CONVERT_ERROR_NOT_ABSOLUTE_PATH } GConvertError; #define G_CONVERT_ERROR g_convert_error_quark() @@ -107,6 +110,15 @@ gchar* g_filename_from_utf8 (const gchar *utf8string, gsize *bytes_written, GError **error); +gchar *g_filename_from_uri (const char *uri, + char **hostname, + GError **error); + +gchar *g_filename_to_uri (const char *filename, + char *hostname, + GError **error); + + G_END_DECLS #endif /* __G_CONVERT_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 59e96e3..d2fdf5e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -75,7 +75,8 @@ test_programs = \ tree-test \ type-test \ unicode-caseconv \ - unicode-encoding + unicode-encoding \ + uri-test test_scripts = run-markup-tests.sh @@ -117,6 +118,7 @@ tree_test_LDADD = $(progs_LDADD) type_test_LDADD = $(progs_LDADD) unicode_encoding_LDADD = $(progs_LDADD) unicode_caseconv_LDADD = $(progs_LDADD) +uri_test_LDADD = $(progs_LDADD) lib_LTLIBRARIES = libmoduletestplugin_a.la libmoduletestplugin_b.la diff --git a/tests/uri-test.c b/tests/uri-test.c new file mode 100644 index 0000000..87b2a62 --- /dev/null +++ b/tests/uri-test.c @@ -0,0 +1,224 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#undef G_DISABLE_ASSERT +#undef G_LOG_DOMAIN + +#include +#include +#include +#include + +typedef struct +{ + char *filename; + char *hostname; + char *expected_result; + GConvertError expected_error; /* If failed */ +} ToUriTest; + +ToUriTest +to_uri_tests[] = { + { "/etc", NULL, "file:///etc"}, + { "/etc", "", "file:///etc"}, + { "/etc", "localhost", "file://localhost/etc"}, +#ifdef G_OS_WIN32 + { "c:\\windows", NULL, "file:///c:\\windows"}, + { "c:\\windows", "localhost", "file://localhost/c:\\windows"}, +#endif + { "etc", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH}, + { "/etc/öäå", NULL, NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/etc/öäå", NULL, "file:///etc/%C3%B6%C3%A4%C3%A5"}, + { "/etc", "öäå", "file://%C3%B6%C3%A4%C3%A5/etc"}, + { "/etc", "åäö", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/etc/file with #%", NULL, "file:///etc/file%20with%20%23%25"}, +}; + + +typedef struct +{ + char *uri; + char *expected_filename; + char *expected_hostname; + GConvertError expected_error; /* If failed */ +} FromUriTest; + +FromUriTest +from_uri_tests[] = { + { "file:///etc", "/etc", NULL}, + { "file:/etc", "/etc", NULL}, + { "file://localhost/etc", "/etc", "localhost", }, + { "file://localhost/etc/%23%25%20file", "/etc/#% file", "localhost", }, + { "file://%C3%B6%C3%A4%C3%A5/etc", "/etc", "öäå", }, + { "file:////etc/%C3%B6%C3%C3%C3%A5", NULL, NULL, G_CONVERT_ERROR_INVALID_URI}, + { "file://localhost/åäö", NULL, NULL, G_CONVERT_ERROR_INVALID_URI}, + { "file://åäö/etc", NULL, NULL, G_CONVERT_ERROR_INVALID_URI}, + { "file:///some/file#bad", NULL, NULL, G_CONVERT_ERROR_INVALID_URI}, + { "file://some", NULL, NULL, G_CONVERT_ERROR_INVALID_URI}, +}; + + +static gboolean any_failed = FALSE; + +static void +run_to_uri_tests (void) +{ + int i; + gchar *res; + GError *error; + + for (i = 0; i < G_N_ELEMENTS (to_uri_tests); i++) + { + error = NULL; + res = g_filename_to_uri (to_uri_tests[i].filename, + to_uri_tests[i].hostname, + &error); + + if (to_uri_tests[i].expected_result == NULL) + { + if (res != NULL) + { + g_print ("\ng_filename_to_uri() test %d failed, expected to return NULL, actual result: %s\n", i, res); + any_failed = TRUE; + } + else + { + if (error == NULL) + { + g_print ("\ng_filename_to_uri() test %d failed, returned NULL, but didn't set error\n", i); + any_failed = TRUE; + } + else if (error->domain != G_CONVERT_ERROR) + { + g_print ("\ng_filename_to_uri() test %d failed, returned NULL, set non G_CONVERT_ERROR error\n", i); + any_failed = TRUE; + } + else if (error->code != to_uri_tests[i].expected_error) + { + g_print ("\ng_filename_to_uri() test %d failed as expected, but set wrong errorcode %d instead of expected %d \n", + i, error->code, to_uri_tests[i].expected_error); + any_failed = TRUE; + } + } + } + else if (res == NULL || strcmp (res, to_uri_tests[i].expected_result) != 0) + { + g_print ("\ng_filename_to_uri() test %d failed, expected result: %s, actual result: %s\n", + i, to_uri_tests[i].expected_result, (res) ? res : "NULL"); + if (error) + g_print ("Error message: %s\n", error->message); + any_failed = TRUE; + } + + /* Give some output */ + g_print ("."); + } +} + +static void +run_from_uri_tests (void) +{ + int i; + gchar *res; + gchar *hostname; + GError *error; + + for (i = 0; i < G_N_ELEMENTS (from_uri_tests); i++) + { + error = NULL; + res = g_filename_from_uri (from_uri_tests[i].uri, + &hostname, + &error); + + if (from_uri_tests[i].expected_filename == NULL) + { + if (res != NULL) + { + g_print ("\ng_filename_from_uri() test %d failed, expected to return NULL, actual result: %s\n", i, res); + any_failed = TRUE; + } + else + { + if (error == NULL) + { + g_print ("\ng_filename_from_uri() test %d failed, returned NULL, but didn't set error\n", i); + any_failed = TRUE; + } + else if (error->domain != G_CONVERT_ERROR) + { + g_print ("\ng_filename_from_uri() test %d failed, returned NULL, set non G_CONVERT_ERROR error\n", i); + any_failed = TRUE; + } + else if (error->code != from_uri_tests[i].expected_error) + { + g_print ("\ng_filename_from_uri() test %d failed as expected, but set wrong errorcode %d instead of expected %d \n", + i, error->code, from_uri_tests[i].expected_error); + any_failed = TRUE; + } + } + } + else + { + if (res == NULL || strcmp (res, from_uri_tests[i].expected_filename) != 0) + { + g_print ("\ng_filename_from_uri() test %d failed, expected result: %s, actual result: %s\n", + i, from_uri_tests[i].expected_filename, (res) ? res : "NULL"); + any_failed = TRUE; + } + + if (from_uri_tests[i].expected_hostname == NULL) + { + if (hostname != NULL) + { + g_print ("\ng_filename_from_uri() test %d failed, expected no hostname, got: %s\n", + i, hostname); + any_failed = TRUE; + } + } + else if (hostname == NULL || + strcmp (hostname, from_uri_tests[i].expected_hostname) != 0) + { + g_print ("\ng_filename_from_uri() test %d failed, expected hostname: %s, actual result: %s\n", + i, from_uri_tests[i].expected_hostname, (hostname) ? hostname : "NULL"); + any_failed = TRUE; + } + } + + /* Give some output */ + g_print ("."); + } + g_print ("\n"); +} + +int +main (int argc, + char *argv[]) +{ + run_to_uri_tests (); + run_from_uri_tests (); + + return any_failed ? 1 : 0; +} -- 2.7.4