diff options
author | delphij <delphij@FreeBSD.org> | 2009-06-22 17:09:46 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-06-22 17:09:46 +0000 |
commit | 3216be3a5a453bb6570d9a31504f54f067832fad (patch) | |
tree | ff466c24979a5205b616c97267983e5b0216ed4c /sys/libkern/iconv_xlat16.c | |
parent | 903095e7105f537fbdcb5a7a542bd833c6b35b3b (diff) | |
download | FreeBSD-src-3216be3a5a453bb6570d9a31504f54f067832fad.zip FreeBSD-src-3216be3a5a453bb6570d9a31504f54f067832fad.tar.gz |
Split tolower/toupper code from usual xlat16 kiconv table, and make it
possible to do tolower/toupper independently without code conversion.
Submitted by: imura (but bugs are mine)
Obtained from: http://people.freebsd.org/~imura/kiconv/
(1_kiconv_wctype_kern.diff, 1_kiconv_wctype_user.diff)
Diffstat (limited to 'sys/libkern/iconv_xlat16.c')
-rw-r--r-- | sys/libkern/iconv_xlat16.c | 164 |
1 files changed, 140 insertions, 24 deletions
diff --git a/sys/libkern/iconv_xlat16.c b/sys/libkern/iconv_xlat16.c index 78e764a..dbac892 100644 --- a/sys/libkern/iconv_xlat16.c +++ b/sys/libkern/iconv_xlat16.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, Ryuichiro Imura + * Copyright (c) 2003, 2005 Ryuichiro Imura * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,12 +43,17 @@ __FBSDID("$FreeBSD$"); MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2); #endif +#define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff) +#define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff) + /* * XLAT16 converter instance */ struct iconv_xlat16 { KOBJ_FIELDS; uint32_t * d_table[0x200]; + void * f_ctp; + void * t_ctp; struct iconv_cspair * d_csp; }; @@ -72,6 +77,16 @@ iconv_xlat16_open(struct iconv_converter_class *dcp, } idxp++; } + + if (strcmp(csp->cp_to, KICONV_WCTYPE_NAME) != 0) { + if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_from, &dp->f_ctp) != 0) + dp->f_ctp = NULL; + if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_to, &dp->t_ctp) != 0) + dp->t_ctp = NULL; + } else { + dp->f_ctp = dp->t_ctp = dp; + } + dp->d_csp = csp; csp->cp_refcount++; *dpp = (void*)dp; @@ -83,6 +98,10 @@ iconv_xlat16_close(void *data) { struct iconv_xlat16 *dp = data; + if (dp->f_ctp && dp->f_ctp != data) + iconv_close(dp->f_ctp); + if (dp->t_ctp && dp->t_ctp != data) + iconv_close(dp->t_ctp); dp->d_csp->cp_refcount--; kobj_delete((struct kobj*)data, M_ICONV); return (0); @@ -100,7 +119,7 @@ iconv_xlat16_conv(void *d2p, const char **inbuf, size_t in, on, ir, or, inlen; uint32_t code; u_char u, l; - uint16_t c1, c2; + uint16_t c1, c2, ctmp; if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) return (0); @@ -112,21 +131,32 @@ iconv_xlat16_conv(void *d2p, const char **inbuf, while(ir > 0 && or > 0) { inlen = 0; - code = '\0'; + code = 0; c1 = ir > 1 ? *(src+1) & 0xff : 0; c2 = *src & 0xff; + ctmp = 0; c1 = c2 & 0x80 ? c1 | 0x100 : c1; c2 = c2 & 0x80 ? c2 & 0x7f : c2; - if (ir > 1 && dp->d_table[c1]) { + if (ir > 1 && dp->d_table[c1] && dp->d_table[c1][c2]) { /* * inbuf char is a double byte char */ - code = dp->d_table[c1][c2]; - if (code) - inlen = 2; + inlen = 2; + + /* toupper,tolower */ + if (casetype == KICONV_FROM_LOWER && dp->f_ctp) + ctmp = towlower(((u_char)*src << 8) | (u_char)*(src + 1), + dp->f_ctp); + else if (casetype == KICONV_FROM_UPPER && dp->f_ctp) + ctmp = towupper(((u_char)*src << 8) | (u_char)*(src + 1), + dp->f_ctp); + if (ctmp) { + c1 = C2I1(ctmp); + c2 = C2I2(ctmp); + } } if (inlen == 0) { @@ -139,11 +169,31 @@ iconv_xlat16_conv(void *d2p, const char **inbuf, * inbuf char is a single byte char */ inlen = 1; - code = dp->d_table[c1][c2]; - if (!code) { - ret = -1; - break; + + if (casetype & (KICONV_FROM_LOWER|KICONV_FROM_UPPER)) + code = dp->d_table[c1][c2]; + + if (casetype == KICONV_FROM_LOWER) { + if (dp->f_ctp) + ctmp = towlower((u_char)*src, dp->f_ctp); + else if (code & XLAT16_HAS_FROM_LOWER_CASE) + ctmp = (u_char)(code >> 16); + } else if (casetype == KICONV_FROM_UPPER) { + if (dp->f_ctp) + ctmp = towupper((u_char)*src, dp->f_ctp); + else if (code & XLAT16_HAS_FROM_UPPER_CASE) + ctmp = (u_char)(code >> 16); } + if (ctmp) { + c1 = C2I1(ctmp << 8); + c2 = C2I2(ctmp << 8); + } + } + + code = dp->d_table[c1][c2]; + if (!code) { + ret = -1; + break; } nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0; @@ -158,14 +208,6 @@ iconv_xlat16_conv(void *d2p, const char **inbuf, /* * now start translation */ - if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) || - (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE)) { - c2 = (u_char)(code >> 16); - c1 = c2 & 0x80 ? 0x100 : 0; - c2 = c2 & 0x80 ? c2 & 0x7f : c2; - code = dp->d_table[c1][c2]; - } - u = (u_char)(code >> 8); l = (u_char)code; @@ -186,15 +228,38 @@ iconv_xlat16_conv(void *d2p, const char **inbuf, ret = -1; break; } + + /* toupper,tolower */ + if (casetype == KICONV_LOWER && dp->t_ctp) { + code = towlower((uint16_t)code, dp->t_ctp); + u = (u_char)(code >> 8); + l = (u_char)code; + } + if (casetype == KICONV_UPPER && dp->t_ctp) { + code = towupper((uint16_t)code, dp->t_ctp); + u = (u_char)(code >> 8); + l = (u_char)code; + } + *dst++ = u; *dst++ = l; or -= 2; } else { - if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) || - (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE)) - *dst++ = (u_char)(code >> 16); - else - *dst++ = l; + /* toupper,tolower */ + if (casetype == KICONV_LOWER) { + if (dp->t_ctp) + l = (u_char)towlower(l, dp->t_ctp); + else if (code & XLAT16_HAS_LOWER_CASE) + l = (u_char)(code >> 16); + } + if (casetype == KICONV_UPPER) { + if (dp->t_ctp) + l = (u_char)towupper(l, dp->t_ctp); + else if (code & XLAT16_HAS_UPPER_CASE) + l = (u_char)(code >> 16); + } + + *dst++ = l; or--; } @@ -232,6 +297,55 @@ iconv_xlat16_name(struct iconv_converter_class *dcp) return ("xlat16"); } +static int +iconv_xlat16_tolower(void *d2p, register int c) +{ + struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; + register int c1, c2, out; + + if (c < 0x100) { + c1 = C2I1(c << 8); + c2 = C2I2(c << 8); + } else if (c < 0x10000) { + c1 = C2I1(c); + c2 = C2I2(c); + } else + return (c); + + if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_LOWER_CASE) { + /*return (int)(dp->d_table[c1][c2] & 0xffff);*/ + out = dp->d_table[c1][c2] & 0xffff; + if ((out & 0xff) == 0) + out = (out >> 8) & 0xff; + return (out); + } else + return (c); +} + +static int +iconv_xlat16_toupper(void *d2p, register int c) +{ + struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; + register int c1, c2, out; + + if (c < 0x100) { + c1 = C2I1(c << 8); + c2 = C2I2(c << 8); + } else if (c < 0x10000) { + c1 = C2I1(c); + c2 = C2I2(c); + } else + return (c); + + if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_UPPER_CASE) { + out = dp->d_table[c1][c2] & 0xffff; + if ((out & 0xff) == 0) + out = (out >> 8) & 0xff; + return (out); + } else + return (c); +} + static kobj_method_t iconv_xlat16_methods[] = { KOBJMETHOD(iconv_converter_open, iconv_xlat16_open), KOBJMETHOD(iconv_converter_close, iconv_xlat16_close), @@ -241,6 +355,8 @@ static kobj_method_t iconv_xlat16_methods[] = { KOBJMETHOD(iconv_converter_done, iconv_xlat16_done), #endif KOBJMETHOD(iconv_converter_name, iconv_xlat16_name), + KOBJMETHOD(iconv_converter_tolower, iconv_xlat16_tolower), + KOBJMETHOD(iconv_converter_toupper, iconv_xlat16_toupper), {0, 0} }; |