1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 30 #include <sys/kernel.h> 31 #include <sys/systm.h> 32 #include <sys/malloc.h> 33 #include <sys/iconv.h> 34 35 #include "iconv_converter_if.h" 36 37 /* 38 * "XLAT16" converter 39 */ 40 41 #ifdef MODULE_DEPEND 42 MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2); 43 #endif 44 45 #define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff) 46 #define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff) 47 48 /* 49 * XLAT16 converter instance 50 */ 51 struct iconv_xlat16 { 52 KOBJ_FIELDS; 53 uint32_t * d_table[0x200]; 54 void * f_ctp; 55 void * t_ctp; 56 struct iconv_cspair * d_csp; 57 }; 58 59 static int 60 iconv_xlat16_open(struct iconv_converter_class *dcp, 61 struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) 62 { 63 struct iconv_xlat16 *dp; 64 uint32_t *headp, **idxp; 65 int i; 66 67 dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); 68 headp = (uint32_t *)((caddr_t)csp->cp_data + sizeof(dp->d_table)); 69 idxp = (uint32_t **)csp->cp_data; 70 for (i = 0 ; i < 0x200 ; i++) { 71 if (*idxp) { 72 dp->d_table[i] = headp; 73 headp += 0x80; 74 } else { 75 dp->d_table[i] = NULL; 76 } 77 idxp++; 78 } 79 80 if (strcmp(csp->cp_to, KICONV_WCTYPE_NAME) != 0) { 81 if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_from, &dp->f_ctp) != 0) 82 dp->f_ctp = NULL; 83 if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_to, &dp->t_ctp) != 0) 84 dp->t_ctp = NULL; 85 } else { 86 dp->f_ctp = dp->t_ctp = dp; 87 } 88 89 dp->d_csp = csp; 90 csp->cp_refcount++; 91 *dpp = (void*)dp; 92 return (0); 93 } 94 95 static int 96 iconv_xlat16_close(void *data) 97 { 98 struct iconv_xlat16 *dp = data; 99 100 if (dp->f_ctp && dp->f_ctp != data) 101 iconv_close(dp->f_ctp); 102 if (dp->t_ctp && dp->t_ctp != data) 103 iconv_close(dp->t_ctp); 104 dp->d_csp->cp_refcount--; 105 kobj_delete((struct kobj*)data, M_ICONV); 106 return (0); 107 } 108 109 static int 110 iconv_xlat16_conv(void *d2p, const char **inbuf, 111 size_t *inbytesleft, char **outbuf, size_t *outbytesleft, 112 int convchar, int casetype) 113 { 114 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 115 const char *src; 116 char *dst; 117 int nullin, ret = 0; 118 size_t in, on, ir, or, inlen; 119 uint32_t code; 120 u_char u, l; 121 uint16_t c1, c2, ctmp; 122 123 if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) 124 return (0); 125 ir = in = *inbytesleft; 126 or = on = *outbytesleft; 127 src = *inbuf; 128 dst = *outbuf; 129 130 while(ir > 0 && or > 0) { 131 inlen = 0; 132 code = 0; 133 134 c1 = ir > 1 ? *(src+1) & 0xff : 0; 135 c2 = *src & 0xff; 136 ctmp = 0; 137 138 c1 = c2 & 0x80 ? c1 | 0x100 : c1; 139 c2 = c2 & 0x80 ? c2 & 0x7f : c2; 140 141 if (ir > 1 && dp->d_table[c1] && dp->d_table[c1][c2]) { 142 /* 143 * inbuf char is a double byte char 144 */ 145 inlen = 2; 146 147 /* toupper,tolower */ 148 if (casetype == KICONV_FROM_LOWER && dp->f_ctp) 149 ctmp = towlower(((u_char)*src << 8) | (u_char)*(src + 1), 150 dp->f_ctp); 151 else if (casetype == KICONV_FROM_UPPER && dp->f_ctp) 152 ctmp = towupper(((u_char)*src << 8) | (u_char)*(src + 1), 153 dp->f_ctp); 154 if (ctmp) { 155 c1 = C2I1(ctmp); 156 c2 = C2I2(ctmp); 157 } 158 } 159 160 if (inlen == 0) { 161 c1 &= 0xff00; 162 if (!dp->d_table[c1]) { 163 ret = -1; 164 break; 165 } 166 /* 167 * inbuf char is a single byte char 168 */ 169 inlen = 1; 170 171 if (casetype & (KICONV_FROM_LOWER|KICONV_FROM_UPPER)) 172 code = dp->d_table[c1][c2]; 173 174 if (casetype == KICONV_FROM_LOWER) { 175 if (dp->f_ctp) 176 ctmp = towlower((u_char)*src, dp->f_ctp); 177 else if (code & XLAT16_HAS_FROM_LOWER_CASE) 178 ctmp = (u_char)(code >> 16); 179 } else if (casetype == KICONV_FROM_UPPER) { 180 if (dp->f_ctp) 181 ctmp = towupper((u_char)*src, dp->f_ctp); 182 else if (code & XLAT16_HAS_FROM_UPPER_CASE) 183 ctmp = (u_char)(code >> 16); 184 } 185 if (ctmp) { 186 c1 = C2I1(ctmp << 8); 187 c2 = C2I2(ctmp << 8); 188 } 189 } 190 191 code = dp->d_table[c1][c2]; 192 if (!code) { 193 ret = -1; 194 break; 195 } 196 197 nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0; 198 if (inlen == 1 && nullin) { 199 /* 200 * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte 201 */ 202 ret = -1; 203 break; 204 } 205 206 /* 207 * now start translation 208 */ 209 u = (u_char)(code >> 8); 210 l = (u_char)code; 211 212 #ifdef XLAT16_ACCEPT_3BYTE_CHR 213 if (code & XLAT16_IS_3BYTE_CHR) { 214 if (or < 3) { 215 ret = -1; 216 break; 217 } 218 *dst++ = u; 219 *dst++ = l; 220 *dst++ = (u_char)(code >> 16); 221 or -= 3; 222 } else 223 #endif 224 if (u || code & XLAT16_ACCEPT_NULL_OUT) { 225 if (or < 2) { 226 ret = -1; 227 break; 228 } 229 230 /* toupper,tolower */ 231 if (casetype == KICONV_LOWER && dp->t_ctp) { 232 code = towlower((uint16_t)code, dp->t_ctp); 233 u = (u_char)(code >> 8); 234 l = (u_char)code; 235 } 236 if (casetype == KICONV_UPPER && dp->t_ctp) { 237 code = towupper((uint16_t)code, dp->t_ctp); 238 u = (u_char)(code >> 8); 239 l = (u_char)code; 240 } 241 242 *dst++ = u; 243 *dst++ = l; 244 or -= 2; 245 } else { 246 /* toupper,tolower */ 247 if (casetype == KICONV_LOWER) { 248 if (dp->t_ctp) 249 l = (u_char)towlower(l, dp->t_ctp); 250 else if (code & XLAT16_HAS_LOWER_CASE) 251 l = (u_char)(code >> 16); 252 } 253 if (casetype == KICONV_UPPER) { 254 if (dp->t_ctp) 255 l = (u_char)towupper(l, dp->t_ctp); 256 else if (code & XLAT16_HAS_UPPER_CASE) 257 l = (u_char)(code >> 16); 258 } 259 260 *dst++ = l; 261 or--; 262 } 263 264 if (inlen == 2) { 265 /* 266 * there is a case that inbuf char is a single 267 * byte char while inlen == 2 268 */ 269 if ((u_char)*(src+1) == '\0' && !nullin ) { 270 src++; 271 ir--; 272 } else { 273 src += 2; 274 ir -= 2; 275 } 276 } else { 277 src++; 278 ir--; 279 } 280 281 if (convchar == 1) 282 break; 283 } 284 285 *inbuf += in - ir; 286 *outbuf += on - or; 287 *inbytesleft -= in - ir; 288 *outbytesleft -= on - or; 289 return (ret); 290 } 291 292 static const char * 293 iconv_xlat16_name(struct iconv_converter_class *dcp) 294 { 295 return ("xlat16"); 296 } 297 298 static int 299 iconv_xlat16_tolower(void *d2p, int c) 300 { 301 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 302 int c1, c2, out; 303 304 if (c < 0x100) { 305 c1 = C2I1(c << 8); 306 c2 = C2I2(c << 8); 307 } else if (c < 0x10000) { 308 c1 = C2I1(c); 309 c2 = C2I2(c); 310 } else 311 return (c); 312 313 if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_LOWER_CASE) { 314 /*return (int)(dp->d_table[c1][c2] & 0xffff);*/ 315 out = dp->d_table[c1][c2] & 0xffff; 316 if ((out & 0xff) == 0) 317 out = (out >> 8) & 0xff; 318 return (out); 319 } else 320 return (c); 321 } 322 323 static int 324 iconv_xlat16_toupper(void *d2p, int c) 325 { 326 struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p; 327 int c1, c2, out; 328 329 if (c < 0x100) { 330 c1 = C2I1(c << 8); 331 c2 = C2I2(c << 8); 332 } else if (c < 0x10000) { 333 c1 = C2I1(c); 334 c2 = C2I2(c); 335 } else 336 return (c); 337 338 if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_UPPER_CASE) { 339 out = dp->d_table[c1][c2] & 0xffff; 340 if ((out & 0xff) == 0) 341 out = (out >> 8) & 0xff; 342 return (out); 343 } else 344 return (c); 345 } 346 347 static kobj_method_t iconv_xlat16_methods[] = { 348 KOBJMETHOD(iconv_converter_open, iconv_xlat16_open), 349 KOBJMETHOD(iconv_converter_close, iconv_xlat16_close), 350 KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv), 351 #if 0 352 KOBJMETHOD(iconv_converter_init, iconv_xlat16_init), 353 KOBJMETHOD(iconv_converter_done, iconv_xlat16_done), 354 #endif 355 KOBJMETHOD(iconv_converter_name, iconv_xlat16_name), 356 KOBJMETHOD(iconv_converter_tolower, iconv_xlat16_tolower), 357 KOBJMETHOD(iconv_converter_toupper, iconv_xlat16_toupper), 358 {0, 0} 359 }; 360 361 KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16)); 362