1c4f02a89SMax Khon /*- 2c4f02a89SMax Khon * Copyright (c) 2003, Ryuichiro Imura 3c4f02a89SMax Khon * All rights reserved. 4c4f02a89SMax Khon * 5c4f02a89SMax Khon * Redistribution and use in source and binary forms, with or without 6c4f02a89SMax Khon * modification, are permitted provided that the following conditions 7c4f02a89SMax Khon * are met: 8c4f02a89SMax Khon * 1. Redistributions of source code must retain the above copyright 9c4f02a89SMax Khon * notice, this list of conditions and the following disclaimer. 10c4f02a89SMax Khon * 2. Redistributions in binary form must reproduce the above copyright 11c4f02a89SMax Khon * notice, this list of conditions and the following disclaimer in the 12c4f02a89SMax Khon * documentation and/or other materials provided with the distribution. 13c4f02a89SMax Khon * 14c4f02a89SMax Khon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c4f02a89SMax Khon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c4f02a89SMax Khon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c4f02a89SMax Khon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c4f02a89SMax Khon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c4f02a89SMax Khon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c4f02a89SMax Khon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c4f02a89SMax Khon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c4f02a89SMax Khon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c4f02a89SMax Khon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c4f02a89SMax Khon * SUCH DAMAGE. 25c4f02a89SMax Khon */ 26c4f02a89SMax Khon 27c4f02a89SMax Khon #include <sys/cdefs.h> 28c4f02a89SMax Khon __FBSDID("$FreeBSD$"); 29c4f02a89SMax Khon 30c4f02a89SMax Khon #include <sys/param.h> 31c4f02a89SMax Khon #include <sys/kernel.h> 32c4f02a89SMax Khon #include <sys/systm.h> 33c4f02a89SMax Khon #include <sys/malloc.h> 34c4f02a89SMax Khon #include <sys/iconv.h> 35c4f02a89SMax Khon 36c4f02a89SMax Khon #include "iconv_converter_if.h" 37c4f02a89SMax Khon 38c4f02a89SMax Khon /* 39c4f02a89SMax Khon * "XLAT16" converter 40c4f02a89SMax Khon */ 41c4f02a89SMax Khon 42c4f02a89SMax Khon #ifdef MODULE_DEPEND 43c4f02a89SMax Khon MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2); 44c4f02a89SMax Khon #endif 45c4f02a89SMax Khon 46c4f02a89SMax Khon /* 47c4f02a89SMax Khon * XLAT16 converter instance 48c4f02a89SMax Khon */ 49c4f02a89SMax Khon struct iconv_xlat16 { 50c4f02a89SMax Khon KOBJ_FIELDS; 51c4f02a89SMax Khon uint32_t * d_table[0x200]; 52c4f02a89SMax Khon struct iconv_cspair * d_csp; 53c4f02a89SMax Khon }; 54c4f02a89SMax Khon 55c4f02a89SMax Khon static int 56c4f02a89SMax Khon iconv_xlat16_open(struct iconv_converter_class *dcp, 57c4f02a89SMax Khon struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) 58c4f02a89SMax Khon { 59c4f02a89SMax Khon struct iconv_xlat16 *dp; 60c4f02a89SMax Khon uint32_t *headp, *idxp, dist = 0; 61c4f02a89SMax Khon int i; 62c4f02a89SMax Khon 63c4f02a89SMax Khon dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); 64c4f02a89SMax Khon headp = idxp = (uint32_t *)csp->cp_data; 65c4f02a89SMax Khon dist = 0x200; 66c4f02a89SMax Khon for (i = 0 ; i < 0x200 ; i++) { 67c4f02a89SMax Khon if (*idxp) { 68c4f02a89SMax Khon dp->d_table[i] = headp + dist; 69c4f02a89SMax Khon dist += 0x80; 70c4f02a89SMax Khon } else { 71c4f02a89SMax Khon dp->d_table[i] = NULL; 72c4f02a89SMax Khon } 73c4f02a89SMax Khon idxp++; 74c4f02a89SMax Khon } 75c4f02a89SMax Khon dp->d_csp = csp; 76c4f02a89SMax Khon csp->cp_refcount++; 77c4f02a89SMax Khon *dpp = (void*)dp; 78c4f02a89SMax Khon return (0); 79c4f02a89SMax Khon } 80c4f02a89SMax Khon 81c4f02a89SMax Khon static int 82c4f02a89SMax Khon iconv_xlat16_close(void *data) 83c4f02a89SMax Khon { 84c4f02a89SMax Khon struct iconv_xlat16 *dp = data; 85c4f02a89SMax Khon 86c4f02a89SMax Khon dp->d_csp->cp_refcount--; 87c4f02a89SMax Khon kobj_delete((struct kobj*)data, M_ICONV); 88c4f02a89SMax Khon return (0); 89c4f02a89SMax Khon } 90c4f02a89SMax Khon 91c4f02a89SMax Khon static int 92c4f02a89SMax Khon iconv_xlat16_conv(void *d2p, const char **inbuf, 93c4f02a89SMax Khon size_t *inbytesleft, char **outbuf, size_t *outbytesleft, 94c4f02a89SMax Khon int convchar, int casetype) 95c4f02a89SMax Khon { 96c4f02a89SMax Khon struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 97c4f02a89SMax Khon const char *src; 98c4f02a89SMax Khon char *dst; 990f4e4130SMax Khon int nullin, ret = 0; 100c4f02a89SMax Khon size_t in, on, ir, or, inlen; 101c4f02a89SMax Khon uint32_t code; 102c4f02a89SMax Khon u_char u, l; 1030f4e4130SMax Khon uint16_t c1, c2; 104c4f02a89SMax Khon 105c4f02a89SMax Khon if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) 106c4f02a89SMax Khon return (0); 107c4f02a89SMax Khon ir = in = *inbytesleft; 108c4f02a89SMax Khon or = on = *outbytesleft; 109c4f02a89SMax Khon src = *inbuf; 110c4f02a89SMax Khon dst = *outbuf; 111c4f02a89SMax Khon 112c4f02a89SMax Khon while(ir > 0 && or > 0) { 113c4f02a89SMax Khon 114c4f02a89SMax Khon inlen = 0; 115c4f02a89SMax Khon code = '\0'; 116c4f02a89SMax Khon 117c4f02a89SMax Khon c1 = ir > 1 ? *(src+1) & 0xff : 0; 118c4f02a89SMax Khon c2 = *src & 0xff; 119c4f02a89SMax Khon 120c4f02a89SMax Khon c1 = c2 & 0x80 ? c1 | 0x100 : c1; 121c4f02a89SMax Khon c2 = c2 & 0x80 ? c2 & 0x7f : c2; 122c4f02a89SMax Khon 123c4f02a89SMax Khon if (ir > 1 && dp->d_table[c1]) { 124c4f02a89SMax Khon /* 125c4f02a89SMax Khon * inbuf char is a double byte char 126c4f02a89SMax Khon */ 127c4f02a89SMax Khon code = dp->d_table[c1][c2]; 128c4f02a89SMax Khon if (code) 129c4f02a89SMax Khon inlen = 2; 130c4f02a89SMax Khon } 131c4f02a89SMax Khon 132c4f02a89SMax Khon if (inlen == 0) { 133c4f02a89SMax Khon c1 &= 0xff00; 134c4f02a89SMax Khon if (!dp->d_table[c1]) { 135c4f02a89SMax Khon ret = -1; 136c4f02a89SMax Khon break; 137c4f02a89SMax Khon } 138c4f02a89SMax Khon /* 139c4f02a89SMax Khon * inbuf char is a single byte char 140c4f02a89SMax Khon */ 141c4f02a89SMax Khon inlen = 1; 142c4f02a89SMax Khon code = dp->d_table[c1][c2]; 143c4f02a89SMax Khon if (!code) { 144c4f02a89SMax Khon ret = -1; 145c4f02a89SMax Khon break; 146c4f02a89SMax Khon } 147c4f02a89SMax Khon } 148c4f02a89SMax Khon 1490f4e4130SMax Khon nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0; 1500f4e4130SMax Khon if (inlen == 1 && nullin) { 151c4f02a89SMax Khon /* 152c4f02a89SMax Khon * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte 153c4f02a89SMax Khon */ 154c4f02a89SMax Khon ret = -1; 155c4f02a89SMax Khon break; 156c4f02a89SMax Khon } 157c4f02a89SMax Khon 158c4f02a89SMax Khon /* 159c4f02a89SMax Khon * now start translation 160c4f02a89SMax Khon */ 1610f4e4130SMax Khon if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) || 1620f4e4130SMax Khon (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE)) { 1630f4e4130SMax Khon c2 = (u_char)(code >> 16); 1640f4e4130SMax Khon c1 = c2 & 0x80 ? 0x100 : 0; 1650f4e4130SMax Khon c2 = c2 & 0x80 ? c2 & 0x7f : c2; 1660f4e4130SMax Khon code = dp->d_table[c1][c2]; 1670f4e4130SMax Khon } 1680f4e4130SMax Khon 169c4f02a89SMax Khon u = (u_char)(code >> 8); 170c4f02a89SMax Khon l = (u_char)code; 171c4f02a89SMax Khon 172c4f02a89SMax Khon #ifdef XLAT16_ACCEPT_3BYTE_CHR 173c4f02a89SMax Khon if (code & XLAT16_IS_3BYTE_CHR) { 174c4f02a89SMax Khon if (or < 3) { 175c4f02a89SMax Khon ret = -1; 176c4f02a89SMax Khon break; 177c4f02a89SMax Khon } 178c4f02a89SMax Khon *dst++ = u; 179c4f02a89SMax Khon *dst++ = l; 180c4f02a89SMax Khon *dst++ = (u_char)(code >> 16); 181c4f02a89SMax Khon or -= 3; 182c4f02a89SMax Khon } else 183c4f02a89SMax Khon #endif 184c4f02a89SMax Khon if (u || code & XLAT16_ACCEPT_NULL_OUT) { 185c4f02a89SMax Khon if (or < 2) { 186c4f02a89SMax Khon ret = -1; 187c4f02a89SMax Khon break; 188c4f02a89SMax Khon } 189c4f02a89SMax Khon *dst++ = u; 190c4f02a89SMax Khon *dst++ = l; 191c4f02a89SMax Khon or -= 2; 192c4f02a89SMax Khon } else { 193c4f02a89SMax Khon if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) || 194c4f02a89SMax Khon (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE)) 195c4f02a89SMax Khon *dst++ = (u_char)(code >> 16); 196c4f02a89SMax Khon else 197c4f02a89SMax Khon *dst++ = l; 198c4f02a89SMax Khon or--; 199c4f02a89SMax Khon } 200c4f02a89SMax Khon 201c4f02a89SMax Khon if (inlen == 2) { 202c4f02a89SMax Khon /* 203c4f02a89SMax Khon * there is a case that inbuf char is a single 204c4f02a89SMax Khon * byte char while inlen == 2 205c4f02a89SMax Khon */ 2060f4e4130SMax Khon if ((u_char)*(src+1) == 0 && !nullin ) { 207c4f02a89SMax Khon src++; 208c4f02a89SMax Khon ir--; 209c4f02a89SMax Khon } else { 210c4f02a89SMax Khon src += 2; 211c4f02a89SMax Khon ir -= 2; 212c4f02a89SMax Khon } 213c4f02a89SMax Khon } else { 214c4f02a89SMax Khon src++; 215c4f02a89SMax Khon ir--; 216c4f02a89SMax Khon } 217c4f02a89SMax Khon 218c4f02a89SMax Khon if (convchar == 1) 219c4f02a89SMax Khon break; 220c4f02a89SMax Khon } 221c4f02a89SMax Khon 222c4f02a89SMax Khon *inbuf += in - ir; 223c4f02a89SMax Khon *outbuf += on - or; 224c4f02a89SMax Khon *inbytesleft -= in - ir; 225c4f02a89SMax Khon *outbytesleft -= on - or; 226c4f02a89SMax Khon return (ret); 227c4f02a89SMax Khon } 228c4f02a89SMax Khon 229c4f02a89SMax Khon static const char * 230c4f02a89SMax Khon iconv_xlat16_name(struct iconv_converter_class *dcp) 231c4f02a89SMax Khon { 232c4f02a89SMax Khon return ("xlat16"); 233c4f02a89SMax Khon } 234c4f02a89SMax Khon 235c4f02a89SMax Khon static kobj_method_t iconv_xlat16_methods[] = { 236c4f02a89SMax Khon KOBJMETHOD(iconv_converter_open, iconv_xlat16_open), 237c4f02a89SMax Khon KOBJMETHOD(iconv_converter_close, iconv_xlat16_close), 238c4f02a89SMax Khon KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv), 239c4f02a89SMax Khon #if 0 240c4f02a89SMax Khon KOBJMETHOD(iconv_converter_init, iconv_xlat16_init), 241c4f02a89SMax Khon KOBJMETHOD(iconv_converter_done, iconv_xlat16_done), 242c4f02a89SMax Khon #endif 243c4f02a89SMax Khon KOBJMETHOD(iconv_converter_name, iconv_xlat16_name), 244c4f02a89SMax Khon {0, 0} 245c4f02a89SMax Khon }; 246c4f02a89SMax Khon 247c4f02a89SMax Khon KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16)); 248