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/lib/libkiconv/xlat16_iconv.c 281550 2015-04-15 09:09:20Z tijl $
30 * kiconv(3) requires shared linked, and reduce module size
31 * when statically linked.
36 #include <sys/types.h>
37 #include <sys/iconv.h>
38 #include <sys/sysctl.h>
54 uint32_t * idx
[0x200];
59 static struct xlat16_table
kiconv_xlat16_open(const char *, const char *, int);
60 static int chklocale(int, const char *);
62 #define my_iconv_init() 0
63 #define my_iconv_open iconv_open
64 #define my_iconv iconv
65 #define my_iconv_close iconv_close
66 static size_t my_iconv_char(iconv_t
, u_char
**, size_t *, u_char
**, size_t *);
69 kiconv_add_xlat16_cspair(const char *tocode
, const char *fromcode
, int flag
)
73 struct xlat16_table xt
;
76 const char unicode
[] = ENCODING_UNICODE
;
78 if ((flag
& KICONV_WCTYPE
) == 0 &&
79 strcmp(unicode
, tocode
) != 0 &&
80 strcmp(unicode
, fromcode
) != 0 &&
81 kiconv_lookupconv(unicode
) == 0) {
82 error
= kiconv_add_xlat16_cspair(unicode
, fromcode
, flag
);
85 error
= kiconv_add_xlat16_cspair(tocode
, unicode
, flag
);
89 if (kiconv_lookupcs(tocode
, fromcode
) == 0)
92 if (flag
& KICONV_WCTYPE
)
93 xt
= kiconv_xlat16_open(fromcode
, fromcode
, flag
);
95 xt
= kiconv_xlat16_open(tocode
, fromcode
, flag
);
99 idxsize
= sizeof(xt
.idx
);
101 if ((idxsize
+ xt
.size
) > ICONV_CSMAXDATALEN
) {
106 if ((data
= malloc(idxsize
+ xt
.size
)) != NULL
) {
108 memcpy(p
, xt
.idx
, idxsize
);
110 memcpy(p
, xt
.data
, xt
.size
);
111 error
= kiconv_add_xlat16_table(tocode
, fromcode
, data
,
112 (int)(idxsize
+ xt
.size
));
120 kiconv_add_xlat16_cspairs(const char *foreigncode
, const char *localcode
)
124 error
= kiconv_add_xlat16_cspair(foreigncode
, localcode
,
125 KICONV_FROM_LOWER
| KICONV_FROM_UPPER
);
128 error
= kiconv_add_xlat16_cspair(localcode
, foreigncode
,
129 KICONV_LOWER
| KICONV_UPPER
);
132 locale
= chklocale(LC_CTYPE
, localcode
);
134 error
= kiconv_add_xlat16_cspair(KICONV_WCTYPE_NAME
, localcode
,
143 static struct xlat16_table
144 kiconv_xlat16_open(const char *tocode
, const char *fromcode
, int lcase
)
146 u_char src
[3], dst
[4], *srcp
, *dstp
, ud
, ld
;
149 uint32_t table
[0x80];
150 size_t inbytesleft
, outbytesleft
, pre_q_size
, post_q_size
;
151 struct xlat16_table xt
;
152 struct quirk_replace_list
*pre_q_list
, *post_q_list
;
162 ret
= my_iconv_init();
166 cd
= my_iconv_open(search_quirk(tocode
, fromcode
, &pre_q_list
, &pre_q_size
),
167 search_quirk(fromcode
, tocode
, &post_q_list
, &post_q_size
));
168 if (cd
== (iconv_t
) (-1))
171 if ((xt
.data
= malloc(0x200 * 0x80 * sizeof(uint32_t))) == NULL
)
176 for (ls
= 0 ; ls
< 0x200 ; ls
++) {
178 for (us
= 0 ; us
< 0x80 ; us
++) {
184 bzero(dst
, outbytesleft
);
186 c
= ((ls
& 0x100 ? us
| 0x80 : us
) << 8) | (u_char
)ls
;
188 if (lcase
& KICONV_WCTYPE
) {
193 if ((c
& 0xff00) == 0)
195 table
[us
] = c
| XLAT16_HAS_LOWER_CASE
;
196 } else if (iswlower(c
)) {
198 if ((c
& 0xff00) == 0)
200 table
[us
] = c
| XLAT16_HAS_UPPER_CASE
;
212 c
= quirk_vendor2unix(c
, pre_q_list
, pre_q_size
);
213 src
[0] = (u_char
)(c
>> 8);
216 ret
= my_iconv_char(cd
, &srcp
, &inbytesleft
,
217 &dstp
, &outbytesleft
);
226 switch(outbytesleft
) {
228 #ifdef XLAT16_ACCEPT_3BYTE_CHR
229 table
[us
] = (ud
<< 8) | ld
;
230 table
[us
] |= (u_char
)dst
[2] << 16;
231 table
[us
] |= XLAT16_IS_3BYTE_CHR
;
238 table
[us
] = quirk_unix2vendor((ud
<< 8) | ld
,
239 post_q_list
, post_q_size
);
240 if ((table
[us
] >> 8) == 0)
241 table
[us
] |= XLAT16_ACCEPT_NULL_OUT
;
245 if (lcase
& KICONV_LOWER
&& ud
!= tolower(ud
)) {
246 table
[us
] |= (u_char
)tolower(ud
) << 16;
247 table
[us
] |= XLAT16_HAS_LOWER_CASE
;
249 if (lcase
& KICONV_UPPER
&& ud
!= toupper(ud
)) {
250 table
[us
] |= (u_char
)toupper(ud
) << 16;
251 table
[us
] |= XLAT16_HAS_UPPER_CASE
;
256 switch(inbytesleft
) {
258 if ((ls
& 0xff) == 0)
259 table
[us
] |= XLAT16_ACCEPT_NULL_IN
;
262 c
= ls
> 0xff ? us
| 0x80 : us
;
263 if (lcase
& KICONV_FROM_LOWER
&& c
!= tolower(c
)) {
264 table
[us
] |= (u_char
)tolower(c
) << 16;
265 table
[us
] |= XLAT16_HAS_FROM_LOWER_CASE
;
267 if (lcase
& KICONV_FROM_UPPER
&& c
!= toupper(c
)) {
268 table
[us
] |= (u_char
)toupper(c
) << 16;
269 table
[us
] |= XLAT16_HAS_FROM_UPPER_CASE
;
283 memcpy(p
, table
, sizeof(table
));
289 xt
.size
= p
- (char *)xt
.data
;
290 xt
.data
= realloc(xt
.data
, xt
.size
);
295 chklocale(int category
, const char *code
)
300 p
= strchr(setlocale(category
, NULL
), '.');
302 error
= strcasecmp(code
, p
);
304 /* XXX - can't avoid calling quirk here... */
305 error
= strcasecmp(code
, kiconv_quirkcs(p
,
306 KICONV_VENDOR_MICSFT
));
313 my_iconv_char(iconv_t cd
, u_char
**ibuf
, size_t * ilen
, u_char
**obuf
,
316 u_char
*sp
, *dp
, ilocal
[3], olocal
[3];
326 ret
= my_iconv(cd
, (char **)&sp
, ilen
, (char **)&dp
, olen
);
331 if (*ilen
== ir
- 1 && (*ibuf
)[1] == '\0' && (c1
|| c2
))
338 * We must judge if inbuf is a single byte char or double byte char.
339 * Here, to judge, try first byte(*sp) conversion and compare.
345 memcpy(ilocal
, *ibuf
, sizeof(ilocal
));
349 if ((my_iconv(cd
, (char **)&sp
, &ir
, (char **)&dp
, &or)) !=
354 if (olocal
[1] == c2
&& (*ibuf
)[1] == '\0') {
356 * inbuf is a single byte char
366 if (olocal
[1] == c2
) {
368 * inbuf is a single byte char,
369 * so return false here.
374 * inbuf is a double byte char
381 * should compare second byte of inbuf
387 * inbuf clould not be splitted, so inbuf is
388 * a double byte char.
394 * try second byte(*(sp+1)) conversion, and compare
404 if ((my_iconv(cd
,(char **)&sp
, &ir
, (char **)&dp
, &or)) !=
408 * inbuf is a single byte char
416 #else /* statically linked */
418 #include <sys/types.h>
419 #include <sys/iconv.h>
423 kiconv_add_xlat16_cspair(const char *tocode __unused
, const char *fromcode __unused
,
432 kiconv_add_xlat16_cspairs(const char *tocode __unused
, const char *fromcode __unused
)