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; 99c4f02a89SMax Khon int ret = 0; 100c4f02a89SMax Khon size_t in, on, ir, or, inlen; 101c4f02a89SMax Khon uint32_t code; 102c4f02a89SMax Khon u_char u, l; 103c4f02a89SMax Khon u_int16_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 149c4f02a89SMax Khon if ((inlen == 1) && (code & XLAT16_ACCEPT_NULL_IN)) { 150c4f02a89SMax Khon /* 151c4f02a89SMax Khon * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte 152c4f02a89SMax Khon */ 153c4f02a89SMax Khon ret = -1; 154c4f02a89SMax Khon break; 155c4f02a89SMax Khon } 156c4f02a89SMax Khon 157c4f02a89SMax Khon /* 158c4f02a89SMax Khon * now start translation 159c4f02a89SMax Khon */ 160c4f02a89SMax Khon u = (u_char)(code >> 8); 161c4f02a89SMax Khon l = (u_char)code; 162c4f02a89SMax Khon 163c4f02a89SMax Khon #ifdef XLAT16_ACCEPT_3BYTE_CHR 164c4f02a89SMax Khon if (code & XLAT16_IS_3BYTE_CHR) { 165c4f02a89SMax Khon if (or < 3) { 166c4f02a89SMax Khon ret = -1; 167c4f02a89SMax Khon break; 168c4f02a89SMax Khon } 169c4f02a89SMax Khon *dst++ = u; 170c4f02a89SMax Khon *dst++ = l; 171c4f02a89SMax Khon *dst++ = (u_char)(code >> 16); 172c4f02a89SMax Khon or -= 3; 173c4f02a89SMax Khon } else 174c4f02a89SMax Khon #endif 175c4f02a89SMax Khon if (u || code & XLAT16_ACCEPT_NULL_OUT) { 176c4f02a89SMax Khon if (or < 2) { 177c4f02a89SMax Khon ret = -1; 178c4f02a89SMax Khon break; 179c4f02a89SMax Khon } 180c4f02a89SMax Khon *dst++ = u; 181c4f02a89SMax Khon *dst++ = l; 182c4f02a89SMax Khon or -= 2; 183c4f02a89SMax Khon } else { 184c4f02a89SMax Khon if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) || 185c4f02a89SMax Khon (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE)) 186c4f02a89SMax Khon *dst++ = (u_char)(code >> 16); 187c4f02a89SMax Khon else if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) || 188c4f02a89SMax Khon (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE)) 189c4f02a89SMax Khon *dst++ = dp->d_table[0][(u_char)(code >> 16)]; 190c4f02a89SMax Khon else 191c4f02a89SMax Khon *dst++ = l; 192c4f02a89SMax Khon or--; 193c4f02a89SMax Khon } 194c4f02a89SMax Khon 195c4f02a89SMax Khon if (inlen == 2) { 196c4f02a89SMax Khon /* 197c4f02a89SMax Khon * there is a case that inbuf char is a single 198c4f02a89SMax Khon * byte char while inlen == 2 199c4f02a89SMax Khon */ 200c4f02a89SMax Khon if ((u_char)*(src+1) == 0 && 201c4f02a89SMax Khon (code & XLAT16_ACCEPT_NULL_IN) == 0 ) { 202c4f02a89SMax Khon src++; 203c4f02a89SMax Khon ir--; 204c4f02a89SMax Khon } else { 205c4f02a89SMax Khon src += 2; 206c4f02a89SMax Khon ir -= 2; 207c4f02a89SMax Khon } 208c4f02a89SMax Khon } else { 209c4f02a89SMax Khon src++; 210c4f02a89SMax Khon ir--; 211c4f02a89SMax Khon } 212c4f02a89SMax Khon 213c4f02a89SMax Khon if (convchar == 1) 214c4f02a89SMax Khon break; 215c4f02a89SMax Khon } 216c4f02a89SMax Khon 217c4f02a89SMax Khon *inbuf += in - ir; 218c4f02a89SMax Khon *outbuf += on - or; 219c4f02a89SMax Khon *inbytesleft -= in - ir; 220c4f02a89SMax Khon *outbytesleft -= on - or; 221c4f02a89SMax Khon return (ret); 222c4f02a89SMax Khon } 223c4f02a89SMax Khon 224c4f02a89SMax Khon static const char * 225c4f02a89SMax Khon iconv_xlat16_name(struct iconv_converter_class *dcp) 226c4f02a89SMax Khon { 227c4f02a89SMax Khon return ("xlat16"); 228c4f02a89SMax Khon } 229c4f02a89SMax Khon 230c4f02a89SMax Khon static kobj_method_t iconv_xlat16_methods[] = { 231c4f02a89SMax Khon KOBJMETHOD(iconv_converter_open, iconv_xlat16_open), 232c4f02a89SMax Khon KOBJMETHOD(iconv_converter_close, iconv_xlat16_close), 233c4f02a89SMax Khon KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv), 234c4f02a89SMax Khon #if 0 235c4f02a89SMax Khon KOBJMETHOD(iconv_converter_init, iconv_xlat16_init), 236c4f02a89SMax Khon KOBJMETHOD(iconv_converter_done, iconv_xlat16_done), 237c4f02a89SMax Khon #endif 238c4f02a89SMax Khon KOBJMETHOD(iconv_converter_name, iconv_xlat16_name), 239c4f02a89SMax Khon {0, 0} 240c4f02a89SMax Khon }; 241c4f02a89SMax Khon 242c4f02a89SMax Khon KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16)); 243