#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 <arpa/inet.h>
-#include <netatalk/endian.h>
#include <atalk/logger.h>
#include <atalk/unicode.h>
#include <atalk/util.h>
-#include "byteorder.h"
+#include <atalk/compat.h>
+#include <atalk/byteorder.h>
/**
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-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)
* 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;
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) {
}
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--;
}
}
}
*/
-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;
}
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 &&
}
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;
* 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;