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