1 /*- 2 * Copyright (c) 2003, 2005 Ryuichiro Imura 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/iconv.h> 35 36 #include "iconv_converter_if.h" 37 38 /* 39 * "XLAT16" converter 40 */ 41 42 #ifdef MODULE_DEPEND 43 MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2); 44 #endif 45 46 #define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff) 47 #define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff) 48 49 /* 50 * XLAT16 converter instance 51 */ 52 struct iconv_xlat16 { 53 KOBJ_FIELDS; 54 uint32_t * d_table[0x200]; 55 void * f_ctp; 56 void * t_ctp; 57 struct iconv_cspair * d_csp; 58 }; 59 60 static int 61 iconv_xlat16_open(struct iconv_converter_class *dcp, 62 struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) 63 { 64 struct iconv_xlat16 *dp; 65 uint32_t *headp, **idxp; 66 int i; 67 68 dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); 69 headp = (uint32_t *)((caddr_t)csp->cp_data + sizeof(dp->d_table)); 70 idxp = (uint32_t **)csp->cp_data; 71 for (i = 0 ; i < 0x200 ; i++) { 72 if (*idxp) { 73 dp->d_table[i] = headp; 74 headp += 0x80; 75 } else { 76 dp->d_table[i] = NULL; 77 } 78 idxp++; 79 } 80 81 if (strcmp(csp->cp_to, KICONV_WCTYPE_NAME) != 0) { 82 if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_from, &dp->f_ctp) != 0) 83 dp->f_ctp = NULL; 84 if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_to, &dp->t_ctp) != 0) 85 dp->t_ctp = NULL; 86 } else { 87 dp->f_ctp = dp->t_ctp = dp; 88 } 89 90 dp->d_csp = csp; 91 csp->cp_refcount++; 92 *dpp = (void*)dp; 93 return (0); 94 } 95 96 static int 97 iconv_xlat16_close(void *data) 98 { 99 struct iconv_xlat16 *dp = data; 100 101 if (dp->f_ctp && dp->f_ctp != data) 102 iconv_close(dp->f_ctp); 103 if (dp->t_ctp && dp->t_ctp != data) 104 iconv_close(dp->t_ctp); 105 dp->d_csp->cp_refcount--; 106 kobj_delete((struct kobj*)data, M_ICONV); 107 return (0); 108 } 109 110 static int 111 iconv_xlat16_conv(void *d2p, const char **inbuf, 112 size_t *inbytesleft, char **outbuf, size_t *outbytesleft, 113 int convchar, int casetype) 114 { 115 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 116 const char *src; 117 char *dst; 118 int nullin, ret = 0; 119 size_t in, on, ir, or, inlen; 120 uint32_t code; 121 u_char u, l; 122 uint16_t c1, c2, ctmp; 123 124 if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) 125 return (0); 126 ir = in = *inbytesleft; 127 or = on = *outbytesleft; 128 src = *inbuf; 129 dst = *outbuf; 130 131 while(ir > 0 && or > 0) { 132 133 inlen = 0; 134 code = 0; 135 136 c1 = ir > 1 ? *(src+1) & 0xff : 0; 137 c2 = *src & 0xff; 138 ctmp = 0; 139 140 c1 = c2 & 0x80 ? c1 | 0x100 : c1; 141 c2 = c2 & 0x80 ? c2 & 0x7f : c2; 142 143 if (ir > 1 && dp->d_table[c1] && dp->d_table[c1][c2]) { 144 /* 145 * inbuf char is a double byte char 146 */ 147 inlen = 2; 148 149 /* toupper,tolower */ 150 if (casetype == KICONV_FROM_LOWER && dp->f_ctp) 151 ctmp = towlower(((u_char)*src << 8) | (u_char)*(src + 1), 152 dp->f_ctp); 153 else if (casetype == KICONV_FROM_UPPER && dp->f_ctp) 154 ctmp = towupper(((u_char)*src << 8) | (u_char)*(src + 1), 155 dp->f_ctp); 156 if (ctmp) { 157 c1 = C2I1(ctmp); 158 c2 = C2I2(ctmp); 159 } 160 } 161 162 if (inlen == 0) { 163 c1 &= 0xff00; 164 if (!dp->d_table[c1]) { 165 ret = -1; 166 break; 167 } 168 /* 169 * inbuf char is a single byte char 170 */ 171 inlen = 1; 172 173 if (casetype & (KICONV_FROM_LOWER|KICONV_FROM_UPPER)) 174 code = dp->d_table[c1][c2]; 175 176 if (casetype == KICONV_FROM_LOWER) { 177 if (dp->f_ctp) 178 ctmp = towlower((u_char)*src, dp->f_ctp); 179 else if (code & XLAT16_HAS_FROM_LOWER_CASE) 180 ctmp = (u_char)(code >> 16); 181 } else if (casetype == KICONV_FROM_UPPER) { 182 if (dp->f_ctp) 183 ctmp = towupper((u_char)*src, dp->f_ctp); 184 else if (code & XLAT16_HAS_FROM_UPPER_CASE) 185 ctmp = (u_char)(code >> 16); 186 } 187 if (ctmp) { 188 c1 = C2I1(ctmp << 8); 189 c2 = C2I2(ctmp << 8); 190 } 191 } 192 193 code = dp->d_table[c1][c2]; 194 if (!code) { 195 ret = -1; 196 break; 197 } 198 199 nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0; 200 if (inlen == 1 && nullin) { 201 /* 202 * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte 203 */ 204 ret = -1; 205 break; 206 } 207 208 /* 209 * now start translation 210 */ 211 u = (u_char)(code >> 8); 212 l = (u_char)code; 213 214 #ifdef XLAT16_ACCEPT_3BYTE_CHR 215 if (code & XLAT16_IS_3BYTE_CHR) { 216 if (or < 3) { 217 ret = -1; 218 break; 219 } 220 *dst++ = u; 221 *dst++ = l; 222 *dst++ = (u_char)(code >> 16); 223 or -= 3; 224 } else 225 #endif 226 if (u || code & XLAT16_ACCEPT_NULL_OUT) { 227 if (or < 2) { 228 ret = -1; 229 break; 230 } 231 232 /* toupper,tolower */ 233 if (casetype == KICONV_LOWER && dp->t_ctp) { 234 code = towlower((uint16_t)code, dp->t_ctp); 235 u = (u_char)(code >> 8); 236 l = (u_char)code; 237 } 238 if (casetype == KICONV_UPPER && dp->t_ctp) { 239 code = towupper((uint16_t)code, dp->t_ctp); 240 u = (u_char)(code >> 8); 241 l = (u_char)code; 242 } 243 244 *dst++ = u; 245 *dst++ = l; 246 or -= 2; 247 } else { 248 /* toupper,tolower */ 249 if (casetype == KICONV_LOWER) { 250 if (dp->t_ctp) 251 l = (u_char)towlower(l, dp->t_ctp); 252 else if (code & XLAT16_HAS_LOWER_CASE) 253 l = (u_char)(code >> 16); 254 } 255 if (casetype == KICONV_UPPER) { 256 if (dp->t_ctp) 257 l = (u_char)towupper(l, dp->t_ctp); 258 else if (code & XLAT16_HAS_UPPER_CASE) 259 l = (u_char)(code >> 16); 260 } 261 262 *dst++ = l; 263 or--; 264 } 265 266 if (inlen == 2) { 267 /* 268 * there is a case that inbuf char is a single 269 * byte char while inlen == 2 270 */ 271 if ((u_char)*(src+1) == 0 && !nullin ) { 272 src++; 273 ir--; 274 } else { 275 src += 2; 276 ir -= 2; 277 } 278 } else { 279 src++; 280 ir--; 281 } 282 283 if (convchar == 1) 284 break; 285 } 286 287 *inbuf += in - ir; 288 *outbuf += on - or; 289 *inbytesleft -= in - ir; 290 *outbytesleft -= on - or; 291 return (ret); 292 } 293 294 static const char * 295 iconv_xlat16_name(struct iconv_converter_class *dcp) 296 { 297 return ("xlat16"); 298 } 299 300 static int 301 iconv_xlat16_tolower(void *d2p, register int c) 302 { 303 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 304 register int c1, c2, out; 305 306 if (c < 0x100) { 307 c1 = C2I1(c << 8); 308 c2 = C2I2(c << 8); 309 } else if (c < 0x10000) { 310 c1 = C2I1(c); 311 c2 = C2I2(c); 312 } else 313 return (c); 314 315 if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_LOWER_CASE) { 316 /*return (int)(dp->d_table[c1][c2] & 0xffff);*/ 317 out = dp->d_table[c1][c2] & 0xffff; 318 if ((out & 0xff) == 0) 319 out = (out >> 8) & 0xff; 320 return (out); 321 } else 322 return (c); 323 } 324 325 static int 326 iconv_xlat16_toupper(void *d2p, register int c) 327 { 328 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 329 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 349 static 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 363 KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16)); 364