iconv_xlat16.c revision 256281
126159Sse/*- 226159Sse * Copyright (c) 2003, 2005 Ryuichiro Imura 326159Sse * All rights reserved. 426159Sse * 526159Sse * Redistribution and use in source and binary forms, with or without 626159Sse * modification, are permitted provided that the following conditions 726159Sse * are met: 826159Sse * 1. Redistributions of source code must retain the above copyright 926159Sse * notice, this list of conditions and the following disclaimer. 1026159Sse * 2. Redistributions in binary form must reproduce the above copyright 1126159Sse * notice, this list of conditions and the following disclaimer in the 1226159Sse * documentation and/or other materials provided with the distribution. 1326159Sse * 1426159Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1526159Sse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626159Sse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1726159Sse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826159Sse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926159Sse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026159Sse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126159Sse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226159Sse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326159Sse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426159Sse * SUCH DAMAGE. 2526159Sse */ 2650477Speter 2726159Sse#include <sys/cdefs.h> 2826159Sse__FBSDID("$FreeBSD: stable/10/sys/libkern/iconv_xlat16.c 194638 2009-06-22 17:09:46Z delphij $"); 296100Sse 3039231Sgibbs#include <sys/param.h> 3139231Sgibbs#include <sys/kernel.h> 3239231Sgibbs#include <sys/systm.h> 3339231Sgibbs#include <sys/malloc.h> 3439231Sgibbs#include <sys/iconv.h> 3526159Sse 366767Sse#include "iconv_converter_if.h" 3726159Sse 3826159Sse/* 3926159Sse * "XLAT16" converter 4026159Sse */ 416100Sse 4226159Sse#ifdef MODULE_DEPEND 4326159SseMODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2); 4426159Sse#endif 456100Sse 4626159Sse#define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff) 476100Sse#define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff) 4826159Sse 4926159Sse/* 5026159Sse * XLAT16 converter instance 5126159Sse */ 5226159Ssestruct iconv_xlat16 { 536100Sse KOBJ_FIELDS; 5426159Sse uint32_t * d_table[0x200]; 556100Sse void * f_ctp; 5626159Sse void * t_ctp; 5745720Speter struct iconv_cspair * d_csp; 5826159Sse}; 596100Sse 6026159Ssestatic int 6126159Sseiconv_xlat16_open(struct iconv_converter_class *dcp, 6226159Sse struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) 6326159Sse{ 646100Sse struct iconv_xlat16 *dp; 6526159Sse uint32_t *headp, **idxp; 6626159Sse int i; 677233Sse 6838304Sgibbs dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); 6926159Sse headp = (uint32_t *)((caddr_t)csp->cp_data + sizeof(dp->d_table)); 7026159Sse idxp = (uint32_t **)csp->cp_data; 7126159Sse for (i = 0 ; i < 0x200 ; i++) { 726100Sse if (*idxp) { 7326159Sse dp->d_table[i] = headp; 7426159Sse headp += 0x80; 7526159Sse } else { 7626159Sse dp->d_table[i] = NULL; 776100Sse } 7826159Sse idxp++; 7926159Sse } 8026159Sse 816100Sse if (strcmp(csp->cp_to, KICONV_WCTYPE_NAME) != 0) { 8226159Sse if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_from, &dp->f_ctp) != 0) 8326159Sse dp->f_ctp = NULL; 847233Sse if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_to, &dp->t_ctp) != 0) 8547339Sgallatin dp->t_ctp = NULL; 8626159Sse } else { 8726159Sse dp->f_ctp = dp->t_ctp = dp; 8826159Sse } 897233Sse 9026159Sse dp->d_csp = csp; 9126159Sse csp->cp_refcount++; 9226159Sse *dpp = (void*)dp; 936100Sse return (0); 9426159Sse} 956100Sse 9626159Ssestatic int 9726159Sseiconv_xlat16_close(void *data) 9826159Sse{ 9926159Sse struct iconv_xlat16 *dp = data; 10026159Sse 10126159Sse if (dp->f_ctp && dp->f_ctp != data) 10226159Sse iconv_close(dp->f_ctp); 1036100Sse if (dp->t_ctp && dp->t_ctp != data) 10426159Sse iconv_close(dp->t_ctp); 10526159Sse dp->d_csp->cp_refcount--; 1067233Sse kobj_delete((struct kobj*)data, M_ICONV); 10726159Sse return (0); 10826159Sse} 10926159Sse 11026159Ssestatic int 11126159Sseiconv_xlat16_conv(void *d2p, const char **inbuf, 11226159Sse size_t *inbytesleft, char **outbuf, size_t *outbytesleft, 11326159Sse int convchar, int casetype) 11426159Sse{ 11526159Sse struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 11626159Sse const char *src; 11726159Sse char *dst; 1186100Sse int nullin, ret = 0; 11926159Sse size_t in, on, ir, or, inlen; 12026159Sse uint32_t code; 12126159Sse u_char u, l; 12226159Sse uint16_t c1, c2, ctmp; 12326159Sse 12426159Sse if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) 12526159Sse return (0); 12626159Sse ir = in = *inbytesleft; 12726159Sse or = on = *outbytesleft; 12826159Sse src = *inbuf; 12926159Sse dst = *outbuf; 13026159Sse 13126159Sse while(ir > 0 && or > 0) { 13226159Sse 13326159Sse inlen = 0; 13426159Sse code = 0; 13526159Sse 13639231Sgibbs c1 = ir > 1 ? *(src+1) & 0xff : 0; 13739231Sgibbs c2 = *src & 0xff; 13861047Speter ctmp = 0; 13961047Speter 14061047Speter c1 = c2 & 0x80 ? c1 | 0x100 : c1; 14161047Speter c2 = c2 & 0x80 ? c2 & 0x7f : c2; 14261047Speter 14361047Speter if (ir > 1 && dp->d_table[c1] && dp->d_table[c1][c2]) { 14461047Speter /* 14561047Speter * inbuf char is a double byte char 14661047Speter */ 14739231Sgibbs inlen = 2; 14826159Sse 14926159Sse /* toupper,tolower */ 15054412Speter if (casetype == KICONV_FROM_LOWER && dp->f_ctp) 15154412Speter ctmp = towlower(((u_char)*src << 8) | (u_char)*(src + 1), 15257332Sdfr dp->f_ctp); 15326159Sse else if (casetype == KICONV_FROM_UPPER && dp->f_ctp) 15426159Sse ctmp = towupper(((u_char)*src << 8) | (u_char)*(src + 1), 15526159Sse dp->f_ctp); 15626159Sse if (ctmp) { 15726159Sse c1 = C2I1(ctmp); 15840004Sdfr c2 = C2I2(ctmp); 15940004Sdfr } 16040004Sdfr } 16140004Sdfr 16245720Speter if (inlen == 0) { 16347646Sroger c1 &= 0xff00; 16447646Sroger if (!dp->d_table[c1]) { 16547646Sroger ret = -1; 16645720Speter break; 16745720Speter } 16845720Speter /* 16945720Speter * inbuf char is a single byte char 17052243Sdfr */ 17152243Sdfr inlen = 1; 17252243Sdfr 17352243Sdfr if (casetype & (KICONV_FROM_LOWER|KICONV_FROM_UPPER)) 17452243Sdfr code = dp->d_table[c1][c2]; 17552243Sdfr 17652243Sdfr if (casetype == KICONV_FROM_LOWER) { 17745720Speter if (dp->f_ctp) 17845720Speter ctmp = towlower((u_char)*src, dp->f_ctp); 17945720Speter else if (code & XLAT16_HAS_FROM_LOWER_CASE) 18045720Speter ctmp = (u_char)(code >> 16); 18145720Speter } else if (casetype == KICONV_FROM_UPPER) { 18245720Speter if (dp->f_ctp) 18345720Speter ctmp = towupper((u_char)*src, dp->f_ctp); 18445720Speter else if (code & XLAT16_HAS_FROM_UPPER_CASE) 18545720Speter ctmp = (u_char)(code >> 16); 18645720Speter } 18745720Speter if (ctmp) { 18845720Speter c1 = C2I1(ctmp << 8); 18945720Speter c2 = C2I2(ctmp << 8); 19045720Speter } 19145720Speter } 19245720Speter 19345720Speter code = dp->d_table[c1][c2]; 19447339Sgallatin if (!code) { 19545720Speter ret = -1; 19645720Speter break; 19745720Speter } 19845720Speter 19945720Speter nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0; 20045720Speter if (inlen == 1 && nullin) { 20145720Speter /* 20245720Speter * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte 20345720Speter */ 20445720Speter ret = -1; 20545720Speter break; 20645720Speter } 20745720Speter 20845720Speter /* 20945720Speter * now start translation 21045720Speter */ 21145720Speter u = (u_char)(code >> 8); 21245720Speter l = (u_char)code; 21345720Speter 21445720Speter#ifdef XLAT16_ACCEPT_3BYTE_CHR 21545720Speter if (code & XLAT16_IS_3BYTE_CHR) { 21645720Speter if (or < 3) { 21745720Speter ret = -1; 21845720Speter break; 21945720Speter } 22045720Speter *dst++ = u; 22145720Speter *dst++ = l; 22245720Speter *dst++ = (u_char)(code >> 16); 22345720Speter or -= 3; 22445720Speter } else 22545720Speter#endif 22645720Speter if (u || code & XLAT16_ACCEPT_NULL_OUT) { 22745720Speter if (or < 2) { 22845720Speter ret = -1; 22945720Speter break; 23045720Speter } 23147339Sgallatin 23245720Speter /* toupper,tolower */ 23345720Speter if (casetype == KICONV_LOWER && dp->t_ctp) { 23445720Speter code = towlower((uint16_t)code, dp->t_ctp); 23545720Speter u = (u_char)(code >> 8); 23645720Speter l = (u_char)code; 23745720Speter } 23845720Speter if (casetype == KICONV_UPPER && dp->t_ctp) { 23945720Speter code = towupper((uint16_t)code, dp->t_ctp); 24045720Speter u = (u_char)(code >> 8); 24145720Speter l = (u_char)code; 24245720Speter } 24345720Speter 24445720Speter *dst++ = u; 24547339Sgallatin *dst++ = l; 24647339Sgallatin or -= 2; 24747339Sgallatin } else { 24847339Sgallatin /* toupper,tolower */ 24947339Sgallatin if (casetype == KICONV_LOWER) { 25047339Sgallatin if (dp->t_ctp) 25147339Sgallatin l = (u_char)towlower(l, dp->t_ctp); 25247339Sgallatin else if (code & XLAT16_HAS_LOWER_CASE) 25347339Sgallatin l = (u_char)(code >> 16); 25447339Sgallatin } 25547339Sgallatin if (casetype == KICONV_UPPER) { 25647339Sgallatin if (dp->t_ctp) 25747339Sgallatin l = (u_char)towupper(l, dp->t_ctp); 25847339Sgallatin else if (code & XLAT16_HAS_UPPER_CASE) 25947339Sgallatin l = (u_char)(code >> 16); 26047339Sgallatin } 26147339Sgallatin 26247339Sgallatin *dst++ = l; 26347339Sgallatin or--; 26447339Sgallatin } 26547339Sgallatin 26647339Sgallatin if (inlen == 2) { 26747339Sgallatin /* 26847339Sgallatin * there is a case that inbuf char is a single 26947339Sgallatin * byte char while inlen == 2 27047339Sgallatin */ 27145720Speter if ((u_char)*(src+1) == 0 && !nullin ) { 27245720Speter src++; 27361047Speter ir--; 27426159Sse } else { 27558320Speter src += 2; 27658287Speter ir -= 2; 27758287Speter } 27858287Speter } else { 27961047Speter src++; 28061047Speter ir--; 28158287Speter } 28258287Speter 28326159Sse if (convchar == 1) 28426159Sse break; 28513597Sse } 28612453Sbde 28726159Sse *inbuf += in - ir; 28826159Sse *outbuf += on - or; 28926159Sse *inbytesleft -= in - ir; 29026159Sse *outbytesleft -= on - or; 29126159Sse return (ret); 29226159Sse} 29341766Sdillon 29426159Ssestatic const char * 29526159Sseiconv_xlat16_name(struct iconv_converter_class *dcp) 29626159Sse{ 2977233Sse return ("xlat16"); 2987233Sse} 29937841Sdfr 30037841Sdfrstatic int 30137841Sdfriconv_xlat16_tolower(void *d2p, register int c) 30237841Sdfr{ 30337841Sdfr struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 30437841Sdfr register int c1, c2, out; 30526159Sse 30626159Sse if (c < 0x100) { 30737841Sdfr c1 = C2I1(c << 8); 30826159Sse c2 = C2I2(c << 8); 30942614Sbde } else if (c < 0x10000) { 31042614Sbde c1 = C2I1(c); 31142614Sbde c2 = C2I2(c); 31242614Sbde } else 3137233Sse return (c); 3147233Sse 31547646Sroger if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_LOWER_CASE) { 31647646Sroger /*return (int)(dp->d_table[c1][c2] & 0xffff);*/ 31747646Sroger out = dp->d_table[c1][c2] & 0xffff; 31846591Speter if ((out & 0xff) == 0) 31946591Speter out = (out >> 8) & 0xff; 32046023Speter return (out); 32146023Speter } else 32246023Speter return (c); 32346023Speter} 32446023Speter 32546023Speterstatic int 32646023Spetericonv_xlat16_toupper(void *d2p, register int c) 32761047Speter{ 32846023Speter struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 32939231Sgibbs register int c1, c2, out; 330 331 if (c < 0x100) { 332 c1 = C2I1(c << 8); 333 c2 = C2I2(c << 8); 334 } else if (c < 0x10000) { 335 c1 = C2I1(c); 336 c2 = C2I2(c); 337 } else 338 return (c); 339 340 if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_UPPER_CASE) { 341 out = dp->d_table[c1][c2] & 0xffff; 342 if ((out & 0xff) == 0) 343 out = (out >> 8) & 0xff; 344 return (out); 345 } else 346 return (c); 347} 348 349static kobj_method_t iconv_xlat16_methods[] = { 350 KOBJMETHOD(iconv_converter_open, iconv_xlat16_open), 351 KOBJMETHOD(iconv_converter_close, iconv_xlat16_close), 352 KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv), 353#if 0 354 KOBJMETHOD(iconv_converter_init, iconv_xlat16_init), 355 KOBJMETHOD(iconv_converter_done, iconv_xlat16_done), 356#endif 357 KOBJMETHOD(iconv_converter_name, iconv_xlat16_name), 358 KOBJMETHOD(iconv_converter_tolower, iconv_xlat16_tolower), 359 KOBJMETHOD(iconv_converter_toupper, iconv_xlat16_toupper), 360 {0, 0} 361}; 362 363KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16)); 364