2 * Copyright (c) 2003, 2005 Ryuichiro Imura
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: head/sys/libkern/iconv_xlat16.c 194638 2009-06-22 17:09:46Z delphij $
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>
35 #include "iconv_converter_if.h"
42 MODULE_DEPEND(iconv_xlat16
, libiconv
, 2, 2, 2);
45 #define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff)
46 #define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff)
49 * XLAT16 converter instance
53 uint32_t * d_table
[0x200];
56 struct iconv_cspair
* d_csp
;
60 iconv_xlat16_open(struct iconv_converter_class
*dcp
,
61 struct iconv_cspair
*csp
, struct iconv_cspair
*cspf
, void **dpp
)
63 struct iconv_xlat16
*dp
;
64 uint32_t *headp
, **idxp
;
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
++) {
72 dp
->d_table
[i
] = headp
;
75 dp
->d_table
[i
] = NULL
;
80 if (strcmp(csp
->cp_to
, KICONV_WCTYPE_NAME
) != 0) {
81 if (iconv_open(KICONV_WCTYPE_NAME
, csp
->cp_from
, &dp
->f_ctp
) != 0)
83 if (iconv_open(KICONV_WCTYPE_NAME
, csp
->cp_to
, &dp
->t_ctp
) != 0)
86 dp
->f_ctp
= dp
->t_ctp
= dp
;
96 iconv_xlat16_close(void *data
)
98 struct iconv_xlat16
*dp
= data
;
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
);
110 iconv_xlat16_conv(void *d2p
, const char **inbuf
,
111 size_t *inbytesleft
, char **outbuf
, size_t *outbytesleft
,
112 int convchar
, int casetype
)
114 struct iconv_xlat16
*dp
= (struct iconv_xlat16
*)d2p
;
118 size_t in
, on
, ir
, or, inlen
;
121 uint16_t c1
, c2
, ctmp
;
123 if (inbuf
== NULL
|| *inbuf
== NULL
|| outbuf
== NULL
|| *outbuf
== NULL
)
125 ir
= in
= *inbytesleft
;
126 or = on
= *outbytesleft
;
130 while(ir
> 0 && or > 0) {
135 c1
= ir
> 1 ? *(src
+1) & 0xff : 0;
139 c1
= c2
& 0x80 ? c1
| 0x100 : c1
;
140 c2
= c2
& 0x80 ? c2
& 0x7f : c2
;
142 if (ir
> 1 && dp
->d_table
[c1
] && dp
->d_table
[c1
][c2
]) {
144 * inbuf char is a double byte char
148 /* toupper,tolower */
149 if (casetype
== KICONV_FROM_LOWER
&& dp
->f_ctp
)
150 ctmp
= towlower(((u_char
)*src
<< 8) | (u_char
)*(src
+ 1),
152 else if (casetype
== KICONV_FROM_UPPER
&& dp
->f_ctp
)
153 ctmp
= towupper(((u_char
)*src
<< 8) | (u_char
)*(src
+ 1),
163 if (!dp
->d_table
[c1
]) {
168 * inbuf char is a single byte char
172 if (casetype
& (KICONV_FROM_LOWER
|KICONV_FROM_UPPER
))
173 code
= dp
->d_table
[c1
][c2
];
175 if (casetype
== KICONV_FROM_LOWER
) {
177 ctmp
= towlower((u_char
)*src
, dp
->f_ctp
);
178 else if (code
& XLAT16_HAS_FROM_LOWER_CASE
)
179 ctmp
= (u_char
)(code
>> 16);
180 } else if (casetype
== KICONV_FROM_UPPER
) {
182 ctmp
= towupper((u_char
)*src
, dp
->f_ctp
);
183 else if (code
& XLAT16_HAS_FROM_UPPER_CASE
)
184 ctmp
= (u_char
)(code
>> 16);
187 c1
= C2I1(ctmp
<< 8);
188 c2
= C2I2(ctmp
<< 8);
192 code
= dp
->d_table
[c1
][c2
];
198 nullin
= (code
& XLAT16_ACCEPT_NULL_IN
) ? 1 : 0;
199 if (inlen
== 1 && nullin
) {
201 * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte
208 * now start translation
210 u
= (u_char
)(code
>> 8);
213 #ifdef XLAT16_ACCEPT_3BYTE_CHR
214 if (code
& XLAT16_IS_3BYTE_CHR
) {
221 *dst
++ = (u_char
)(code
>> 16);
225 if (u
|| code
& XLAT16_ACCEPT_NULL_OUT
) {
231 /* toupper,tolower */
232 if (casetype
== KICONV_LOWER
&& dp
->t_ctp
) {
233 code
= towlower((uint16_t)code
, dp
->t_ctp
);
234 u
= (u_char
)(code
>> 8);
237 if (casetype
== KICONV_UPPER
&& dp
->t_ctp
) {
238 code
= towupper((uint16_t)code
, dp
->t_ctp
);
239 u
= (u_char
)(code
>> 8);
247 /* toupper,tolower */
248 if (casetype
== KICONV_LOWER
) {
250 l
= (u_char
)towlower(l
, dp
->t_ctp
);
251 else if (code
& XLAT16_HAS_LOWER_CASE
)
252 l
= (u_char
)(code
>> 16);
254 if (casetype
== KICONV_UPPER
) {
256 l
= (u_char
)towupper(l
, dp
->t_ctp
);
257 else if (code
& XLAT16_HAS_UPPER_CASE
)
258 l
= (u_char
)(code
>> 16);
267 * there is a case that inbuf char is a single
268 * byte char while inlen == 2
270 if ((u_char
)*(src
+1) == 0 && !nullin
) {
288 *inbytesleft
-= in
- ir
;
289 *outbytesleft
-= on
- or;
294 iconv_xlat16_name(struct iconv_converter_class
*dcp
)
300 iconv_xlat16_tolower(void *d2p
, int c
)
302 struct iconv_xlat16
*dp
= (struct iconv_xlat16
*)d2p
;
308 } else if (c
< 0x10000) {
314 if (dp
->d_table
[c1
] && dp
->d_table
[c1
][c2
] & XLAT16_HAS_LOWER_CASE
) {
315 /*return (int)(dp->d_table[c1][c2] & 0xffff);*/
316 out
= dp
->d_table
[c1
][c2
] & 0xffff;
317 if ((out
& 0xff) == 0)
318 out
= (out
>> 8) & 0xff;
325 iconv_xlat16_toupper(void *d2p
, int c
)
327 struct iconv_xlat16
*dp
= (struct iconv_xlat16
*)d2p
;
333 } else if (c
< 0x10000) {
339 if (dp
->d_table
[c1
] && dp
->d_table
[c1
][c2
] & XLAT16_HAS_UPPER_CASE
) {
340 out
= dp
->d_table
[c1
][c2
] & 0xffff;
341 if ((out
& 0xff) == 0)
342 out
= (out
>> 8) & 0xff;
348 static kobj_method_t iconv_xlat16_methods
[] = {
349 KOBJMETHOD(iconv_converter_open
, iconv_xlat16_open
),
350 KOBJMETHOD(iconv_converter_close
, iconv_xlat16_close
),
351 KOBJMETHOD(iconv_converter_conv
, iconv_xlat16_conv
),
353 KOBJMETHOD(iconv_converter_init
, iconv_xlat16_init
),
354 KOBJMETHOD(iconv_converter_done
, iconv_xlat16_done
),
356 KOBJMETHOD(iconv_converter_name
, iconv_xlat16_name
),
357 KOBJMETHOD(iconv_converter_tolower
, iconv_xlat16_tolower
),
358 KOBJMETHOD(iconv_converter_toupper
, iconv_xlat16_toupper
),
362 KICONV_CONVERTER(xlat16
, sizeof(struct iconv_xlat16
));