]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/unicode/charcnv.c
fix macname cache, SF bug 1021642
[netatalk.git] / libatalk / unicode / charcnv.c
index 9b9a8d32f47631c52c211b7ec883a632c118a3bc..11b5e4dbad48d233b6225684bfdffab5fcdcafa7 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <sys/param.h>
 #include <ctype.h>
-#include <sys/stat.h>
-#include <atalk/logger.h>
 #include <errno.h>
-
-#include <netatalk/endian.h>
-#include <atalk/unicode.h>
-
+#include <sys/stat.h>
+#include <sys/param.h>
 #ifdef HAVE_USABLE_ICONV
 #include <iconv.h>
 #endif
-
 #if HAVE_LOCALE_H
 #include <locale.h>
 #endif
-
 #if HAVE_LANGINFO_H
 #include <langinfo.h>
 #endif
 
+#include <netatalk/endian.h>
+#include <atalk/logger.h>
+#include <atalk/unicode.h>
+#include <atalk/util.h>
+#include "byteorder.h"
+
 
 /**
  * @file
@@ -77,18 +76,65 @@ static struct charset_functions* charsets[MAX_CHARSETS];
 static char hexdig[] = "0123456789abcdef";
 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
 
+static char* read_charsets_from_env(charset_t ch) 
+{
+       char *name;
+
+       switch (ch) {
+           case CH_MAC:
+                if (( name = getenv( "ATALK_MAC_CHARSET" )) != NULL ) 
+                   return name;
+               else
+                   return "MAC_ROMAN";
+               break;
+            case CH_UNIX:
+                if (( name = getenv( "ATALK_UNIX_CHARSET" )) != NULL ) 
+                   return name;
+               else
+                   return "LOCALE";
+               break;
+           default:
+               break;
+        }
+        return "ASCII";
+} 
+           
+
 /**
  * Return the name of a charset to give to iconv().
  **/
 static const char *charset_name(charset_t ch)
 {
        const char *ret = NULL;
+       static int first = 1;
+       static char macname[128];
+       static char unixname[128];
+
+       if (first) {
+               memset(macname, 0, sizeof(macname));
+               memset(unixname, 0, sizeof(unixname));
+               first = 0;
+       }
 
-       if (ch == CH_UCS2) ret = "UCS-2LE";
-       else if (ch == CH_UNIX) ret = "LOCALE"; /*lp_unix_charset();*/
-       else if (ch == CH_MAC) ret = "MAC_ROMAN"; /*lp_display_charset();*/
+       if (ch == CH_UCS2) ret = "UCS-2";
        else if (ch == CH_UTF8) ret = "UTF8";
        else if (ch == CH_UTF8_MAC) ret = "UTF8-MAC";
+       else if (ch == CH_UNIX) {
+               if (unixname[0] == '\0') {
+                       ret = read_charsets_from_env(CH_UNIX);
+                       strlcpy(unixname, ret, sizeof(unixname));
+               }
+               else
+                       ret = unixname;
+       }
+       else if (ch == CH_MAC) {
+               if (macname[0] == '\0') {
+                       ret = read_charsets_from_env(CH_MAC);
+                       strlcpy(macname, ret, sizeof(macname));
+               }
+               else
+                       ret = macname;
+       }
 
        if (!ret)
                ret = charset_names[ch];
@@ -104,16 +150,20 @@ static const char *charset_name(charset_t ch)
                if (ln) {
                        /* Check whether the charset name is supported
                           by iconv */
-                       atalk_iconv_t handle = atalk_iconv_open(ln,"UCS-2LE");
+                       atalk_iconv_t handle = atalk_iconv_open(ln, "UCS-2");
                        if (handle == (atalk_iconv_t) -1) {
                                LOG(log_debug, logtype_default, "Locale charset '%s' unsupported, using ASCII instead", ln);
-                               ln = NULL;
+                               ln = "ASCII";
                        } else {
                                atalk_iconv_close(handle);
                        }
+                       if (ch==CH_UNIX)
+                               strlcpy(unixname, ln, sizeof(unixname));
                }
                ret = ln;
        }
+#else /* system doesn't have LOCALE support */
+if (ch == CH_UNIX) ret = NULL;
 #endif
 
        if (!ret || !*ret) ret = "ASCII";
@@ -201,14 +251,6 @@ void init_iconv(void)
 {
        int c1;
 
-       /* so that charset_name() works we need to get the UNIX<->UCS2 going
-          first */
-       if (!conv_handles[CH_UNIX][CH_UCS2])
-               conv_handles[CH_UNIX][CH_UCS2] = atalk_iconv_open("UCS-2LE", "ASCII");
-
-       if (!conv_handles[CH_UCS2][CH_UNIX])
-               conv_handles[CH_UCS2][CH_UNIX] = atalk_iconv_open("ASCII", "UCS-2LE");
-
        for (c1=0;c1<NUM_CHARSETS;c1++) {
                const char *name = charset_name((charset_t)c1);
 
@@ -219,11 +261,13 @@ void init_iconv(void)
                        conv_handles[c1][CH_UCS2] = NULL;
                }
 
-               conv_handles[CH_UCS2][c1] = atalk_iconv_open( name, charset_name(CH_UCS2));
-               if (conv_handles[CH_UCS2][1] == (atalk_iconv_t)-1) {
-                       LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
-                               charset_name(CH_UCS2), name);
-                       conv_handles[c1][c1] = NULL;
+               if (c1 != CH_UCS2) { /* avoid lost memory, make valgrind happy */
+                       conv_handles[CH_UCS2][c1] = atalk_iconv_open( name, charset_name(CH_UCS2));
+                       if (conv_handles[CH_UCS2][c1] == (atalk_iconv_t)-1) {
+                               LOG(log_error, logtype_default, "Required conversion from %s to %s not supported",
+                                       charset_name(CH_UCS2), name);
+                               conv_handles[CH_UCS2][c1] = NULL;
+                       }
                }
                
                charsets[c1] = get_charset_functions (c1);
@@ -247,6 +291,7 @@ static size_t convert_string_internal(charset_t from, charset_t to,
        size_t retval;
        const char* inbuf = (const char*)src;
        char* outbuf = (char*)dest;
+       char* o_save = outbuf;
        atalk_iconv_t descriptor;
 
        if (srclen == (size_t)-1)
@@ -276,17 +321,20 @@ static size_t convert_string_internal(charset_t from, charset_t to,
                               reason="Illegal multibyte sequence";
                               break;
                }
-               LOG(log_debug, logtype_default,"Conversion error: %s(%s)\n",reason,inbuf);
+               LOG(log_debug, logtype_default,"Conversion error: %s",reason);
                return (size_t)-1;
        }
 
        /* Terminate the string */
        if (to == CH_UCS2 && destlen-o_len >= 2) {
-               *outbuf++ = 0;
-               *outbuf++ = 0;
+               o_save[destlen-o_len]   = 0;
+               o_save[destlen-o_len+1] = 0;
+       }
+       else if ( to != CH_UCS2 && destlen-o_len > 0 )
+               o_save[destlen-o_len] = 0;
+       else {
+               /* FIXME: what should we do here, string *might* be unterminated. E2BIG? */
        }
-       else if ( destlen-o_len > 0)
-               *outbuf++ = 0;
 
        return destlen-o_len;
 }
@@ -297,15 +345,16 @@ size_t convert_string(charset_t from, charset_t to,
                      void *dest, size_t destlen)
 {
        size_t i_len, o_len;
-       char *u;
-       char buffer[MAXPATHLEN];
-       char buffer2[MAXPATHLEN];
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
        int composition = 0;
 
        lazy_initialize_conv();
 
        /* convert from_set to UCS2 */
-       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, buffer, MAXPATHLEN)) ) {
+       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, 
+                                                               (char*) buffer, sizeof(buffer))) ) {
                LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from));
                return (size_t) -1;
        }
@@ -317,7 +366,7 @@ size_t convert_string(charset_t from, charset_t to,
        if ((charsets[to] && charsets[to]->flags & CHARSET_DECOMPOSED) )
            composition = 2;
  
-       i_len = MAXPATHLEN;
+       i_len = sizeof(buffer2);
        u = buffer2;
 
        switch (composition) {
@@ -326,17 +375,17 @@ size_t convert_string(charset_t from, charset_t to,
            i_len = o_len;
            break;
        case 1:
-            if ( (size_t)-1 == (i_len = precompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        case 2:
-            if ( (size_t)-1 == (i_len = decompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        }
                
        /* Convert UCS2 to to_set */
-       if ((size_t)(-1) == ( o_len = convert_string_internal( CH_UCS2, to, u, i_len, dest, destlen)) ) {
+       if ((size_t)(-1) == ( o_len = convert_string_internal( CH_UCS2, to, (char*) u, i_len, dest, destlen)) ) {
                LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to), strerror(errno));
                return (size_t) -1;
        }
@@ -362,7 +411,7 @@ static size_t convert_string_allocate_internal(charset_t from, charset_t to,
        size_t i_len, o_len, destlen;
        size_t retval;
        const char *inbuf = (const char *)src;
-       char *outbuf, *ob;
+       char *outbuf = NULL, *ob = NULL;
        atalk_iconv_t descriptor;
 
        *dest = NULL;
@@ -376,22 +425,22 @@ static size_t convert_string_allocate_internal(charset_t from, charset_t to,
 
        if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
                /* conversion not supported, return -1*/
-               LOG(log_debug, logtype_default, "convert_string_allocate: conversion not supported!\n");
+               LOG(log_debug, logtype_default, "convert_string_allocate: conversion not supported!");
                return -1;
        }
 
        destlen = MAX(srclen, 512);
-       outbuf = NULL;
 convert:
        destlen = destlen * 2;
-       ob = (char *)realloc(outbuf, destlen);
-       if (!ob) {
-               LOG(log_debug, logtype_default,"convert_string_allocate: realloc failed!\n");
-               SAFE_FREE(outbuf);
+       outbuf = (char *)realloc(ob, destlen);
+       if (!outbuf) {
+               LOG(log_debug, logtype_default,"convert_string_allocate: realloc failed!");
+               SAFE_FREE(ob);
                return (size_t)-1;
        } else {
-               outbuf = ob;
+               ob = outbuf;
        }
+       inbuf = src;   /* this restarts the whole conversion if buffer needed to be increased */
        i_len = srclen;
        o_len = destlen;
        retval = atalk_iconv(descriptor,
@@ -409,8 +458,8 @@ convert:
                                reason="Illegal multibyte sequence";
                                break;
                }
-               LOG(log_debug, logtype_default,"Conversion error: %s(%s)\n",reason,inbuf);
-               /* smb_panic(reason); */
+               LOG(log_debug, logtype_default,"Conversion error: %s(%s)",reason,inbuf);
+               SAFE_FREE(ob);
                return (size_t)-1;
        }
 
@@ -418,18 +467,21 @@ convert:
        destlen = destlen - o_len;
 
        /* Terminate the string */
-       if (to == CH_UCS2 && destlen-o_len >= 2) {
-               *outbuf++ = 0;
-               *outbuf++ = 0;
+       if (to == CH_UCS2 && o_len >= 2) {
+               ob[destlen] = 0;
+               ob[destlen+1] = 0;
                *dest = (char *)realloc(ob,destlen+2);
        }
-       else if ( destlen-o_len > 0) {
-               *outbuf++ = 0;
+       else if ( to != CH_UCS2 && o_len > 0 ) {
+               ob[destlen] = 0;
                *dest = (char *)realloc(ob,destlen+1);
        }
+       else {
+               goto convert; /* realloc */
+       }
 
        if (destlen && !*dest) {
-               LOG(log_debug, logtype_default, "convert_string_allocate: out of memory!\n");
+               LOG(log_debug, logtype_default, "convert_string_allocate: out of memory!");
                SAFE_FREE(ob);
                return (size_t)-1;
        }
@@ -443,15 +495,18 @@ size_t convert_string_allocate(charset_t from, charset_t to,
                      char ** dest)
 {
        size_t i_len, o_len;
-       char *u;
-       char buffer[MAXPATHLEN];
-       char buffer2[MAXPATHLEN];
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
        int composition = 0;
 
        lazy_initialize_conv();
 
+       *dest = NULL;
+
        /* convert from_set to UCS2 */
-       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, buffer, MAXPATHLEN)) ) {
+       if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, 
+                                                               buffer, sizeof(buffer))) ) {
                LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from));
                return (size_t) -1;
        }
@@ -463,7 +518,7 @@ size_t convert_string_allocate(charset_t from, charset_t to,
        if ((charsets[to] && charsets[to]->flags & CHARSET_DECOMPOSED) )
            composition = 2;
  
-       i_len = MAXPATHLEN;
+       i_len = sizeof(buffer2);
        u = buffer2;
 
        switch (composition) {
@@ -472,17 +527,17 @@ size_t convert_string_allocate(charset_t from, charset_t to,
            i_len = o_len;
            break;
        case 1:
-            if ( (size_t)-1 == (i_len = precompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        case 2:
-            if ( (size_t)-1 == (i_len = decompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        }
                
        /* Convert UCS2 to to_set */
-       if ((size_t)(-1) == ( o_len = convert_string_allocate_internal( CH_UCS2, to, u, i_len, dest)) ) 
+       if ((size_t)(-1) == ( o_len = convert_string_allocate_internal( CH_UCS2, to, (char*)u, i_len, dest)) ) 
                LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to), strerror(errno));
                
        return o_len;
@@ -497,7 +552,7 @@ size_t charset_strupper(charset_t ch, const char *src, size_t srclen, char *dest
        size = convert_string_allocate_internal(ch, CH_UCS2, src, srclen,
                                       (char**) &buffer);
        if (size == (size_t)-1) {
-               free(buffer);
+               SAFE_FREE(buffer);
                return size;
        }
        if (!strupper_w((ucs2_t *)buffer) && (dest == src)) {
@@ -518,7 +573,7 @@ size_t charset_strlower(charset_t ch, const char *src, size_t srclen, char *dest
        size = convert_string_allocate_internal(ch, CH_UCS2, src, srclen,
                                       (char **) &buffer);
        if (size == (size_t)-1) {
-               free(buffer);
+               SAFE_FREE(buffer);
                return size;
        }
        if (!strlower_w((ucs2_t *)buffer) && (dest == src)) {
@@ -563,7 +618,7 @@ size_t utf8_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
 
 size_t charset_to_ucs2_allocate(charset_t ch, ucs2_t **dest, const char *src)
 {
-       size_t src_len = strlen(src)+1;
+       size_t src_len = strlen(src);
 
        *dest = NULL;
        return convert_string_allocate(ch, CH_UCS2, src, src_len, (char**) dest);       
@@ -579,7 +634,7 @@ size_t charset_to_ucs2_allocate(charset_t ch, ucs2_t **dest, const char *src)
 
 size_t charset_to_utf8_allocate(charset_t ch, char **dest, const char *src)
 {
-       size_t src_len = strlen(src)+1;
+       size_t src_len = strlen(src);
 
        *dest = NULL;
        return convert_string_allocate(ch, CH_UTF8, src, src_len, dest);        
@@ -593,9 +648,16 @@ size_t charset_to_utf8_allocate(charset_t ch, char **dest, const char *src)
  * @returns The number of bytes occupied by the string in the destination
  **/
 
+size_t ucs2_to_charset(charset_t ch, const ucs2_t *src, char *dest, size_t destlen)
+{
+       size_t src_len = (strlen_w(src)) * sizeof(ucs2_t);
+       return convert_string(CH_UCS2, ch, src, src_len, dest, destlen);        
+}
+
+
 size_t ucs2_to_charset_allocate(charset_t ch, char **dest, const ucs2_t *src)
 {
-       size_t src_len = (strlen_w(src)+1) * sizeof(ucs2_t);
+       size_t src_len = (strlen_w(src)) * sizeof(ucs2_t);
        *dest = NULL;
        return convert_string_allocate(CH_UCS2, ch, src, src_len, dest);        
 }
@@ -618,21 +680,21 @@ size_t utf8_to_charset_allocate(charset_t ch, char **dest, const char *src)
 size_t charset_precompose ( charset_t ch, char * src, size_t inlen, char * dst, size_t outlen)
 {
        char *buffer;
-       char u[MAXPATHLEN];
+       ucs2_t u[MAXPATHLEN];
        size_t len;
        size_t ilen;
 
         if ((size_t)(-1) == (len = convert_string_allocate_internal(ch, CH_UCS2, src, inlen, &buffer)) )
             return len;
 
-       ilen=MAXPATHLEN;
+       ilen=sizeof(u);
 
-       if ( (size_t)-1 == (ilen = precompose_w((ucs2_t *)buffer, len, (ucs2_t *)u, &ilen)) ) {
+       if ( (size_t)-1 == (ilen = precompose_w((ucs2_t *)buffer, len, u, &ilen)) ) {
            free (buffer);
            return (size_t)(-1);
        }
 
-        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, u, ilen, dst, outlen)) ) {
+        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, (char*)u, ilen, dst, outlen)) ) {
            free (buffer);
            return (size_t)(-1);
        }
@@ -645,21 +707,21 @@ size_t charset_precompose ( charset_t ch, char * src, size_t inlen, char * dst,
 size_t charset_decompose ( charset_t ch, char * src, size_t inlen, char * dst, size_t outlen)
 {
        char *buffer;
-       char u[MAXPATHLEN];
+       ucs2_t u[MAXPATHLEN];
        size_t len;
        size_t ilen;
 
         if ((size_t)(-1) == (len = convert_string_allocate_internal(ch, CH_UCS2, src, inlen, &buffer)) )
             return len;
 
-       ilen=MAXPATHLEN;
+       ilen=sizeof(u);
 
-       if ( (size_t)-1 == (ilen = decompose_w((ucs2_t *)buffer, len, (ucs2_t *)u, &ilen)) ) {
+       if ( (size_t)-1 == (ilen = decompose_w((ucs2_t *)buffer, len, u, &ilen)) ) {
            free (buffer);
            return (size_t)(-1);
        }
 
-        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, u, ilen, dst, outlen)) ) {
+        if ((size_t)(-1) == (len = convert_string_internal( CH_UCS2, ch, (char*)u, ilen, dst, outlen)) ) {
            free (buffer);
            return (size_t)(-1);
        }
@@ -679,6 +741,7 @@ size_t utf8_decompose ( char * src, size_t inlen, char * dst, size_t outlen)
        return charset_decompose ( CH_UTF8, src, inlen, dst, outlen);
 }
 
+#if 0
 static char  debugbuf[ MAXPATHLEN +1 ];
 char * debug_out ( char * seq, size_t len)
 {
@@ -699,12 +762,13 @@ char * debug_out ( char * seq, size_t len)
         q = debugbuf;
         return q;
 }
+#endif
 
 /* 
  * Convert from MB to UCS2 charset 
  * Flags:
- *             CONV_UNESCAPEHEX:        ':XXXX' will be converted to an UCS2 character
- *             CONV_IGNORE:            unconvertable characters will be replaced with '_'
+ *             CONV_UNESCAPEHEX:        ':XX' will be converted to an UCS2 character
+ *             CONV_IGNORE:             return the first convertable characters.
  * FIXME:
  *             This will *not* work if the destination charset is not multibyte, i.e. UCS2->UCS2 will fail
  *             The (un)escape scheme is not compatible to the old cap style escape. This is bad, we need it 
@@ -750,19 +814,9 @@ conversion_loop:
        
        retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
        if(retval==(size_t)-1) {
-               if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
-                               if (o_len < 2) {
-                                       errno = E2BIG;
-                                       return (size_t) -1;
-                               }
-                               o_save[destlen-o_len]   = '_';
-                               o_save[destlen-o_len+1] = 0x0;
-                               o_len -= 2;
-                               outbuf = o_save + destlen - o_len;
-                               inbuf += 1;
-                               i_len -= 1;
+           if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
                                *flags |= CONV_REQMANGLE;
-                               goto conversion_loop;
+                               return destlen-o_len;
            }
            else
                return (size_t) -1;
@@ -790,17 +844,8 @@ unhex_char:
                        h_buf = (const char*) h;
                        if ((size_t) -1 == (retval = atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len)) ) {
                                if (errno == EILSEQ && CHECK_FLAGS(flags, CONV_IGNORE)) {
-                                       if (o_len < hlen) {
-                                               errno = E2BIG;
-                                               return retval;
-                                       }
-                                       while ( hlen > 0) {
-                                               *outbuf++ = '_';
-                                               *outbuf++ = 0;
-                                               o_len -= 2;
-                                               hlen -= 1;
-                                               *flags |= CONV_REQMANGLE;
-                                       }
+                                       *flags |= CONV_REQMANGLE;
+                                       return destlen-o_len;
                                }
                                else {
                                        return retval;
@@ -810,12 +855,8 @@ unhex_char:
                else {
                        /* We have an invalid :xx sequence */
                        if (CHECK_FLAGS(flags, CONV_IGNORE)) {
-                               *outbuf++ = '_';
-                               *outbuf++ = 0;
-                               inbuf++;
-                               o_len -= 2;
-                               j -= 1;
                                *flags |= CONV_REQMANGLE;
+                               return destlen-o_len;
                        }
                        else {
                                errno=EILSEQ;
@@ -828,6 +869,8 @@ unhex_char:
                        goto conversion_loop;
        }
 
+
+
        return destlen-o_len;
 }
 
@@ -835,7 +878,7 @@ unhex_char:
  * Convert from UCS2 to MB charset 
  * Flags:
  *             CONV_ESCAPEDOTS: escape leading dots
- *             CONV_ESCAPEHEX:  unconvertable characters and '/' will be escaped to :XXXX
+ *             CONV_ESCAPEHEX:  unconvertable characters and '/' will be escaped to :XX
  *             CONV_IGNORE:     unconvertable characters will be replaced with '_'
  * FIXME:
  *             CONV_IGNORE and CONV_ESCAPEHEX can't work together. Should we check this ?
@@ -868,7 +911,7 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src
     o_len=destlen;
     o_save=outbuf;
     
-    if (*inbuf == '.' && flags && (*flags & CONV_ESCAPEDOTS)) {
+    if ( SVAL(inbuf,0) == 0x002e && flags && (*flags & CONV_ESCAPEDOTS)) { /* 0x002e = . */
         if (o_len < 3) {
             errno = E2BIG;
             return (size_t) -1;
@@ -886,31 +929,23 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src
 conversion_loop:
     if ( flags && (*flags & CONV_ESCAPEHEX)) {
         for ( i = 0; i < i_len; i+=2) {
-            if ( inbuf[i] == '/' ) {
+            if ( SVAL((inbuf+i),0) == 0x002f) { /* 0x002f = / */
                 j = i_len - i;
                 if ( 0 == ( i_len = i))
                     goto escape_slash;
                 break;
-            }
+            } else if ( SVAL(inbuf+i,0) == 0x003a) { /* 0x003a = : */
+               errno = EILSEQ;
+               return (size_t) -1;
+           }
         }
     }
     
     retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
     if (retval==(size_t)-1) {
-        if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
-            if (o_len == 0) {
-                errno = E2BIG;
-                return (size_t) -1;
-            }
-            o_save[destlen-o_len] = '_';
-            o_len -=1;
-            outbuf = o_save + destlen - o_len;
-            inbuf += 2;
-            i_len -= 2;
-            if (flags ) 
-                *flags |= CONV_REQMANGLE;
-           if (i_len)
-                goto conversion_loop;
+        if (errno == EILSEQ && CHECK_FLAGS(flags, CONV_IGNORE)) {
+            *flags |= CONV_REQMANGLE;
+           return destlen -o_len;
         }
         else if ( errno == EILSEQ && flags && (*flags & CONV_ESCAPEHEX)) {
             if (o_len < 3) {
@@ -935,6 +970,7 @@ conversion_loop:
            SAFE_FREE(buf_save);
            buflen = 0;
            i_len -= 2;
+           inbuf += 2;
             if (flags) *flags |= CONV_REQESCAPE;
            if ( i_len > 0)
                goto conversion_loop;
@@ -966,19 +1002,23 @@ escape_slash:
 size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, char* src, size_t src_len, char* dest, size_t dest_len, u_int16_t *flags)
 {
        size_t i_len, o_len;
-       char *u;
-       char buffer[MAXPATHLEN];
-       char buffer2[MAXPATHLEN];
+       ucs2_t *u;
+       ucs2_t buffer[MAXPATHLEN];
+       ucs2_t buffer2[MAXPATHLEN];
        int composition = 0;
        
        lazy_initialize_conv();
 
        /* convert from_set to UCS2 */
-       if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, cap_charset, src, src_len, buffer, MAXPATHLEN, flags)) ) {
+       if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, cap_charset, src, src_len, 
+                                                          (char *) buffer, sizeof(buffer), flags)) ) {
                LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set));
                return (size_t) -1;
        }
 
+       if ( o_len == 0)
+               return o_len;
+
        /* Do pre/decomposition */
        if (CHECK_FLAGS(flags, CONV_PRECOMPOSE) || 
                ((!(charsets[to_set])   || !(charsets[to_set]->flags & CHARSET_DECOMPOSED)) && 
@@ -987,7 +1027,7 @@ size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_cha
        if (CHECK_FLAGS(flags, CONV_DECOMPOSE) || (charsets[to_set] && charsets[to_set]->flags & CHARSET_DECOMPOSED) )
            composition = 2;
  
-       i_len = MAXPATHLEN;
+       i_len = sizeof(buffer2);
        u = buffer2;
 
        switch (composition) {
@@ -996,27 +1036,25 @@ size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_cha
            i_len = o_len;
            break;
        case 1:
-            if ( (size_t)-1 == (i_len = precompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        case 2:
-            if ( (size_t)-1 == (i_len = decompose_w((ucs2_t *)buffer, o_len, (ucs2_t *)u, &i_len)) )
+            if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) )
                return (size_t)(-1);
            break;
        }
                
        /* Do case conversions */       
        if (CHECK_FLAGS(flags, CONV_TOUPPER)) {
-           if (!strupper_w((ucs2_t *) u)) 
-               return (size_t)(-1);
+           strupper_w(u);
        }
        if (CHECK_FLAGS(flags, CONV_TOLOWER)) {
-           if (!strlower_w((ucs2_t *) u)) 
-               return (size_t)(-1);
+           strlower_w(u);
        }
 
        /* Convert UCS2 to to_set */
-       if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, cap_charset, u, i_len, dest, dest_len, flags )) ) {
+       if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, cap_charset, (char *)u, i_len, dest, dest_len, flags )) ) {
                LOG(log_error, logtype_default, 
                       "Conversion failed (CH_UCS2 to %s):%s", charset_name(to_set), strerror(errno));
                return (size_t) -1;