X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=libatalk%2Funicode%2Fcharcnv.c;fp=libatalk%2Funicode%2Fcharcnv.c;h=4e772e165a16e4f60f0f7dd331d176bf542645da;hp=785e47720f1d7ab2e74ce2be611c93164386fdb9;hb=b6f259d1c2d472b1b97b77eb2ca1374f07f2d6c0;hpb=29ac6c817273cf860569a0735608e0b9410659d8 diff --git a/libatalk/unicode/charcnv.c b/libatalk/unicode/charcnv.c index 785e4772..4e772e16 100644 --- a/libatalk/unicode/charcnv.c +++ b/libatalk/unicode/charcnv.c @@ -95,6 +95,16 @@ int set_charset_name(charset_t ch, const char *name) return 0; } +void free_charset_names(void) +{ + for (int ch = 0; ch < MAX_CHARSETS; ch++) { + if (charset_names[ch]) { + free(charset_names[ch]); + charset_names[ch] = NULL; + } + } +} + static struct charset_functions* get_charset_functions (charset_t ch) { if (charsets[ch] != NULL) @@ -693,7 +703,7 @@ 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, uint16_t *flags) +static size_t pull_charset_flags (charset_t from_set, charset_t to_set, charset_t cap_set, const char *src, size_t srclen, char* dest, size_t destlen, uint16_t *flags) { const uint16_t option = (flags ? *flags : 0); size_t i_len, o_len; @@ -702,6 +712,7 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c char* outbuf = dest; atalk_iconv_t descriptor; atalk_iconv_t descriptor_cap; + char escch; /* 150210: uninitialized OK, depends on j */ if (srclen == (size_t)-1) srclen = strlen(src) + 1; @@ -717,10 +728,30 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c i_len=srclen; o_len=destlen; + if ((option & CONV_ESCAPEDOTS) && i_len >= 2 && inbuf[0] == '.') { + if (o_len < 6) { + errno = E2BIG; + goto end; + } + ucs2_t ucs2 = ':'; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + ucs2 = '2'; + memcpy(outbuf + sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + ucs2 = 'e'; + memcpy(outbuf + 2 * sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + outbuf += 6; + o_len -= 6; + inbuf++; + i_len--; + *flags |= CONV_REQESCAPE; + } + while (i_len > 0) { for (j = 0; j < i_len; ++j) - if (inbuf[j] == ':') + if (inbuf[j] == ':' || inbuf[j] == '/') { + escch = inbuf[j]; break; + } j = i_len - j; i_len -= j; @@ -750,48 +781,108 @@ static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, const c } if (j) { - /* we have a ':' */ + /* we have a ':' or '/' */ i_len = j, j = 0; - 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)) { + if (escch == ':') { + 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; + } else if (option & CONV_ESCAPEHEX) { + if (o_len < 6) { + errno = E2BIG; + goto end; } - goto end; + ucs2_t ucs2 = ':'; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + ucs2 = '3'; + memcpy(outbuf + sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + ucs2 = 'a'; + memcpy(outbuf + 2 * sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + outbuf += 6; + o_len -= 6; + inbuf++; + i_len--; + } else if (to_set == CH_UTF8_MAC || to_set == CH_MAC) { + /* convert to a '/' */ + ucs2_t slash = 0x002f; + memcpy(outbuf, &slash, sizeof(ucs2_t)); + outbuf += 2; + o_len -= 2; + inbuf++; + i_len--; + } else { + /* keep as ':' */ + ucs2_t ucs2 = 0x003a; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + outbuf += 2; + o_len -= 2; + inbuf++; + i_len--; } } else { - /* 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--; + /* '/' */ + if (option & CONV_ESCAPEHEX) { + if (o_len < 6) { + errno = E2BIG; + goto end; + } + ucs2_t ucs2 = ':'; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + ucs2 = '2'; + memcpy(outbuf + sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + ucs2 = 'f'; + memcpy(outbuf + 2 * sizeof(ucs2_t), &ucs2, sizeof(ucs2_t)); + outbuf += 6; + o_len -= 6; + inbuf++; + i_len--; + } else if ((from_set == CH_UTF8_MAC || from_set == CH_MAC) + && (to_set != CH_UTF8_MAC || to_set != CH_MAC)) { + /* convert to ':' */ + ucs2_t ucs2 = 0x003a; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + outbuf += 2; + o_len -= 2; + inbuf++; + i_len--; + } else { + /* keep as '/' */ + ucs2_t ucs2 = 0x002f; + memcpy(outbuf, &ucs2, sizeof(ucs2_t)); + outbuf += 2; + o_len -= 2; + inbuf++; + i_len--; + } } } } @@ -824,7 +915,6 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src char* outbuf = (char*)dest; atalk_iconv_t descriptor; atalk_iconv_t descriptor_cap; - char escch; /* 150210: uninitialized OK, depends on j */ descriptor = conv_handles[CH_UCS2][to_set]; descriptor_cap = conv_handles[CH_UCS2][cap_set]; @@ -837,42 +927,7 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src i_len=srclen; o_len=destlen; - if ((option & CONV_ESCAPEDOTS) && - i_len >= 2 && SVAL(inbuf, 0) == 0x002e) { /* 0x002e = . */ - if (o_len < 3) { - errno = E2BIG; - goto end; - } - *outbuf++ = ':'; - *outbuf++ = '2'; - *outbuf++ = 'e'; - o_len -= 3; - inbuf += 2; - i_len -= 2; - *flags |= CONV_REQESCAPE; - } - while (i_len >= 2) { - 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 && atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) { if (errno == EILSEQ) { @@ -921,57 +976,8 @@ static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src } goto end; } + } /* while (i_len >= 2) */ - if (j) { - /* we have a ':' or '/' */ - i_len = j, j = 0; - - 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; - } - } - } if (i_len > 0) errno = EINVAL; end: return (i_len + j == 0 || (option & CONV_FORCE)) ? destlen - o_len : (size_t)-1; @@ -991,7 +997,7 @@ size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_cha lazy_initialize_conv(); /* convert from_set to UCS2 */ - if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, cap_charset, src, src_len, + if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, to_set, cap_charset, src, src_len, (char *) buffer, sizeof(buffer) -2, flags)) ) { LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set)); return (size_t) -1;