xref: /onnv-gate/usr/src/uts/common/os/kiconv.c (revision 5206:34f0b41fc3c5)
1*5206Sis /*
2*5206Sis  * CDDL HEADER START
3*5206Sis  *
4*5206Sis  * The contents of this file are subject to the terms of the
5*5206Sis  * Common Development and Distribution License (the "License").
6*5206Sis  * You may not use this file except in compliance with the License.
7*5206Sis  *
8*5206Sis  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5206Sis  * or http://www.opensolaris.org/os/licensing.
10*5206Sis  * See the License for the specific language governing permissions
11*5206Sis  * and limitations under the License.
12*5206Sis  *
13*5206Sis  * When distributing Covered Code, include this CDDL HEADER in each
14*5206Sis  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5206Sis  * If applicable, add the following below this CDDL HEADER, with the
16*5206Sis  * fields enclosed by brackets "[]" replaced with your own identifying
17*5206Sis  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5206Sis  *
19*5206Sis  * CDDL HEADER END
20*5206Sis  */
21*5206Sis /*
22*5206Sis  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5206Sis  * Use is subject to license terms.
24*5206Sis  */
25*5206Sis 
26*5206Sis #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5206Sis 
28*5206Sis /*
29*5206Sis  * Kernel iconv code conversion functions (PSARC/2007/173).
30*5206Sis  *
31*5206Sis  * Man pages: kiconv_open(9F), kiconv(9F), kiconv_close(9F), and kiconvstr(9F).
32*5206Sis  * Interface stability: Committed.
33*5206Sis  */
34*5206Sis 
35*5206Sis #include <sys/types.h>
36*5206Sis #include <sys/param.h>
37*5206Sis #include <sys/sysmacros.h>
38*5206Sis #include <sys/systm.h>
39*5206Sis #include <sys/debug.h>
40*5206Sis #include <sys/kmem.h>
41*5206Sis #include <sys/sunddi.h>
42*5206Sis #include <sys/ksynch.h>
43*5206Sis #include <sys/modctl.h>
44*5206Sis #include <sys/byteorder.h>
45*5206Sis #include <sys/errno.h>
46*5206Sis #include <sys/kiconv.h>
47*5206Sis #include <sys/kiconv_latin1.h>
48*5206Sis 
49*5206Sis 
50*5206Sis /*
51*5206Sis  * The following macros indicate ids to the correct code conversion mapping
52*5206Sis  * data tables to use. The actual tables are coming from <sys/kiconv_latin1.h>.
53*5206Sis  */
54*5206Sis #define	KICONV_TBLID_1252		(0x00)
55*5206Sis #define	KICONV_TBLID_8859_1		(0x01)
56*5206Sis #define	KICONV_TBLID_8859_15		(0x02)
57*5206Sis #define	KICONV_TBLID_850		(0x03)
58*5206Sis 
59*5206Sis #define	KICONV_MAX_MAPPING_TBLID	(0x03)
60*5206Sis 
61*5206Sis /*
62*5206Sis  * The following tables are coming from u8_textprep.c. We use them to
63*5206Sis  * check on validity of UTF-8 characters and their bytes.
64*5206Sis  */
65*5206Sis extern const int8_t u8_number_of_bytes[];
66*5206Sis extern const uint8_t u8_valid_min_2nd_byte[];
67*5206Sis extern const uint8_t u8_valid_max_2nd_byte[];
68*5206Sis 
69*5206Sis 
70*5206Sis /*
71*5206Sis  * The following four functions, open_to_1252(), open_to_88591(),
72*5206Sis  * open_to_885915(), and open_to_850(), are kiconv_open functions from
73*5206Sis  * UTF-8 to corresponding single byte codesets.
74*5206Sis  */
75*5206Sis static void *
open_to_1252()76*5206Sis open_to_1252()
77*5206Sis {
78*5206Sis 	kiconv_state_t s;
79*5206Sis 
80*5206Sis 	s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
81*5206Sis 	s->id = KICONV_TBLID_1252;
82*5206Sis 	s->bom_processed = 0;
83*5206Sis 
84*5206Sis 	return ((void *)s);
85*5206Sis }
86*5206Sis 
87*5206Sis static void *
open_to_88591()88*5206Sis open_to_88591()
89*5206Sis {
90*5206Sis 	kiconv_state_t s;
91*5206Sis 
92*5206Sis 	s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
93*5206Sis 	s->id = KICONV_TBLID_8859_1;
94*5206Sis 	s->bom_processed = 0;
95*5206Sis 
96*5206Sis 	return ((void *)s);
97*5206Sis }
98*5206Sis 
99*5206Sis static void *
open_to_885915()100*5206Sis open_to_885915()
101*5206Sis {
102*5206Sis 	kiconv_state_t s;
103*5206Sis 
104*5206Sis 	s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
105*5206Sis 	s->id = KICONV_TBLID_8859_15;
106*5206Sis 	s->bom_processed = 0;
107*5206Sis 
108*5206Sis 	return ((void *)s);
109*5206Sis }
110*5206Sis 
111*5206Sis static void *
open_to_850()112*5206Sis open_to_850()
113*5206Sis {
114*5206Sis 	kiconv_state_t s;
115*5206Sis 
116*5206Sis 	s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
117*5206Sis 	s->id = KICONV_TBLID_850;
118*5206Sis 	s->bom_processed = 0;
119*5206Sis 
120*5206Sis 	return ((void *)s);
121*5206Sis }
122*5206Sis 
123*5206Sis /*
124*5206Sis  * The following four functions, open_fr_1252(), open_fr_88591(),
125*5206Sis  * open_fr_885915(), and open_fr_850(), are kiconv_open functions from
126*5206Sis  * corresponding single byte codesets to UTF-8.
127*5206Sis  */
128*5206Sis static void *
open_fr_1252()129*5206Sis open_fr_1252()
130*5206Sis {
131*5206Sis 	return ((void *)KICONV_TBLID_1252);
132*5206Sis }
133*5206Sis 
134*5206Sis static void *
open_fr_88591()135*5206Sis open_fr_88591()
136*5206Sis {
137*5206Sis 	return ((void *)KICONV_TBLID_8859_1);
138*5206Sis }
139*5206Sis 
140*5206Sis static void *
open_fr_885915()141*5206Sis open_fr_885915()
142*5206Sis {
143*5206Sis 	return ((void *)KICONV_TBLID_8859_15);
144*5206Sis }
145*5206Sis 
146*5206Sis static void *
open_fr_850()147*5206Sis open_fr_850()
148*5206Sis {
149*5206Sis 	return ((void *)KICONV_TBLID_850);
150*5206Sis }
151*5206Sis 
152*5206Sis /*
153*5206Sis  * The following close_to_sb() function is kiconv_close function for
154*5206Sis  * the conversions from UTF-8 to single byte codesets. The close_fr_sb()
155*5206Sis  * is kiconv_close function for the conversions from single byte codesets to
156*5206Sis  * UTF-8.
157*5206Sis  */
158*5206Sis static int
close_to_sb(void * s)159*5206Sis close_to_sb(void *s)
160*5206Sis {
161*5206Sis 	if (! s || s == (void *)-1)
162*5206Sis 		return (EBADF);
163*5206Sis 
164*5206Sis 	kmem_free(s, sizeof (kiconv_state_data_t));
165*5206Sis 
166*5206Sis 	return (0);
167*5206Sis }
168*5206Sis 
169*5206Sis static int
close_fr_sb(void * s)170*5206Sis close_fr_sb(void *s)
171*5206Sis {
172*5206Sis 	if ((ulong_t)s > KICONV_MAX_MAPPING_TBLID)
173*5206Sis 		return (EBADF);
174*5206Sis 
175*5206Sis 	return (0);
176*5206Sis }
177*5206Sis 
178*5206Sis /*
179*5206Sis  * The following is the common kiconv function for conversions from UTF-8
180*5206Sis  * to single byte codesets.
181*5206Sis  */
182*5206Sis static size_t
kiconv_to_sb(void * kcd,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft,int * errno)183*5206Sis kiconv_to_sb(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf,
184*5206Sis 	size_t *outbytesleft, int *errno)
185*5206Sis {
186*5206Sis 	size_t id;
187*5206Sis 	size_t ret_val;
188*5206Sis 	uchar_t *ib;
189*5206Sis 	uchar_t *oldib;
190*5206Sis 	uchar_t *ob;
191*5206Sis 	uchar_t *ibtail;
192*5206Sis 	uchar_t *obtail;
193*5206Sis 	uint32_t u8;
194*5206Sis 	size_t i;
195*5206Sis 	size_t l;
196*5206Sis 	size_t h;
197*5206Sis 	size_t init_h;
198*5206Sis 	int8_t sz;
199*5206Sis 	boolean_t second;
200*5206Sis 
201*5206Sis 	/* Check on the kiconv code conversion descriptor. */
202*5206Sis 	if (! kcd || kcd == (void *)-1) {
203*5206Sis 		*errno = EBADF;
204*5206Sis 		return ((size_t)-1);
205*5206Sis 	}
206*5206Sis 
207*5206Sis 	/*
208*5206Sis 	 * Get the table id we are going to use for the code conversion
209*5206Sis 	 * and let's double check on it.
210*5206Sis 	 */
211*5206Sis 	id = ((kiconv_state_t)kcd)->id;
212*5206Sis 	if (id > KICONV_MAX_MAPPING_TBLID) {
213*5206Sis 		*errno = EBADF;
214*5206Sis 		return ((size_t)-1);
215*5206Sis 	}
216*5206Sis 
217*5206Sis 	/* If this is a state reset request, process and return. */
218*5206Sis 	if (! inbuf || ! (*inbuf)) {
219*5206Sis 		((kiconv_state_t)kcd)->bom_processed = 0;
220*5206Sis 		return ((size_t)0);
221*5206Sis 	}
222*5206Sis 
223*5206Sis 	ret_val = 0;
224*5206Sis 	ib = (uchar_t *)*inbuf;
225*5206Sis 	ob = (uchar_t *)*outbuf;
226*5206Sis 	ibtail = ib + *inbytesleft;
227*5206Sis 	obtail = ob + *outbytesleft;
228*5206Sis 
229*5206Sis 	/*
230*5206Sis 	 * The inital high value for the binary search we will be using
231*5206Sis 	 * shortly is a literal constant as of today but to be future proof,
232*5206Sis 	 * let's calculate it like the following at here.
233*5206Sis 	 */
234*5206Sis 	init_h = sizeof (to_sb_tbl[id]) / sizeof (kiconv_to_sb_tbl_comp_t) - 1;
235*5206Sis 
236*5206Sis 	/*
237*5206Sis 	 * If we haven't checked on the UTF-8 signature BOM character in
238*5206Sis 	 * the beginning of the conversion data stream, we check it and if
239*5206Sis 	 * find one, we skip it since we have no use for it.
240*5206Sis 	 */
241*5206Sis 	if (((kiconv_state_t)kcd)->bom_processed == 0 && (ibtail - ib) >= 3 &&
242*5206Sis 	    *ib == 0xef && *(ib + 1) == 0xbb && *(ib + 2) == 0xbf)
243*5206Sis 			ib += 3;
244*5206Sis 	((kiconv_state_t)kcd)->bom_processed = 1;
245*5206Sis 
246*5206Sis 	while (ib < ibtail) {
247*5206Sis 		sz = u8_number_of_bytes[*ib];
248*5206Sis 		if (sz <= 0) {
249*5206Sis 			*errno = EILSEQ;
250*5206Sis 			ret_val = (size_t)-1;
251*5206Sis 			break;
252*5206Sis 		}
253*5206Sis 
254*5206Sis 		/*
255*5206Sis 		 * If there is no room to write at the output buffer,
256*5206Sis 		 * issue E2BIG error.
257*5206Sis 		 */
258*5206Sis 		if (ob >= obtail) {
259*5206Sis 			*errno = E2BIG;
260*5206Sis 			ret_val = (size_t)-1;
261*5206Sis 			break;
262*5206Sis 		}
263*5206Sis 
264*5206Sis 		/*
265*5206Sis 		 * If it is a 7-bit ASCII character, we don't need to
266*5206Sis 		 * process further and we just copy the character over.
267*5206Sis 		 *
268*5206Sis 		 * If not, we collect the character bytes up to four bytes,
269*5206Sis 		 * validate the bytes, and binary search for the corresponding
270*5206Sis 		 * single byte codeset character byte. If we find it from
271*5206Sis 		 * the mapping table, we put that into the output buffer;
272*5206Sis 		 * otherwise, we put a replacement character instead as
273*5206Sis 		 * a non-identical conversion.
274*5206Sis 		 */
275*5206Sis 		if (sz == 1) {
276*5206Sis 			*ob++ = *ib++;
277*5206Sis 			continue;
278*5206Sis 		}
279*5206Sis 
280*5206Sis 		/*
281*5206Sis 		 * Issue EINVAL error if input buffer has an incomplete
282*5206Sis 		 * character at the end of the buffer.
283*5206Sis 		 */
284*5206Sis 		if ((ibtail - ib) < sz) {
285*5206Sis 			*errno = EINVAL;
286*5206Sis 			ret_val = (size_t)-1;
287*5206Sis 			break;
288*5206Sis 		}
289*5206Sis 
290*5206Sis 		/*
291*5206Sis 		 * We collect UTF-8 character bytes and also check if
292*5206Sis 		 * this is a valid UTF-8 character without any bogus bytes
293*5206Sis 		 * based on the latest UTF-8 binary representation.
294*5206Sis 		 */
295*5206Sis 		oldib = ib;
296*5206Sis 		u8 = *ib++;
297*5206Sis 		second = B_TRUE;
298*5206Sis 		for (i = 1; i < sz; i++) {
299*5206Sis 			if (second) {
300*5206Sis 				if (*ib < u8_valid_min_2nd_byte[u8] ||
301*5206Sis 				    *ib > u8_valid_max_2nd_byte[u8]) {
302*5206Sis 					*errno = EILSEQ;
303*5206Sis 					ret_val = (size_t)-1;
304*5206Sis 					ib = oldib;
305*5206Sis 					goto TO_SB_ILLEGAL_CHAR_ERR;
306*5206Sis 				}
307*5206Sis 				second = B_FALSE;
308*5206Sis 			} else if (*ib < 0x80 || *ib > 0xbf) {
309*5206Sis 				*errno = EILSEQ;
310*5206Sis 				ret_val = (size_t)-1;
311*5206Sis 				ib = oldib;
312*5206Sis 				goto TO_SB_ILLEGAL_CHAR_ERR;
313*5206Sis 			}
314*5206Sis 			u8 = (u8 << 8) | ((uint32_t)*ib);
315*5206Sis 			ib++;
316*5206Sis 		}
317*5206Sis 
318*5206Sis 		i = l = 0;
319*5206Sis 		h = init_h;
320*5206Sis 		while (l <= h) {
321*5206Sis 			i = (l + h) / 2;
322*5206Sis 			if (to_sb_tbl[id][i].u8 == u8)
323*5206Sis 				break;
324*5206Sis 			else if (to_sb_tbl[id][i].u8 < u8)
325*5206Sis 				l = i + 1;
326*5206Sis 			else
327*5206Sis 				h = i - 1;
328*5206Sis 		}
329*5206Sis 
330*5206Sis 		if (to_sb_tbl[id][i].u8 == u8) {
331*5206Sis 			*ob++ = to_sb_tbl[id][i].sb;
332*5206Sis 		} else {
333*5206Sis 			/*
334*5206Sis 			 * If we don't find a character in the target
335*5206Sis 			 * codeset, we insert an ASCII replacement character
336*5206Sis 			 * at the output buffer and indicate such
337*5206Sis 			 * "non-identical" conversion by increasing the
338*5206Sis 			 * return value which is the non-identical conversion
339*5206Sis 			 * counter if bigger than 0.
340*5206Sis 			 */
341*5206Sis 			*ob++ = KICONV_ASCII_REPLACEMENT_CHAR;
342*5206Sis 			ret_val++;
343*5206Sis 		}
344*5206Sis 	}
345*5206Sis 
346*5206Sis TO_SB_ILLEGAL_CHAR_ERR:
347*5206Sis 	*inbuf = (char *)ib;
348*5206Sis 	*inbytesleft = ibtail - ib;
349*5206Sis 	*outbuf = (char *)ob;
350*5206Sis 	*outbytesleft = obtail - ob;
351*5206Sis 
352*5206Sis 	return (ret_val);
353*5206Sis }
354*5206Sis 
355*5206Sis /*
356*5206Sis  * The following is the common kiconv function from single byte codesets to
357*5206Sis  * UTF-8.
358*5206Sis  */
359*5206Sis static size_t
kiconv_fr_sb(void * kcd,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft,int * errno)360*5206Sis kiconv_fr_sb(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf,
361*5206Sis 	size_t *outbytesleft, int *errno)
362*5206Sis {
363*5206Sis 	size_t ret_val;
364*5206Sis 	uchar_t *ib;
365*5206Sis 	uchar_t *ob;
366*5206Sis 	uchar_t *ibtail;
367*5206Sis 	uchar_t *obtail;
368*5206Sis 	size_t i;
369*5206Sis 	size_t k;
370*5206Sis 	int8_t sz;
371*5206Sis 
372*5206Sis 	/* Check on the kiconv code conversion descriptor validity. */
373*5206Sis 	if ((ulong_t)kcd > KICONV_MAX_MAPPING_TBLID) {
374*5206Sis 		*errno = EBADF;
375*5206Sis 		return ((size_t)-1);
376*5206Sis 	}
377*5206Sis 
378*5206Sis 	/*
379*5206Sis 	 * If this is a state reset request, there is nothing to do and so
380*5206Sis 	 * we just return.
381*5206Sis 	 */
382*5206Sis 	if (! inbuf || ! (*inbuf))
383*5206Sis 		return ((size_t)0);
384*5206Sis 
385*5206Sis 	ret_val = 0;
386*5206Sis 	ib = (uchar_t *)*inbuf;
387*5206Sis 	ob = (uchar_t *)*outbuf;
388*5206Sis 	ibtail = ib + *inbytesleft;
389*5206Sis 	obtail = ob + *outbytesleft;
390*5206Sis 
391*5206Sis 	while (ib < ibtail) {
392*5206Sis 		/*
393*5206Sis 		 * If this is a 7-bit ASCII character, we just copy over and
394*5206Sis 		 * that's all we need to do for this character.
395*5206Sis 		 */
396*5206Sis 		if (*ib < 0x80) {
397*5206Sis 			if (ob >= obtail) {
398*5206Sis 				*errno = E2BIG;
399*5206Sis 				ret_val = (size_t)-1;
400*5206Sis 				break;
401*5206Sis 			}
402*5206Sis 
403*5206Sis 			*ob++ = *ib++;
404*5206Sis 			continue;
405*5206Sis 		}
406*5206Sis 
407*5206Sis 		/*
408*5206Sis 		 * Otherwise, we get the corresponding UTF-8 character bytes
409*5206Sis 		 * from the mapping table and copy them over.
410*5206Sis 		 *
411*5206Sis 		 * We don't need to worry about if the UTF-8 character bytes
412*5206Sis 		 * at the mapping tables are valid or not since they are good.
413*5206Sis 		 */
414*5206Sis 		k = *ib - 0x80;
415*5206Sis 		sz = u8_number_of_bytes[to_u8_tbl[(ulong_t)kcd][k].u8[0]];
416*5206Sis 
417*5206Sis 		/*
418*5206Sis 		 * If sz <= 0, that means we don't have any assigned character
419*5206Sis 		 * at the code point, k + 0x80, of the single byte codeset
420*5206Sis 		 * which is the fromcode. In other words, the input buffer
421*5206Sis 		 * has an illegal character.
422*5206Sis 		 */
423*5206Sis 		if (sz <= 0) {
424*5206Sis 			*errno = EILSEQ;
425*5206Sis 			ret_val = (size_t)-1;
426*5206Sis 			break;
427*5206Sis 		}
428*5206Sis 
429*5206Sis 		if ((obtail - ob) < sz) {
430*5206Sis 			*errno = E2BIG;
431*5206Sis 			ret_val = (size_t)-1;
432*5206Sis 			break;
433*5206Sis 		}
434*5206Sis 
435*5206Sis 		for (i = 0; i < sz; i++)
436*5206Sis 			*ob++ = to_u8_tbl[(ulong_t)kcd][k].u8[i];
437*5206Sis 
438*5206Sis 		ib++;
439*5206Sis 	}
440*5206Sis 
441*5206Sis 	*inbuf = (char *)ib;
442*5206Sis 	*inbytesleft = ibtail - ib;
443*5206Sis 	*outbuf = (char *)ob;
444*5206Sis 	*outbytesleft = obtail - ob;
445*5206Sis 
446*5206Sis 	return (ret_val);
447*5206Sis }
448*5206Sis 
449*5206Sis /*
450*5206Sis  * The following is the common kiconvstr function from UTF-8 to single byte
451*5206Sis  * codesets.
452*5206Sis  */
453*5206Sis static size_t
kiconvstr_to_sb(size_t id,uchar_t * ib,size_t * inlen,uchar_t * ob,size_t * outlen,int flag,int * errno)454*5206Sis kiconvstr_to_sb(size_t id, uchar_t *ib, size_t *inlen, uchar_t *ob,
455*5206Sis 	size_t *outlen, int flag, int *errno)
456*5206Sis {
457*5206Sis 	size_t ret_val;
458*5206Sis 	uchar_t *oldib;
459*5206Sis 	uchar_t *ibtail;
460*5206Sis 	uchar_t *obtail;
461*5206Sis 	uint32_t u8;
462*5206Sis 	size_t i;
463*5206Sis 	size_t l;
464*5206Sis 	size_t h;
465*5206Sis 	size_t init_h;
466*5206Sis 	int8_t sz;
467*5206Sis 	boolean_t second;
468*5206Sis 	boolean_t do_not_ignore_null;
469*5206Sis 
470*5206Sis 	/* Let's make sure that the table id is within the valid boundary. */
471*5206Sis 	if (id > KICONV_MAX_MAPPING_TBLID) {
472*5206Sis 		*errno = EBADF;
473*5206Sis 		return ((size_t)-1);
474*5206Sis 	}
475*5206Sis 
476*5206Sis 	ret_val = 0;
477*5206Sis 	ibtail = ib + *inlen;
478*5206Sis 	obtail = ob + *outlen;
479*5206Sis 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
480*5206Sis 	init_h = sizeof (to_sb_tbl[id]) / sizeof (kiconv_to_sb_tbl_comp_t) - 1;
481*5206Sis 
482*5206Sis 	/* Skip any UTF-8 signature BOM character in the beginning. */
483*5206Sis 	if ((ibtail - ib) >= 3 && *ib == 0xef && *(ib + 1) == 0xbb &&
484*5206Sis 	    *(ib + 2) == 0xbf)
485*5206Sis 			ib += 3;
486*5206Sis 
487*5206Sis 	/*
488*5206Sis 	 * Basically this is pretty much the same as kiconv_to_sb() except
489*5206Sis 	 * that we are now accepting two flag values and doing the processing
490*5206Sis 	 * accordingly.
491*5206Sis 	 */
492*5206Sis 	while (ib < ibtail) {
493*5206Sis 		sz = u8_number_of_bytes[*ib];
494*5206Sis 		if (sz <= 0) {
495*5206Sis 			if (flag & KICONV_REPLACE_INVALID) {
496*5206Sis 				if (ob >= obtail) {
497*5206Sis 					*errno = E2BIG;
498*5206Sis 					ret_val = (size_t)-1;
499*5206Sis 					break;
500*5206Sis 				}
501*5206Sis 
502*5206Sis 				ib++;
503*5206Sis 				goto STR_TO_SB_REPLACE_INVALID;
504*5206Sis 			}
505*5206Sis 
506*5206Sis 			*errno = EILSEQ;
507*5206Sis 			ret_val = (size_t)-1;
508*5206Sis 			break;
509*5206Sis 		}
510*5206Sis 
511*5206Sis 		if (*ib == '\0' && do_not_ignore_null)
512*5206Sis 			break;
513*5206Sis 
514*5206Sis 		if (ob >= obtail) {
515*5206Sis 			*errno = E2BIG;
516*5206Sis 			ret_val = (size_t)-1;
517*5206Sis 			break;
518*5206Sis 		}
519*5206Sis 
520*5206Sis 		if (sz == 1) {
521*5206Sis 			*ob++ = *ib++;
522*5206Sis 			continue;
523*5206Sis 		}
524*5206Sis 
525*5206Sis 		if ((ibtail - ib) < sz) {
526*5206Sis 			if (flag & KICONV_REPLACE_INVALID) {
527*5206Sis 				ib = ibtail;
528*5206Sis 				goto STR_TO_SB_REPLACE_INVALID;
529*5206Sis 			}
530*5206Sis 
531*5206Sis 			*errno = EINVAL;
532*5206Sis 			ret_val = (size_t)-1;
533*5206Sis 			break;
534*5206Sis 		}
535*5206Sis 
536*5206Sis 		oldib = ib;
537*5206Sis 		u8 = *ib++;
538*5206Sis 		second = B_TRUE;
539*5206Sis 		for (i = 1; i < sz; i++) {
540*5206Sis 			if (second) {
541*5206Sis 				if (*ib < u8_valid_min_2nd_byte[u8] ||
542*5206Sis 				    *ib > u8_valid_max_2nd_byte[u8]) {
543*5206Sis 					if (flag & KICONV_REPLACE_INVALID) {
544*5206Sis 						ib = oldib + sz;
545*5206Sis 						goto STR_TO_SB_REPLACE_INVALID;
546*5206Sis 					}
547*5206Sis 
548*5206Sis 					*errno = EILSEQ;
549*5206Sis 					ret_val = (size_t)-1;
550*5206Sis 					ib = oldib;
551*5206Sis 					goto STR_TO_SB_ILLEGAL_CHAR_ERR;
552*5206Sis 				}
553*5206Sis 				second = B_FALSE;
554*5206Sis 			} else if (*ib < 0x80 || *ib > 0xbf) {
555*5206Sis 				if (flag & KICONV_REPLACE_INVALID) {
556*5206Sis 					ib = oldib + sz;
557*5206Sis 					goto STR_TO_SB_REPLACE_INVALID;
558*5206Sis 				}
559*5206Sis 
560*5206Sis 				*errno = EILSEQ;
561*5206Sis 				ret_val = (size_t)-1;
562*5206Sis 				ib = oldib;
563*5206Sis 				goto STR_TO_SB_ILLEGAL_CHAR_ERR;
564*5206Sis 			}
565*5206Sis 			u8 = (u8 << 8) | ((uint32_t)*ib);
566*5206Sis 			ib++;
567*5206Sis 		}
568*5206Sis 
569*5206Sis 		i = l = 0;
570*5206Sis 		h = init_h;
571*5206Sis 		while (l <= h) {
572*5206Sis 			i = (l + h) / 2;
573*5206Sis 			if (to_sb_tbl[id][i].u8 == u8)
574*5206Sis 				break;
575*5206Sis 			else if (to_sb_tbl[id][i].u8 < u8)
576*5206Sis 				l = i + 1;
577*5206Sis 			else
578*5206Sis 				h = i - 1;
579*5206Sis 		}
580*5206Sis 
581*5206Sis 		if (to_sb_tbl[id][i].u8 == u8) {
582*5206Sis 			*ob++ = to_sb_tbl[id][i].sb;
583*5206Sis 		} else {
584*5206Sis STR_TO_SB_REPLACE_INVALID:
585*5206Sis 			*ob++ = KICONV_ASCII_REPLACEMENT_CHAR;
586*5206Sis 			ret_val++;
587*5206Sis 		}
588*5206Sis 	}
589*5206Sis 
590*5206Sis STR_TO_SB_ILLEGAL_CHAR_ERR:
591*5206Sis 	*inlen = ibtail - ib;
592*5206Sis 	*outlen = obtail - ob;
593*5206Sis 
594*5206Sis 	return (ret_val);
595*5206Sis }
596*5206Sis 
597*5206Sis /*
598*5206Sis  * The following four functions are entry points recorded at the conv_list[]
599*5206Sis  * defined at below.
600*5206Sis  */
601*5206Sis static size_t
kiconvstr_to_1252(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)602*5206Sis kiconvstr_to_1252(char *inarray, size_t *inlen, char *outarray,
603*5206Sis 	size_t *outlen, int flag, int *errno)
604*5206Sis {
605*5206Sis 	return (kiconvstr_to_sb(KICONV_TBLID_1252, (uchar_t *)inarray,
606*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
607*5206Sis }
608*5206Sis 
609*5206Sis static size_t
kiconvstr_to_1(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)610*5206Sis kiconvstr_to_1(char *inarray, size_t *inlen, char *outarray,
611*5206Sis 	size_t *outlen, int flag, int *errno)
612*5206Sis {
613*5206Sis 	return (kiconvstr_to_sb(KICONV_TBLID_8859_1, (uchar_t *)inarray,
614*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
615*5206Sis }
616*5206Sis 
617*5206Sis static size_t
kiconvstr_to_15(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)618*5206Sis kiconvstr_to_15(char *inarray, size_t *inlen, char *outarray,
619*5206Sis 	size_t *outlen, int flag, int *errno)
620*5206Sis {
621*5206Sis 	return (kiconvstr_to_sb(KICONV_TBLID_8859_15, (uchar_t *)inarray,
622*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
623*5206Sis }
624*5206Sis 
625*5206Sis static size_t
kiconvstr_to_850(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)626*5206Sis kiconvstr_to_850(char *inarray, size_t *inlen, char *outarray,
627*5206Sis 	size_t *outlen, int flag, int *errno)
628*5206Sis {
629*5206Sis 	return (kiconvstr_to_sb(KICONV_TBLID_850, (uchar_t *)inarray,
630*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
631*5206Sis }
632*5206Sis 
633*5206Sis /*
634*5206Sis  * The following is the common kiconvstr function for conversions from
635*5206Sis  * single byte codesets to UTF-8.
636*5206Sis  */
637*5206Sis static size_t
kiconvstr_fr_sb(size_t id,uchar_t * ib,size_t * inlen,uchar_t * ob,size_t * outlen,int flag,int * errno)638*5206Sis kiconvstr_fr_sb(size_t id, uchar_t *ib, size_t *inlen, uchar_t *ob,
639*5206Sis 	size_t *outlen, int flag, int *errno)
640*5206Sis {
641*5206Sis 	size_t ret_val;
642*5206Sis 	uchar_t *ibtail;
643*5206Sis 	uchar_t *obtail;
644*5206Sis 	size_t i;
645*5206Sis 	size_t k;
646*5206Sis 	int8_t sz;
647*5206Sis 	boolean_t do_not_ignore_null;
648*5206Sis 
649*5206Sis 	ret_val = 0;
650*5206Sis 	ibtail = ib + *inlen;
651*5206Sis 	obtail = ob + *outlen;
652*5206Sis 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
653*5206Sis 
654*5206Sis 	while (ib < ibtail) {
655*5206Sis 		if (*ib == '\0' && do_not_ignore_null)
656*5206Sis 			break;
657*5206Sis 
658*5206Sis 		if (*ib < 0x80) {
659*5206Sis 			if (ob >= obtail) {
660*5206Sis 				*errno = E2BIG;
661*5206Sis 				ret_val = (size_t)-1;
662*5206Sis 				break;
663*5206Sis 			}
664*5206Sis 			*ob++ = *ib++;
665*5206Sis 			continue;
666*5206Sis 		}
667*5206Sis 
668*5206Sis 		k = *ib - 0x80;
669*5206Sis 		sz = u8_number_of_bytes[to_u8_tbl[id][k].u8[0]];
670*5206Sis 
671*5206Sis 		if (sz <= 0) {
672*5206Sis 			if (flag & KICONV_REPLACE_INVALID) {
673*5206Sis 				if ((obtail - ob) < 3) {
674*5206Sis 					*errno = E2BIG;
675*5206Sis 					ret_val = (size_t)-1;
676*5206Sis 					break;
677*5206Sis 				}
678*5206Sis 
679*5206Sis 				/* Save KICONV_UTF8_REPLACEMENT_CHAR. */
680*5206Sis 				*ob++ = 0xef;
681*5206Sis 				*ob++ = 0xbf;
682*5206Sis 				*ob++ = 0xbd;
683*5206Sis 				ret_val++;
684*5206Sis 				ib++;
685*5206Sis 
686*5206Sis 				continue;
687*5206Sis 			}
688*5206Sis 
689*5206Sis 			*errno = EILSEQ;
690*5206Sis 			ret_val = (size_t)-1;
691*5206Sis 			break;
692*5206Sis 		}
693*5206Sis 
694*5206Sis 		if ((obtail - ob) < sz) {
695*5206Sis 			*errno = E2BIG;
696*5206Sis 			ret_val = (size_t)-1;
697*5206Sis 			break;
698*5206Sis 		}
699*5206Sis 
700*5206Sis 		for (i = 0; i < sz; i++)
701*5206Sis 			*ob++ = to_u8_tbl[id][k].u8[i];
702*5206Sis 
703*5206Sis 		ib++;
704*5206Sis 	}
705*5206Sis 
706*5206Sis 	*inlen = ibtail - ib;
707*5206Sis 	*outlen = obtail - ob;
708*5206Sis 
709*5206Sis 	return (ret_val);
710*5206Sis }
711*5206Sis 
712*5206Sis /*
713*5206Sis  * The following four functions are also entry points recorded at
714*5206Sis  * the conv_list[] at below.
715*5206Sis  */
716*5206Sis static size_t
kiconvstr_fr_1252(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)717*5206Sis kiconvstr_fr_1252(char *inarray, size_t *inlen, char *outarray,
718*5206Sis 	size_t *outlen, int flag, int *errno)
719*5206Sis {
720*5206Sis 	return (kiconvstr_fr_sb(KICONV_TBLID_1252, (uchar_t *)inarray,
721*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
722*5206Sis }
723*5206Sis 
724*5206Sis static size_t
kiconvstr_fr_1(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)725*5206Sis kiconvstr_fr_1(char *inarray, size_t *inlen, char *outarray,
726*5206Sis 	size_t *outlen, int flag, int *errno)
727*5206Sis {
728*5206Sis 	return (kiconvstr_fr_sb(KICONV_TBLID_8859_1, (uchar_t *)inarray,
729*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
730*5206Sis }
731*5206Sis 
732*5206Sis static size_t
kiconvstr_fr_15(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)733*5206Sis kiconvstr_fr_15(char *inarray, size_t *inlen, char *outarray,
734*5206Sis 	size_t *outlen, int flag, int *errno)
735*5206Sis {
736*5206Sis 	return (kiconvstr_fr_sb(KICONV_TBLID_8859_15, (uchar_t *)inarray,
737*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
738*5206Sis }
739*5206Sis 
740*5206Sis static size_t
kiconvstr_fr_850(char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)741*5206Sis kiconvstr_fr_850(char *inarray, size_t *inlen, char *outarray,
742*5206Sis 	size_t *outlen, int flag, int *errno)
743*5206Sis {
744*5206Sis 	return (kiconvstr_fr_sb(KICONV_TBLID_850, (uchar_t *)inarray,
745*5206Sis 	    inlen, (uchar_t *)outarray, outlen, flag, errno));
746*5206Sis }
747*5206Sis 
748*5206Sis /*
749*5206Sis  * The following static vector contains the normalized code names
750*5206Sis  * and their corresponding code ids. They are somewhat arbitrarily ordered
751*5206Sis  * based on marketing data available. A code id could repeat for aliases.
752*5206Sis  *
753*5206Sis  * The vector was generated by using a small utility program called
754*5206Sis  * codeidlistgen.c that you can find from PSARC/2007/173/materials/util/.
755*5206Sis  *
756*5206Sis  * The code ids must be portable, i.e., if needed, you can always generate
757*5206Sis  * the code_list[] again with different code ids. You'll also need to
758*5206Sis  * update the conv_list[] at below.
759*5206Sis  */
760*5206Sis #define	KICONV_MAX_CODEID_ENTRY		68
761*5206Sis #define	KICONV_MAX_CODEID		42
762*5206Sis 
763*5206Sis static kiconv_code_list_t code_list[KICONV_MAX_CODEID_ENTRY] = {
764*5206Sis 	{ "utf8", 0 },
765*5206Sis 	{ "cp1252", 1 },
766*5206Sis 	{ "1252", 1 },
767*5206Sis 	{ "iso88591", 2 },
768*5206Sis 	{ "iso885915", 3 },
769*5206Sis 	{ "cp850", 4 },
770*5206Sis 	{ "850", 4 },
771*5206Sis 	{ "eucjp", 5 },
772*5206Sis 	{ "eucjpms", 6 },
773*5206Sis 	{ "cp932", 7 },
774*5206Sis 	{ "932", 7 },
775*5206Sis 	{ "shiftjis", 8 },
776*5206Sis 	{ "pck", 8 },
777*5206Sis 	{ "sjis", 8 },
778*5206Sis 	{ "gb18030", 9 },
779*5206Sis 	{ "gbk", 10 },
780*5206Sis 	{ "cp936", 10 },
781*5206Sis 	{ "936", 10 },
782*5206Sis 	{ "euccn", 11 },
783*5206Sis 	{ "euckr", 12 },
784*5206Sis 	{ "unifiedhangul", 13 },
785*5206Sis 	{ "cp949", 13 },
786*5206Sis 	{ "949", 13 },
787*5206Sis 	{ "big5", 14 },
788*5206Sis 	{ "cp950", 14 },
789*5206Sis 	{ "950", 14 },
790*5206Sis 	{ "big5hkscs", 15 },
791*5206Sis 	{ "euctw", 16 },
792*5206Sis 	{ "cp950hkscs", 17 },
793*5206Sis 	{ "cp1250", 18 },
794*5206Sis 	{ "1250", 18 },
795*5206Sis 	{ "iso88592", 19 },
796*5206Sis 	{ "cp852", 20 },
797*5206Sis 	{ "852", 20 },
798*5206Sis 	{ "cp1251", 21 },
799*5206Sis 	{ "1251", 21 },
800*5206Sis 	{ "iso88595", 22 },
801*5206Sis 	{ "koi8r", 23 },
802*5206Sis 	{ "cp866", 24 },
803*5206Sis 	{ "866", 24 },
804*5206Sis 	{ "cp1253", 25 },
805*5206Sis 	{ "1253", 25 },
806*5206Sis 	{ "iso88597", 26 },
807*5206Sis 	{ "cp737", 27 },
808*5206Sis 	{ "737", 27 },
809*5206Sis 	{ "cp1254", 28 },
810*5206Sis 	{ "1254", 28 },
811*5206Sis 	{ "iso88599", 29 },
812*5206Sis 	{ "cp857", 30 },
813*5206Sis 	{ "857", 30 },
814*5206Sis 	{ "cp1256", 31 },
815*5206Sis 	{ "1256", 31 },
816*5206Sis 	{ "iso88596", 32 },
817*5206Sis 	{ "cp720", 33 },
818*5206Sis 	{ "720", 33 },
819*5206Sis 	{ "cp1255", 34 },
820*5206Sis 	{ "1255", 34 },
821*5206Sis 	{ "iso88598", 35 },
822*5206Sis 	{ "cp862", 36 },
823*5206Sis 	{ "862", 36 },
824*5206Sis 	{ "cp1257", 37 },
825*5206Sis 	{ "1257", 37 },
826*5206Sis 	{ "iso885913", 38 },
827*5206Sis 	{ "iso885910", 39 },
828*5206Sis 	{ "iso885911", 40 },
829*5206Sis 	{ "tis620", 40 },
830*5206Sis 	{ "iso88593", 41 },
831*5206Sis 	{ "iso88594", 42 },
832*5206Sis };
833*5206Sis 
834*5206Sis /*
835*5206Sis  * The list of code conversions supported are grouped together per
836*5206Sis  * module which will be loaded as needed.
837*5206Sis  */
838*5206Sis #define	KICONV_MAX_CONVERSIONS		84
839*5206Sis 
840*5206Sis static kiconv_conv_list_t conv_list[KICONV_MAX_CONVERSIONS] = {
841*5206Sis 	/* Embedded code conversions: */
842*5206Sis 	{
843*5206Sis 		1, 0, KICONV_EMBEDDED,
844*5206Sis 		open_to_1252, kiconv_to_sb, close_to_sb, kiconvstr_to_1252
845*5206Sis 	},
846*5206Sis 	{
847*5206Sis 		0, 1, KICONV_EMBEDDED,
848*5206Sis 		open_fr_1252, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_1252
849*5206Sis 	},
850*5206Sis 	{
851*5206Sis 		2, 0, KICONV_EMBEDDED,
852*5206Sis 		open_to_88591, kiconv_to_sb, close_to_sb, kiconvstr_to_1
853*5206Sis 	},
854*5206Sis 	{
855*5206Sis 		0, 2, KICONV_EMBEDDED,
856*5206Sis 		open_fr_88591, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_1
857*5206Sis 	},
858*5206Sis 	{
859*5206Sis 		3, 0, KICONV_EMBEDDED,
860*5206Sis 		open_to_885915, kiconv_to_sb, close_to_sb, kiconvstr_to_15
861*5206Sis 	},
862*5206Sis 	{
863*5206Sis 		0, 3, KICONV_EMBEDDED,
864*5206Sis 		open_fr_885915, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_15
865*5206Sis 	},
866*5206Sis 	{
867*5206Sis 		4, 0, KICONV_EMBEDDED,
868*5206Sis 		open_to_850, kiconv_to_sb, close_to_sb, kiconvstr_to_850
869*5206Sis 	},
870*5206Sis 	{
871*5206Sis 		0, 4, KICONV_EMBEDDED,
872*5206Sis 		open_fr_850, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_850
873*5206Sis 	},
874*5206Sis 
875*5206Sis 	/* kiconv_ja module conversions: */
876*5206Sis 	{ 0, 5, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
877*5206Sis 	{ 5, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
878*5206Sis 	{ 0, 6, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
879*5206Sis 	{ 6, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
880*5206Sis 	{ 0, 7, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
881*5206Sis 	{ 7, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
882*5206Sis 	{ 0, 8, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
883*5206Sis 	{ 8, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
884*5206Sis 
885*5206Sis 	/* kiconv_sc module conversions: */
886*5206Sis 	{ 0, 9, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
887*5206Sis 	{ 9, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
888*5206Sis 	{ 0, 10, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
889*5206Sis 	{ 10, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
890*5206Sis 	{ 0, 11, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
891*5206Sis 	{ 11, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
892*5206Sis 
893*5206Sis 	/* kiconv_ko module conversions: */
894*5206Sis 	{ 0, 12, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
895*5206Sis 	{ 12, 0, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
896*5206Sis 	{ 0, 13, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
897*5206Sis 	{ 13, 0, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
898*5206Sis 
899*5206Sis 	/* kiconv_tc module conversions: */
900*5206Sis 	{ 0, 14, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
901*5206Sis 	{ 14, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
902*5206Sis 	{ 0, 15, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
903*5206Sis 	{ 15, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
904*5206Sis 	{ 0, 16, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
905*5206Sis 	{ 16, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
906*5206Sis 	{ 0, 17, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
907*5206Sis 	{ 17, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
908*5206Sis 
909*5206Sis 	/* kiconv_emea module conversions: */
910*5206Sis 	{ 0, 18, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
911*5206Sis 	{ 18, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
912*5206Sis 	{ 0, 19, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
913*5206Sis 	{ 19, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
914*5206Sis 	{ 0, 20, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
915*5206Sis 	{ 20, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
916*5206Sis 	{ 0, 21, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
917*5206Sis 	{ 21, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
918*5206Sis 	{ 0, 22, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
919*5206Sis 	{ 22, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
920*5206Sis 	{ 0, 23, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
921*5206Sis 	{ 23, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
922*5206Sis 	{ 0, 24, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
923*5206Sis 	{ 24, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
924*5206Sis 	{ 0, 25, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
925*5206Sis 	{ 25, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
926*5206Sis 	{ 0, 26, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
927*5206Sis 	{ 26, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
928*5206Sis 	{ 0, 27, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
929*5206Sis 	{ 27, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
930*5206Sis 	{ 0, 28, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
931*5206Sis 	{ 28, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
932*5206Sis 	{ 0, 29, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
933*5206Sis 	{ 29, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
934*5206Sis 	{ 0, 30, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
935*5206Sis 	{ 30, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
936*5206Sis 	{ 0, 31, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
937*5206Sis 	{ 31, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
938*5206Sis 	{ 0, 32, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
939*5206Sis 	{ 32, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
940*5206Sis 	{ 0, 33, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
941*5206Sis 	{ 33, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
942*5206Sis 	{ 0, 34, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
943*5206Sis 	{ 34, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
944*5206Sis 	{ 0, 35, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
945*5206Sis 	{ 35, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
946*5206Sis 	{ 0, 36, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
947*5206Sis 	{ 36, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
948*5206Sis 	{ 0, 37, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
949*5206Sis 	{ 37, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
950*5206Sis 	{ 0, 38, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
951*5206Sis 	{ 38, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
952*5206Sis 	{ 0, 39, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
953*5206Sis 	{ 39, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
954*5206Sis 	{ 0, 40, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
955*5206Sis 	{ 40, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
956*5206Sis 	{ 0, 41, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
957*5206Sis 	{ 41, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
958*5206Sis 	{ 0, 42, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
959*5206Sis 	{ 42, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
960*5206Sis };
961*5206Sis 
962*5206Sis /* The list of implemeted and supported modules. */
963*5206Sis static kiconv_mod_list_t module_list[KICONV_MAX_MODULE_ID + 1] = {
964*5206Sis 	"kiconv_embedded", 0,
965*5206Sis 	"kiconv_ja", 0,
966*5206Sis 	"kiconv_sc", 0,
967*5206Sis 	"kiconv_ko", 0,
968*5206Sis 	"kiconv_tc", 0,
969*5206Sis 	"kiconv_emea", 0,
970*5206Sis };
971*5206Sis 
972*5206Sis /*
973*5206Sis  * We use conv_list_lock to restrict data access of both conv_list[] and
974*5206Sis  * module_list[] as they are tightly coupled critical sections that need to be
975*5206Sis  * dealt together as a unit.
976*5206Sis  */
977*5206Sis static kmutex_t conv_list_lock;
978*5206Sis 
979*5206Sis void
kiconv_init()980*5206Sis kiconv_init()
981*5206Sis {
982*5206Sis 	mutex_init(&conv_list_lock, NULL, MUTEX_DEFAULT, NULL);
983*5206Sis }
984*5206Sis 
985*5206Sis /*
986*5206Sis  * The following is used to check on whether a kiconv module is being
987*5206Sis  * used or not at the _fini() of the module.
988*5206Sis  */
989*5206Sis size_t
kiconv_module_ref_count(size_t mid)990*5206Sis kiconv_module_ref_count(size_t mid)
991*5206Sis {
992*5206Sis 	int count;
993*5206Sis 
994*5206Sis 	if (mid <= 0 || mid > KICONV_MAX_MODULE_ID)
995*5206Sis 		return (0);
996*5206Sis 
997*5206Sis 	mutex_enter(&conv_list_lock);
998*5206Sis 
999*5206Sis 	count = module_list[mid].refcount;
1000*5206Sis 
1001*5206Sis 	mutex_exit(&conv_list_lock);
1002*5206Sis 
1003*5206Sis 	return (count);
1004*5206Sis }
1005*5206Sis 
1006*5206Sis /*
1007*5206Sis  * This function "normalizes" a given code name, n, by not including skippable
1008*5206Sis  * characters and folding uppercase letters to corresponding lowercase letters.
1009*5206Sis  * We only fold 7-bit ASCII uppercase characters since the names should be in
1010*5206Sis  * Portable Character Set of 7-bit ASCII.
1011*5206Sis  *
1012*5206Sis  * By doing this, we will be able to maximize the code name matches.
1013*5206Sis  */
1014*5206Sis static size_t
normalize_codename(const char * n)1015*5206Sis normalize_codename(const char *n)
1016*5206Sis {
1017*5206Sis 	char s[KICONV_MAX_CODENAME_LEN + 1];
1018*5206Sis 	size_t i;
1019*5206Sis 
1020*5206Sis 	if (n == NULL)
1021*5206Sis 		return ((size_t)-1);
1022*5206Sis 
1023*5206Sis 	for (i = 0; *n; n++) {
1024*5206Sis 		if (KICONV_SKIPPABLE_CHAR(*n))
1025*5206Sis 			continue;
1026*5206Sis 
1027*5206Sis 		/* If unreasonably lengthy, we don't support such names. */
1028*5206Sis 		if (i >= KICONV_MAX_CODENAME_LEN)
1029*5206Sis 			return ((size_t)-1);
1030*5206Sis 
1031*5206Sis 		s[i++] = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
1032*5206Sis 	}
1033*5206Sis 	s[i] = '\0';
1034*5206Sis 
1035*5206Sis 	/* With the normalized name, find the corresponding codeset id. */
1036*5206Sis 	for (i = 0; i < KICONV_MAX_CODEID_ENTRY; i++)
1037*5206Sis 		if (strcmp(s, code_list[i].name) == 0)
1038*5206Sis 			return (code_list[i].id);
1039*5206Sis 
1040*5206Sis 	/*
1041*5206Sis 	 * In future time, we will also have a few more lines of code at below
1042*5206Sis 	 * that will deal with other user-created modules' fromcodes and
1043*5206Sis 	 * tocodes including aliases in a different vector. For now, we don't
1044*5206Sis 	 * support that but only the known names to this project at this time.
1045*5206Sis 	 */
1046*5206Sis 
1047*5206Sis 	return ((size_t)-1);
1048*5206Sis }
1049*5206Sis 
1050*5206Sis /*
1051*5206Sis  * This function called from mod_install() registers supplied code
1052*5206Sis  * conversions. At this point, it does not honor aliases and hence does not
1053*5206Sis  * use nowait data field from the kiconv module info data structure.
1054*5206Sis  */
1055*5206Sis int
kiconv_register_module(kiconv_module_info_t * info)1056*5206Sis kiconv_register_module(kiconv_module_info_t *info)
1057*5206Sis {
1058*5206Sis 	size_t mid;
1059*5206Sis 	size_t fid;
1060*5206Sis 	size_t tid;
1061*5206Sis 	size_t i;
1062*5206Sis 	size_t j;
1063*5206Sis 	kiconv_ops_t *op;
1064*5206Sis 
1065*5206Sis 	/* Validate the given kiconv module info. */
1066*5206Sis 	if (info == NULL || info->module_name == NULL ||
1067*5206Sis 	    info->kiconv_num_convs == 0 || info->kiconv_ops_tbl == NULL)
1068*5206Sis 		return (EINVAL);
1069*5206Sis 
1070*5206Sis 	/*
1071*5206Sis 	 * Check if this is one of the known modules. At this point,
1072*5206Sis 	 * we do not allow user-defined kiconv modules and that'd be for
1073*5206Sis 	 * a future project.
1074*5206Sis 	 */
1075*5206Sis 	for (mid = 1; mid <= KICONV_MAX_MODULE_ID; mid++)
1076*5206Sis 		if (strcmp(module_list[mid].name, info->module_name) == 0)
1077*5206Sis 			break;
1078*5206Sis 	if (mid > KICONV_MAX_MODULE_ID)
1079*5206Sis 		return (EINVAL);
1080*5206Sis 
1081*5206Sis 	/* Let's register the conversions supplied. */
1082*5206Sis 	mutex_enter(&conv_list_lock);
1083*5206Sis 
1084*5206Sis 	/*
1085*5206Sis 	 * This is very unlikely situation but by any chance we don't want to
1086*5206Sis 	 * register a module that is already in.
1087*5206Sis 	 */
1088*5206Sis 	if (module_list[mid].refcount > 0) {
1089*5206Sis 		mutex_exit(&conv_list_lock);
1090*5206Sis 		return (EAGAIN);
1091*5206Sis 	}
1092*5206Sis 
1093*5206Sis 	for (i = 0; i < info->kiconv_num_convs; i++) {
1094*5206Sis 		op = &(info->kiconv_ops_tbl[i]);
1095*5206Sis 
1096*5206Sis 		fid = normalize_codename(op->fromcode);
1097*5206Sis 		tid = normalize_codename(op->tocode);
1098*5206Sis 
1099*5206Sis 		/*
1100*5206Sis 		 * If we find anything wrong in this particular conversion,
1101*5206Sis 		 * we skip this one and continue to the next one. This include
1102*5206Sis 		 * a case where there is a conversion already being assigned
1103*5206Sis 		 * into the conv_list[] somehow, i.e., new one never kicks out
1104*5206Sis 		 * old one.
1105*5206Sis 		 */
1106*5206Sis 		if (op->kiconv_open == NULL || op->kiconv == NULL ||
1107*5206Sis 		    op->kiconv_close == NULL || op->kiconvstr == NULL)
1108*5206Sis 			continue;
1109*5206Sis 
1110*5206Sis 		for (j = 0; j < KICONV_MAX_CONVERSIONS; j++) {
1111*5206Sis 			if (conv_list[j].mid == mid &&
1112*5206Sis 			    conv_list[j].fid == fid &&
1113*5206Sis 			    conv_list[j].tid == tid) {
1114*5206Sis 				if (conv_list[j].open == NULL) {
1115*5206Sis 					conv_list[j].open = op->kiconv_open;
1116*5206Sis 					conv_list[j].kiconv = op->kiconv;
1117*5206Sis 					conv_list[j].close = op->kiconv_close;
1118*5206Sis 					conv_list[j].kiconvstr = op->kiconvstr;
1119*5206Sis 				}
1120*5206Sis 				break;
1121*5206Sis 			}
1122*5206Sis 		}
1123*5206Sis 	}
1124*5206Sis 
1125*5206Sis 	mutex_exit(&conv_list_lock);
1126*5206Sis 
1127*5206Sis 	return (0);
1128*5206Sis }
1129*5206Sis 
1130*5206Sis /*
1131*5206Sis  * The following function called during mod_remove() will try to unregister,
1132*5206Sis  * i.e., clear up conversion function pointers, from the conv_list[] if it
1133*5206Sis  * can. If there is any code conversions being used, then, the function will
1134*5206Sis  * just return EBUSY indicating that the module cannot be unloaded.
1135*5206Sis  */
1136*5206Sis int
kiconv_unregister_module(kiconv_module_info_t * info)1137*5206Sis kiconv_unregister_module(kiconv_module_info_t *info)
1138*5206Sis {
1139*5206Sis 	size_t mid;
1140*5206Sis 	size_t i;
1141*5206Sis 
1142*5206Sis 	if (info == NULL || info->module_name == NULL ||
1143*5206Sis 	    info->kiconv_num_convs == 0 || info->kiconv_ops_tbl == NULL)
1144*5206Sis 		return (EINVAL);
1145*5206Sis 
1146*5206Sis 	for (mid = 1; mid <= KICONV_MAX_MODULE_ID; mid++)
1147*5206Sis 		if (strcmp(module_list[mid].name, info->module_name) == 0)
1148*5206Sis 			break;
1149*5206Sis 	if (mid > KICONV_MAX_MODULE_ID)
1150*5206Sis 		return (EINVAL);
1151*5206Sis 
1152*5206Sis 	mutex_enter(&conv_list_lock);
1153*5206Sis 
1154*5206Sis 	/*
1155*5206Sis 	 * If any of the conversions are used, then, this module canont be
1156*5206Sis 	 * unloaded.
1157*5206Sis 	 */
1158*5206Sis 	if (module_list[mid].refcount > 0) {
1159*5206Sis 		mutex_exit(&conv_list_lock);
1160*5206Sis 		return (EBUSY);
1161*5206Sis 	}
1162*5206Sis 
1163*5206Sis 	/*
1164*5206Sis 	 * Otherwise, we unregister all conversions from this module
1165*5206Sis 	 * and be ready for the unloading. At this point, we only care about
1166*5206Sis 	 * the conversions we know about with the module.
1167*5206Sis 	 */
1168*5206Sis 	for (i = 0; i < KICONV_MAX_CONVERSIONS; i++) {
1169*5206Sis 		if (conv_list[i].mid == mid) {
1170*5206Sis 			conv_list[i].open = NULL;
1171*5206Sis 			conv_list[i].kiconv = NULL;
1172*5206Sis 			conv_list[i].close = NULL;
1173*5206Sis 			conv_list[i].kiconvstr = NULL;
1174*5206Sis 		}
1175*5206Sis 	}
1176*5206Sis 
1177*5206Sis 	mutex_exit(&conv_list_lock);
1178*5206Sis 
1179*5206Sis 	return (0);
1180*5206Sis }
1181*5206Sis 
1182*5206Sis /*
1183*5206Sis  * The following function check if asked code conversion is available
1184*5206Sis  * and if necessary, load the corresponding kiconv module that contains
1185*5206Sis  * the conversion (and others).
1186*5206Sis  */
1187*5206Sis static kiconv_t
check_and_load_conversions(const char * tocode,const char * fromcode)1188*5206Sis check_and_load_conversions(const char *tocode, const char *fromcode)
1189*5206Sis {
1190*5206Sis 	kiconv_t kcd;
1191*5206Sis 	size_t tid;
1192*5206Sis 	size_t fid;
1193*5206Sis 	size_t mid;
1194*5206Sis 	size_t i;
1195*5206Sis 
1196*5206Sis 	/* Normalize the given names and find the corresponding code ids. */
1197*5206Sis 	tid = normalize_codename(tocode);
1198*5206Sis 	if (tid == (size_t)-1)
1199*5206Sis 		return ((kiconv_t)-1);
1200*5206Sis 
1201*5206Sis 	fid = normalize_codename(fromcode);
1202*5206Sis 	if (fid == (size_t)-1)
1203*5206Sis 		return ((kiconv_t)-1);
1204*5206Sis 
1205*5206Sis 	/*
1206*5206Sis 	 * Search the conversion.
1207*5206Sis 	 *
1208*5206Sis 	 * If the conversion isn't supported, just return -1.
1209*5206Sis 	 * If the conversion is supported but there is no corresponding
1210*5206Sis 	 * module loaded, try to load it and if successful, return
1211*5206Sis 	 * a kiconv conversion descriptor memory block.
1212*5206Sis 	 *
1213*5206Sis 	 * We maintain a reference counter of uint_t for each module.
1214*5206Sis 	 */
1215*5206Sis 	mutex_enter(&conv_list_lock);
1216*5206Sis 
1217*5206Sis 	for (i = 0; i < KICONV_MAX_CONVERSIONS; i++)
1218*5206Sis 		if (conv_list[i].tid == tid && conv_list[i].fid == fid)
1219*5206Sis 			break;
1220*5206Sis 	if (i >= KICONV_MAX_CONVERSIONS) {
1221*5206Sis 		mutex_exit(&conv_list_lock);
1222*5206Sis 		return ((kiconv_t)-1);
1223*5206Sis 	}
1224*5206Sis 
1225*5206Sis 	mid = conv_list[i].mid;
1226*5206Sis 
1227*5206Sis 	if (conv_list[i].open == NULL) {
1228*5206Sis 		mutex_exit(&conv_list_lock);
1229*5206Sis 
1230*5206Sis 		if (modload("kiconv", module_list[mid].name) < 0)
1231*5206Sis 			return ((kiconv_t)-1);
1232*5206Sis 
1233*5206Sis 		/*
1234*5206Sis 		 * Let's double check if something happened right after
1235*5206Sis 		 * the modload and/or if the module really has the conversion.
1236*5206Sis 		 */
1237*5206Sis 		mutex_enter(&conv_list_lock);
1238*5206Sis 
1239*5206Sis 		if (conv_list[i].open == NULL) {
1240*5206Sis 			mutex_exit(&conv_list_lock);
1241*5206Sis 			return ((kiconv_t)-1);
1242*5206Sis 		}
1243*5206Sis 	}
1244*5206Sis 
1245*5206Sis 	/*
1246*5206Sis 	 * If we got the conversion, we will use the conversion function
1247*5206Sis 	 * in the module and so let's increase the module's refcounter
1248*5206Sis 	 * so that the module won't be kicked out. (To be more exact and
1249*5206Sis 	 * specific, the "refcount" is thus the reference counter of
1250*5206Sis 	 * the module functions being used.)
1251*5206Sis 	 */
1252*5206Sis 	if (module_list[mid].refcount < UINT_MAX)
1253*5206Sis 		module_list[mid].refcount++;
1254*5206Sis 
1255*5206Sis 	mutex_exit(&conv_list_lock);
1256*5206Sis 
1257*5206Sis 	kcd = (kiconv_t)kmem_alloc(sizeof (kiconv_data_t), KM_SLEEP);
1258*5206Sis 	kcd->handle = (void *)-1;
1259*5206Sis 	kcd->id = i;
1260*5206Sis 
1261*5206Sis 	return (kcd);
1262*5206Sis }
1263*5206Sis 
1264*5206Sis /*
1265*5206Sis  * The following are the four "Committed" interfaces.
1266*5206Sis  */
1267*5206Sis kiconv_t
kiconv_open(const char * tocode,const char * fromcode)1268*5206Sis kiconv_open(const char *tocode, const char *fromcode)
1269*5206Sis {
1270*5206Sis 	kiconv_t kcd;
1271*5206Sis 	size_t mid;
1272*5206Sis 
1273*5206Sis 	kcd = check_and_load_conversions(tocode, fromcode);
1274*5206Sis 	if (kcd == (kiconv_t)-1)
1275*5206Sis 		return ((kiconv_t)-1);
1276*5206Sis 
1277*5206Sis 	kcd->handle = (conv_list[kcd->id].open)();
1278*5206Sis 	if (kcd->handle == (void *)-1) {
1279*5206Sis 		/*
1280*5206Sis 		 * If the conversion couldn't be opened for some reason,
1281*5206Sis 		 * then, we unallocate the kcd and, more importantly, before
1282*5206Sis 		 * that, we also decrease the module reference counter.
1283*5206Sis 		 */
1284*5206Sis 		mid = conv_list[kcd->id].mid;
1285*5206Sis 
1286*5206Sis 		mutex_enter(&conv_list_lock);
1287*5206Sis 
1288*5206Sis 		if (module_list[mid].refcount > 0)
1289*5206Sis 			module_list[mid].refcount--;
1290*5206Sis 
1291*5206Sis 		mutex_exit(&conv_list_lock);
1292*5206Sis 
1293*5206Sis 		kmem_free((void *)kcd, sizeof (kiconv_data_t));
1294*5206Sis 
1295*5206Sis 		return ((kiconv_t)-1);
1296*5206Sis 	}
1297*5206Sis 
1298*5206Sis 	return (kcd);
1299*5206Sis }
1300*5206Sis 
1301*5206Sis size_t
kiconv(kiconv_t kcd,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft,int * errno)1302*5206Sis kiconv(kiconv_t kcd, char **inbuf, size_t *inbytesleft,
1303*5206Sis 	char **outbuf, size_t *outbytesleft, int *errno)
1304*5206Sis {
1305*5206Sis 	/* Do some minimum checking on the kiconv conversion descriptor. */
1306*5206Sis 	if (! kcd || kcd == (kiconv_t)-1 || conv_list[kcd->id].kiconv == NULL) {
1307*5206Sis 		*errno = EBADF;
1308*5206Sis 		return ((size_t)-1);
1309*5206Sis 	}
1310*5206Sis 
1311*5206Sis 	return ((conv_list[kcd->id].kiconv)(kcd->handle, inbuf, inbytesleft,
1312*5206Sis 	    outbuf, outbytesleft, errno));
1313*5206Sis }
1314*5206Sis 
1315*5206Sis int
kiconv_close(kiconv_t kcd)1316*5206Sis kiconv_close(kiconv_t kcd)
1317*5206Sis {
1318*5206Sis 	int ret;
1319*5206Sis 	size_t mid;
1320*5206Sis 
1321*5206Sis 	if (! kcd || kcd == (kiconv_t)-1 || conv_list[kcd->id].close == NULL)
1322*5206Sis 		return (EBADF);
1323*5206Sis 
1324*5206Sis 	mid = conv_list[kcd->id].mid;
1325*5206Sis 
1326*5206Sis 	ret = (conv_list[kcd->id].close)(kcd->handle);
1327*5206Sis 
1328*5206Sis 	kmem_free((void *)kcd, sizeof (kiconv_data_t));
1329*5206Sis 
1330*5206Sis 	mutex_enter(&conv_list_lock);
1331*5206Sis 
1332*5206Sis 	/*
1333*5206Sis 	 * While we maintain reference conter for each module, once loaded,
1334*5206Sis 	 * we don't modunload from kiconv functions even if the counter
1335*5206Sis 	 * reaches back to zero.
1336*5206Sis 	 */
1337*5206Sis 	if (module_list[mid].refcount > 0)
1338*5206Sis 		module_list[mid].refcount--;
1339*5206Sis 
1340*5206Sis 	mutex_exit(&conv_list_lock);
1341*5206Sis 
1342*5206Sis 	return (ret);
1343*5206Sis }
1344*5206Sis 
1345*5206Sis size_t
kiconvstr(const char * tocode,const char * fromcode,char * inarray,size_t * inlen,char * outarray,size_t * outlen,int flag,int * errno)1346*5206Sis kiconvstr(const char *tocode, const char *fromcode, char *inarray,
1347*5206Sis 	size_t *inlen, char *outarray, size_t *outlen, int flag, int *errno)
1348*5206Sis {
1349*5206Sis 	kiconv_t kcd;
1350*5206Sis 	size_t ret;
1351*5206Sis 	size_t mid;
1352*5206Sis 
1353*5206Sis 	kcd = check_and_load_conversions(tocode, fromcode);
1354*5206Sis 	if (kcd == (kiconv_t)-1 || conv_list[kcd->id].kiconvstr == NULL) {
1355*5206Sis 		*errno = EBADF;
1356*5206Sis 		return ((size_t)-1);
1357*5206Sis 	}
1358*5206Sis 
1359*5206Sis 	mid = conv_list[kcd->id].mid;
1360*5206Sis 
1361*5206Sis 	ret = (conv_list[kcd->id].kiconvstr)(inarray, inlen, outarray, outlen,
1362*5206Sis 	    flag, errno);
1363*5206Sis 
1364*5206Sis 	kmem_free((void *)kcd, sizeof (kiconv_data_t));
1365*5206Sis 
1366*5206Sis 	mutex_enter(&conv_list_lock);
1367*5206Sis 
1368*5206Sis 	if (module_list[mid].refcount > 0)
1369*5206Sis 		module_list[mid].refcount--;
1370*5206Sis 
1371*5206Sis 	mutex_exit(&conv_list_lock);
1372*5206Sis 
1373*5206Sis 	return (ret);
1374*5206Sis }
1375