From a3596a5e3ec4937a220e6e60218639e2aba82701 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 May 2005 23:18:13 +0000 Subject: * utf-8 collation of domain names * case insensitive comparison of domain names git-svn-id: file:///home/lennart/svn/public/avahi/trunk@71 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/util.c | 236 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 200 insertions(+), 36 deletions(-) (limited to 'avahi-core/util.c') diff --git a/avahi-core/util.c b/avahi-core/util.c index fa97eec..086c041 100644 --- a/avahi-core/util.c +++ b/avahi-core/util.c @@ -43,19 +43,60 @@ gchar *avahi_get_host_name(void) { return avahi_normalize_name(t); } +static gchar *unescape_uneeded(const gchar *src, gchar *ret_dest, size_t size) { + gboolean escaped = FALSE; + + g_assert(src); + g_assert(ret_dest); + g_assert(size > 0); + + for (; *src; src++) { + + if (!escaped && *src == '\\') + escaped = TRUE; + else if (escaped && (*src == '.' || *src == '\\')) { + + if ((size -= 2) <= 1) break; + + *(ret_dest++) = '\\'; + *(ret_dest++) = *src; + + escaped = FALSE; + } else { + if (--size <= 1) break; + + *(ret_dest++) = *src; + escaped = FALSE; + } + + } + + *ret_dest = 0; + + return ret_dest; +} + gchar *avahi_normalize_name(const gchar *s) { - size_t l; + gchar tmp[256]; + gchar *n, *t; + guint l; g_assert(s); - l = strlen(s); + unescape_uneeded(s, tmp, sizeof(tmp)); - if (!l) + n = g_utf8_normalize(tmp, -1, G_NORMALIZE_DEFAULT); + + if ((l = strlen(n)) == 0) { + g_free(n); return g_strdup("."); + } - if (s[l-1] == '.') - return g_strdup(s); - - return g_strdup_printf("%s.", s); + if (n[l-1] == '.') + return n; + + t = g_strdup_printf("%s.", n); + g_free(n); + return t; } gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b) { @@ -158,50 +199,151 @@ gint avahi_age(const GTimeVal *a) { return avahi_timeval_diff(&now, a); } -gboolean avahi_domain_cmp(const gchar *a, const gchar *b) { - int escaped_a = 0, escaped_b = 0; - g_assert(a); - g_assert(b); +/* Read the first label from string *name, unescape "\" and write it to dest */ +gchar *avahi_unescape_label(const gchar **name, gchar *dest, guint size) { + guint i = 0; + gchar *d; + + g_assert(dest); + g_assert(size > 0); + g_assert(name); - for (;;) { - /* Check for escape characters "\" */ - if ((escaped_a = *a == '\\')) - a ++; + if (!**name) + return NULL; - if ((escaped_b = *b == '\\')) - b++; + d = dest; + + for (;;) { + if (i >= size) + return NULL; - /* Check for string end */ - if (*a == 0 && *b == 0) - return 0; + if (**name == '.') { + (*name)++; + break; + } - if (*a == 0 && !escaped_b && *b == '.' && *(b+1) == 0) - return 0; + if (**name == 0) + break; + + if (**name == '\\') { + (*name) ++; + + if (**name == 0) + break; + } + + *(d++) = *((*name) ++); + i++; + } - if (!escaped_a && *a == '.' && *(a+1) == 0 && *b == 0) - return 0; + g_assert(i < size); + + *d = 0; + + return dest; +} - /* Compare characters */ - if (escaped_a == escaped_b && *a != *b) - return *a < *b ? -1 : 1; +/* Escape "\" and ".", append \0 */ +gchar *avahi_escape_label(const guint8* src, guint src_length, gchar **ret_name, guint *ret_size) { + gchar *r; + + g_assert(src); + g_assert(ret_name); + g_assert(*ret_name); + g_assert(ret_size); + g_assert(*ret_size > 0); + + r = *ret_name; + + while (src_length > 0) { + if (*src == '.' || *src == '\\') { + if (*ret_size < 3) + return NULL; + + *((*ret_name) ++) = '\\'; + (*ret_size) --; + } - /* Next characters */ - a++; - b++; + if (*ret_size < 2) + return NULL; + *((*ret_name)++) = *src; + (*ret_size) --; + + src_length --; + src++; } + + **ret_name = 0; + + return r; +} + +static gint utf8_strcasecmp(const gchar *a, const gchar *b) { + gchar *ta, *tb; + gint r; + + g_assert(a); + g_assert(b); + + ta = g_utf8_casefold(a, -1); + tb = g_utf8_casefold(b, -1); + r = g_utf8_collate(ta, tb); + g_free(ta); + g_free(tb); + + return r; } gboolean avahi_domain_equal(const gchar *a, const gchar *b) { - return avahi_domain_cmp(a, b) == 0; + g_assert(a); + g_assert(b); + + if (a == b) + return TRUE; + + for (;;) { + gchar ca[65], cb[65], *pa, *pb; + + pa = avahi_unescape_label(&a, ca, sizeof(ca)); + pb = avahi_unescape_label(&b, cb, sizeof(cb)); + + if (!pa && !pb) + return TRUE; + else if ((pa && !pb) || (!pa && pb)) + return FALSE; + + if (utf8_strcasecmp(pa, pb)) + return FALSE; + } + + return TRUE; } -guint avahi_domain_hash(const gchar *p) { - char t[256]; - strncpy(t, p, sizeof(t)-1); - t[sizeof(t)-1] = 0; +gint avahi_binary_domain_cmp(const gchar *a, const gchar *b) { + g_assert(a); + g_assert(b); + + if (a == b) + return 0; + + for (;;) { + gchar ca[65], cb[65], *pa, *pb; + gint r; + + pa = avahi_unescape_label(&a, ca, sizeof(ca)); + pb = avahi_unescape_label(&b, cb, sizeof(cb)); - return g_int_hash(t); + if (!pa && !pb) + return 0; + else if (pa && !pb) + return 1; + else if (!pa && pb) + return -1; + + if ((r = strcmp(pa, pb))) + return r; + } } void avahi_hexdump(gconstpointer p, guint size) { @@ -237,3 +379,25 @@ void avahi_hexdump(gconstpointer p, guint size) { size -= 16; } } + +gint avahi_domain_hash(const gchar *s) { + guint hash = 0; + + for (;;) { + gchar c[65], *n, *m; + + if (!avahi_unescape_label(&s, c, sizeof(c))) + return hash; + + if (!c[0]) + continue; + + n = g_utf8_normalize(c, -1, G_NORMALIZE_DEFAULT); + m = g_utf8_strdown(n, -1); + + hash += g_str_hash(m); + + g_free(m); + g_free(n); + } +} -- cgit