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