2 * Copyright (c) 2003 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: src/lib/libkiconv/xlat16_iconv.c,v 1.4.8.1 2009/04/15 03:14:26 kensmith Exp $
30 * kiconv(3) requires shared linked, and reduce module size
31 * when statically linked.
33 #include <sys/types.h>
34 #include <sys/iconv.h>
35 #include <sys/sysctl.h>
49 uint32_t * idx
[0x200];
54 static struct xlat16_table
kiconv_xlat16_open(const char *, const char *, int);
56 static int my_iconv_init(void);
57 static iconv_t (*my_iconv_open
)(const char *, const char *);
58 static size_t (*my_iconv
)(iconv_t
, const char **, size_t *, char **, size_t *);
59 static int (*my_iconv_close
)(iconv_t
);
60 static size_t my_iconv_char(iconv_t
, const u_char
**, size_t *, u_char
**, size_t *);
63 kiconv_add_xlat16_cspair(const char *tocode
, const char *fromcode
, int flag
)
66 size_t i
, size
, idxsize
;
67 struct iconv_cspair_info
*csi
;
68 struct xlat16_table xt
;
71 if (sysctlbyname("kern.iconv.cslist", NULL
, &size
, NULL
, 0) == -1)
77 if (sysctlbyname("kern.iconv.cslist", csi
, &size
, NULL
, 0) == -1) {
81 for (i
= 0; i
< (size
/sizeof(*csi
)); i
++, csi
++){
82 if (strcmp(csi
->cs_to
, tocode
) == 0 &&
83 strcmp(csi
->cs_from
, fromcode
) == 0)
88 xt
= kiconv_xlat16_open(tocode
, fromcode
, flag
);
92 idxsize
= sizeof(xt
.idx
);
94 if ((idxsize
+ xt
.size
) > ICONV_CSMAXDATALEN
) {
99 if ((data
= malloc(idxsize
+ xt
.size
)) != NULL
) {
101 memcpy(p
, xt
.idx
, idxsize
);
103 memcpy(p
, xt
.data
, xt
.size
);
104 error
= kiconv_add_xlat16_table(tocode
, fromcode
, data
,
105 (int)(idxsize
+ xt
.size
));
112 kiconv_add_xlat16_cspairs(const char *foreigncode
, const char *localcode
)
116 error
= kiconv_add_xlat16_cspair(foreigncode
, localcode
,
117 KICONV_FROM_LOWER
| KICONV_FROM_UPPER
);
120 error
= kiconv_add_xlat16_cspair(localcode
, foreigncode
,
121 KICONV_LOWER
| KICONV_UPPER
);
127 static struct xlat16_table
128 kiconv_xlat16_open(const char *tocode
, const char *fromcode
, int lcase
)
130 u_char src
[3], dst
[4], *srcp
, *dstp
, ud
, ld
;
133 uint32_t table
[0x80];
134 size_t inbytesleft
, outbytesleft
, pre_q_size
, post_q_size
;
135 struct xlat16_table xt
;
136 struct quirk_replace_list
*pre_q_list
, *post_q_list
;
145 ret
= my_iconv_init();
148 cd
= my_iconv_open(search_quirk(tocode
, fromcode
, &pre_q_list
, &pre_q_size
),
149 search_quirk(fromcode
, tocode
, &post_q_list
, &post_q_size
));
150 if (cd
== (iconv_t
) (-1))
153 if ((xt
.data
= malloc(0x200 * 0x80 * sizeof(uint32_t))) == NULL
)
158 for (ls
= 0 ; ls
< 0x200 ; ls
++) {
160 for (us
= 0 ; us
< 0x80 ; us
++) {
166 bzero(dst
, outbytesleft
);
168 c
= ((ls
& 0x100 ? us
| 0x80 : us
) << 8) | (u_char
)ls
;
169 c
= quirk_vendor2unix(c
, pre_q_list
, pre_q_size
);
170 src
[0] = (u_char
)(c
>> 8);
173 ret
= my_iconv_char(cd
, (const u_char
**)&srcp
,
174 &inbytesleft
, &dstp
, &outbytesleft
);
183 switch(outbytesleft
) {
185 #ifdef XLAT16_ACCEPT_3BYTE_CHR
186 table
[us
] = (ud
<< 8) | ld
;
187 table
[us
] |= (u_char
)dst
[2] << 16;
188 table
[us
] |= XLAT16_IS_3BYTE_CHR
;
195 table
[us
] = quirk_unix2vendor((ud
<< 8) | ld
,
196 post_q_list
, post_q_size
);
197 if ((table
[us
] >> 8) == 0)
198 table
[us
] |= XLAT16_ACCEPT_NULL_OUT
;
202 if (lcase
& KICONV_LOWER
&& ud
!= tolower(ud
)) {
203 table
[us
] |= (u_char
)tolower(ud
) << 16;
204 table
[us
] |= XLAT16_HAS_LOWER_CASE
;
206 if (lcase
& KICONV_UPPER
&& ud
!= toupper(ud
)) {
207 table
[us
] |= (u_char
)toupper(ud
) << 16;
208 table
[us
] |= XLAT16_HAS_UPPER_CASE
;
213 switch(inbytesleft
) {
215 if ((ls
& 0xff) == 0)
216 table
[us
] |= XLAT16_ACCEPT_NULL_IN
;
219 c
= ls
> 0xff ? us
| 0x80 : us
;
220 if (lcase
& KICONV_FROM_LOWER
&& c
!= tolower(c
)) {
221 table
[us
] |= (u_char
)tolower(c
) << 16;
222 table
[us
] |= XLAT16_HAS_FROM_LOWER_CASE
;
224 if (lcase
& KICONV_FROM_UPPER
&& c
!= toupper(c
)) {
225 table
[us
] |= (u_char
)toupper(c
) << 16;
226 table
[us
] |= XLAT16_HAS_FROM_UPPER_CASE
;
240 memcpy(p
, table
, sizeof(table
));
246 xt
.size
= p
- (char *)xt
.data
;
247 xt
.data
= realloc(xt
.data
, xt
.size
);
256 iconv_lib
= dlopen("libc.so", RTLD_LAZY
| RTLD_GLOBAL
);
257 if (iconv_lib
== NULL
) {
258 warn("Unable to load iconv library: %s\n", dlerror());
262 my_iconv_open
= dlsym(iconv_lib
, "iconv_open");
263 my_iconv
= dlsym(iconv_lib
, "iconv");
264 my_iconv_close
= dlsym(iconv_lib
, "iconv_close");
266 my_iconv_open
= iconv_open
;
268 my_iconv_close
= iconv_close
;
275 my_iconv_char(iconv_t cd
, const u_char
**ibuf
, size_t * ilen
, u_char
**obuf
,
279 u_char
*dp
, ilocal
[3], olocal
[3];
289 ret
= my_iconv(cd
, (const char **)&sp
, ilen
, (char **)&dp
, olen
);
294 if (*ilen
== ir
- 1 && (*ibuf
)[1] == '\0' && (c1
|| c2
))
301 * We must judge if inbuf is a single byte char or double byte char.
302 * Here, to judge, try first byte(*sp) conversion and compare.
308 memcpy(ilocal
, *ibuf
, sizeof(ilocal
));
312 if ((my_iconv(cd
,(const char **)&sp
, &ir
, (char **)&dp
, &or)) != -1) {
316 if (olocal
[1] == c2
&& (*ibuf
)[1] == '\0') {
318 * inbuf is a single byte char
328 if (olocal
[1] == c2
) {
330 * inbuf is a single byte char,
331 * so return false here.
336 * inbuf is a double byte char
343 * should compare second byte of inbuf
349 * inbuf clould not be splitted, so inbuf is
350 * a double byte char.
356 * try second byte(*(sp+1)) conversion, and compare
366 if ((my_iconv(cd
,(const char **)&sp
, &ir
, (char **)&dp
, &or)) != -1) {
369 * inbuf is a single byte char