X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Funicode%2Fcharcnv.c;h=be9186e6028fb09d33190abc41167e48bf3437d1;hb=654f86c6e05414423af719716ad028f7af7a65f5;hp=e4f6d2b3b2a86ac698ea38000e23406f0141250b;hpb=dd14ee0c14fe7a965ec8db07c0d3e8bb0aa49613;p=netatalk.git diff --git a/libatalk/unicode/charcnv.c b/libatalk/unicode/charcnv.c index e4f6d2b3..be9186e6 100644 --- a/libatalk/unicode/charcnv.c +++ b/libatalk/unicode/charcnv.c @@ -36,18 +36,13 @@ #ifdef HAVE_USABLE_ICONV #include #endif -#if HAVE_LOCALE_H -#include -#endif -#if HAVE_LANGINFO_H -#include -#endif +#include -#include #include #include #include -#include "byteorder.h" +#include +#include /** @@ -76,29 +71,6 @@ 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(). @@ -106,68 +78,22 @@ static char* read_charsets_from_env(charset_t ch) 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-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]; - -#if defined(CODESET) - if (ret && strcasecmp(ret, "LOCALE") == 0) { - const char *ln = NULL; - - setlocale(LC_ALL, ""); - ln = nl_langinfo(CODESET); - if (ln) { - /* Check whether the charset name is supported - by iconv */ - 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 = "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"; + else ret = charset_names[ch]; return ret; } +int set_charset_name(charset_t ch, const char *name) +{ + if (ch >= NUM_CHARSETS) + return -1; + charset_names[ch] = strdup(name); + return 0; +} + static struct charset_functions* get_charset_functions (charset_t ch) { if (charsets[ch] != NULL) @@ -766,9 +692,9 @@ char * debug_out ( char * seq, size_t len) * for e.g. HFS cdroms. */ -static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const char *src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags) +static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const char *src, size_t srclen, char* dest, size_t destlen, uint16_t *flags) { - const u_int16_t option = (flags ? *flags : 0); + const uint16_t option = (flags ? *flags : 0); size_t i_len, o_len; size_t j = 0; const char* inbuf = (const char*)src; @@ -791,13 +717,11 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c o_len=destlen; while (i_len > 0) { - if ((option & CONV_UNESCAPEHEX)) { - for (j = 0; j < i_len; ++j) { - if (inbuf[j] == ':') break; - } - j = i_len - j; - i_len -= j; - } + for (j = 0; j < i_len; ++j) + if (inbuf[j] == ':') + break; + j = i_len - j; + i_len -= j; if (i_len > 0 && atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) { @@ -825,36 +749,48 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c } if (j) { - /* we're at the start on an hex encoded ucs2 char */ - char h[MAXPATHLEN]; - size_t hlen = 0; - + /* we have a ':' */ i_len = j, j = 0; - while (i_len >= 3 && inbuf[0] == ':' && - isxdigit(inbuf[1]) && isxdigit(inbuf[2])) { - h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]); - inbuf += 3; - i_len -= 3; - } - if (hlen) { - const char *h_buf = h; - if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) { - i_len += hlen * 3; - inbuf -= hlen * 3; - if (errno == EILSEQ && (option & CONV_IGNORE)) { + + if ((option & CONV_UNESCAPEHEX)) { + /* treat it as a CAP hex encoded char */ + char h[MAXPATHLEN]; + size_t hlen = 0; + + while (i_len >= 3 && inbuf[0] == ':' && + isxdigit(inbuf[1]) && isxdigit(inbuf[2])) { + h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]); + inbuf += 3; + i_len -= 3; + } + if (hlen) { + const char *h_buf = h; + if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) { + i_len += hlen * 3; + inbuf -= hlen * 3; + if (errno == EILSEQ && (option & CONV_IGNORE)) { + *flags |= CONV_REQMANGLE; + return destlen - o_len; + } + goto end; + } + } else { + /* We have an invalid :xx sequence */ + errno = EILSEQ; + if ((option & CONV_IGNORE)) { *flags |= CONV_REQMANGLE; return destlen - o_len; } goto end; } } else { - /* We have an invalid :xx sequence */ - errno = EILSEQ; - if ((option & CONV_IGNORE)) { - *flags |= CONV_REQMANGLE; - return destlen - o_len; - } - goto end; + /* a ':' that we just convert to a '/' */ + ucs2_t slash = 0x002f; + memcpy(outbuf, &slash, sizeof(ucs2_t)); + outbuf += 2; + o_len -= 2; + inbuf++; + i_len--; } } } @@ -878,9 +814,9 @@ end: */ -static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags) +static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, uint16_t *flags) { - const u_int16_t option = (flags ? *flags : 0); + const uint16_t option = (flags ? *flags : 0); size_t i_len, o_len, i; size_t j = 0; const char* inbuf = (const char*)src; @@ -916,25 +852,24 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src } while (i_len >= 2) { - if ((option & CONV_ESCAPEHEX)) { - for (i = 0; i < i_len; i += 2) { - ucs2_t c = SVAL(inbuf, i); - switch (c) { - case 0x003a: /* 0x003a = ':' */ - if ( ! (option & CONV_ALLOW_COLON)) { - errno = EILSEQ; - goto end; - } - escch = c; - j = i_len - i; - i_len = i; - break; - case 0x002f: /* 0x002f = '/' */ - escch = c; - j = i_len - i; - i_len = i; - break; + for (i = 0; i < i_len; i += 2) { + ucs2_t c = SVAL(inbuf, i); + switch (c) { + case 0x003a: /* 0x003a = ':' */ + if ( ! (option & CONV_ALLOW_COLON)) { + errno = EILSEQ; + goto end; } + escch = c; + j = i_len - i; + i_len = i; + break; + case 0x002f: /* 0x002f = '/' */ + if (option & CONV_ALLOW_SLASH) break; + escch = c; + j = i_len - i; + i_len = i; + break; } } while (i_len > 0 && @@ -987,35 +922,53 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src } if (j) { + /* we have a ':' or '/' */ i_len = j, j = 0; - if (o_len < 3) { - errno = E2BIG; - goto end; - } - switch (escch) { - case '/': - *outbuf++ = ':'; - *outbuf++ = '2'; - *outbuf++ = 'f'; - break; - case ':': - *outbuf++ = ':'; - *outbuf++ = '3'; - *outbuf++ = 'a'; - break; - default: - /* - * THIS SHOULD NEVER BE REACHED !!! - * As a safety net I put in a ' ' here - */ - *outbuf++ = ':'; - *outbuf++ = '2'; - *outbuf++ = '0'; - break; + + if ((option & CONV_ESCAPEHEX)) { + /* CAP hex encode it */ + if (o_len < 3) { + errno = E2BIG; + goto end; + } + switch (escch) { + case '/': + *outbuf++ = ':'; + *outbuf++ = '2'; + *outbuf++ = 'f'; + break; + case ':': + *outbuf++ = ':'; + *outbuf++ = '3'; + *outbuf++ = 'a'; + break; + default: + /* + * THIS SHOULD NEVER BE REACHED !!! + * As a safety net I put in a ' ' here + */ + *outbuf++ = ':'; + *outbuf++ = '2'; + *outbuf++ = '0'; + break; + } + o_len -= 3; + inbuf += 2; + i_len -= 2; + } else { + switch (escch) { + case '/': + case ':': + *outbuf++ = ':'; + break; + default: /* should never be reached */ + *outbuf++ = ' '; + break; + } + o_len--; + inbuf += 2; + i_len -= 2; } - o_len -= 3; - inbuf += 2; - i_len -= 2; } } if (i_len > 0) errno = EINVAL; @@ -1027,7 +980,7 @@ end: * FIXME the size is a mess we really need a malloc/free logic *`dest size must be dest_len +2 */ -size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, const char *src, size_t src_len, char *dest, size_t dest_len, u_int16_t *flags) +size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, const char *src, size_t src_len, char *dest, size_t dest_len, uint16_t *flags) { size_t i_len, o_len; ucs2_t *u;