xref: /illumos-gate/usr/src/uts/common/kiconv/kiconv_ja/kiconv_ja.c (revision 2a6e99a0f1f7d22c0396e8b2ce9b9babbd1056cf)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/sysmacros.h>
32 #include <sys/systm.h>
33 #include <sys/debug.h>
34 #include <sys/kmem.h>
35 #include <sys/sunddi.h>
36 #include <sys/byteorder.h>
37 #include <sys/errno.h>
38 #include <sys/euc.h>
39 #include <sys/modctl.h>
40 #include <sys/kiconv.h>
41 
42 #include <sys/kiconv_ja.h>
43 #include <sys/kiconv_ja_jis_to_unicode.h>
44 #include <sys/kiconv_ja_unicode_to_jis.h>
45 
46 /*
47  * The following vector shows remaining bytes in a UTF-8 character.
48  * Index will be the first byte of the character. This is defined in
49  * u8_textprep.c.
50  */
51 extern const int8_t u8_number_of_bytes[];
52 
53 /*
54  * The following is a vector of bit-masks to get used bits in
55  * the first byte of a UTF-8 character. Index is remaining bytes at above of
56  * the character. This is defined in uconv.c.
57  */
58 extern const uchar_t u8_masks_tbl[];
59 
60 /*
61  * The following two vectors are to provide valid minimum and
62  * maximum values for the 2'nd byte of a multibyte UTF-8 character for
63  * better illegal sequence checking. The index value must be the value of
64  * the first byte of the UTF-8 character. These are defined in u8_textprep.c.
65  */
66 extern const uint8_t u8_valid_min_2nd_byte[];
67 extern const uint8_t u8_valid_max_2nd_byte[];
68 
69 static kiconv_ja_euc16_t
70 kiconv_ja_ucs2_to_euc16(kiconv_ja_ucs2_t ucs2)
71 {
72 	const kiconv_ja_euc16_t	*p;
73 
74 	if ((p = kiconv_ja_ucs2_to_euc16_index[ucs2 >> 8]) != NULL)
75 		return (p[ucs2 & 0xff]);
76 
77 	return (KICONV_JA_NODEST);
78 }
79 
80 static size_t
81 utf8_ucs(uint_t *p, uchar_t **pip, size_t *pileft, int *errno)
82 {
83 	uint_t	l;		/* to be copied to *p on successful return */
84 	uchar_t	ic;		/* current byte */
85 	uchar_t	ic1;		/* 1st byte */
86 	uchar_t	*ip = *pip;	/* next byte to read */
87 	size_t	ileft = *pileft; /* number of bytes available */
88 	size_t	rv = 0; 	/* return value of this function */
89 	int	remaining_bytes;
90 	int	u8_size;
91 
92 	KICONV_JA_NGET(ic1);	/* read 1st byte */
93 
94 	if (ic1 < 0x80) {
95 		/* successfully converted */
96 		*p = (uint_t)ic1;
97 		goto ret;
98 	}
99 
100 	u8_size = u8_number_of_bytes[ic1];
101 	if (u8_size == U8_ILLEGAL_CHAR) {
102 		KICONV_JA_RETERROR(EILSEQ)
103 	} else if (u8_size == U8_OUT_OF_RANGE_CHAR) {
104 		KICONV_JA_RETERROR(ERANGE)
105 	}
106 
107 	remaining_bytes = u8_size - 1;
108 	if (remaining_bytes != 0) {
109 		l = ic1 & u8_masks_tbl[remaining_bytes];
110 
111 		for (; remaining_bytes > 0; remaining_bytes--) {
112 			KICONV_JA_NGET(ic);
113 			if (ic1 != 0U) {
114 				if ((ic < u8_valid_min_2nd_byte[ic1]) ||
115 				    (ic > u8_valid_max_2nd_byte[ic1])) {
116 					KICONV_JA_RETERROR(EILSEQ)
117 				}
118 				ic1 = 0U; /* 2nd byte check done */
119 			} else {
120 				if ((ic < 0x80) || (ic > 0xbf)) {
121 					KICONV_JA_RETERROR(EILSEQ)
122 				}
123 			}
124 			l = (l << 6) | (ic & 0x3f);
125 		}
126 
127 		/* successfully converted */
128 		*p = l;
129 	} else {
130 		KICONV_JA_RETERROR(EILSEQ)
131 	}
132 
133 ret:
134 	if (rv == 0) {
135 		/*
136 		 * Update rv, *pip, and *pileft on successfule return.
137 		 */
138 		rv = *pileft - ileft;
139 		*pip = ip;
140 		*pileft = ileft;
141 	}
142 
143 	return (rv);
144 }
145 
146 static size_t
147 utf8_ucs_replace(uint_t *p, uchar_t **pip, size_t *pileft, size_t *repnum)
148 {
149 	uint_t	l;		/* to be copied to *p on successful return */
150 	uchar_t	ic;		/* current byte */
151 	uchar_t	ic1;		/* 1st byte */
152 	uchar_t	*ip = *pip;	/* next byte to read */
153 	size_t	ileft = *pileft; /* number of bytes available */
154 	size_t	rv = 0; 	/* return value of this function */
155 	int	remaining_bytes;
156 	int	u8_size;
157 
158 	KICONV_JA_NGET_REP_TO_MB(ic1); 	/* read 1st byte */
159 
160 	if (ic1 < 0x80) {
161 		/* successfully converted */
162 		l = (uint_t)ic1;
163 		goto ret;
164 	}
165 
166 	u8_size = u8_number_of_bytes[ic1];
167 	if (u8_size == U8_ILLEGAL_CHAR || u8_size == U8_OUT_OF_RANGE_CHAR) {
168 		l = KICONV_JA_DEF_SINGLE;
169 		(*repnum)++;
170 		goto ret;
171 	}
172 
173 	remaining_bytes = u8_size - 1;
174 
175 	if (remaining_bytes != 0) {
176 		l = ic1 & u8_masks_tbl[remaining_bytes];
177 
178 		for (; remaining_bytes > 0; remaining_bytes--) {
179 			KICONV_JA_NGET_REP_TO_MB(ic);
180 			if (ic1 != 0U) {
181 				if ((ic < u8_valid_min_2nd_byte[ic1]) ||
182 				    (ic > u8_valid_max_2nd_byte[ic1])) {
183 					l = KICONV_JA_DEF_SINGLE;
184 					(*repnum)++;
185 					ileft -= (remaining_bytes - 1);
186 					ip += (remaining_bytes - 1);
187 					break;
188 				}
189 				ic1 = 0U; /* 2nd byte check done */
190 			} else {
191 				if ((ic < 0x80) || (ic > 0xbf)) {
192 					l = KICONV_JA_DEF_SINGLE;
193 					(*repnum)++;
194 					ileft -= (remaining_bytes - 1);
195 					ip += (remaining_bytes - 1);
196 					break;
197 				}
198 			}
199 			l = (l << 6) | (ic & 0x3f);
200 		}
201 	} else {
202 		l = KICONV_JA_DEF_SINGLE;
203 		(*repnum)++;
204 	}
205 
206 ret:
207 	/* successfully converted */
208 	*p = l;
209 	rv = *pileft - ileft;
210 
211 	*pip = ip;
212 	*pileft = ileft;
213 
214 	return (rv);
215 }
216 
217 static size_t				/* return #bytes read, or -1 */
218 read_unicode(
219 	uint_t	*p,		/* point variable to store UTF-32 */
220 	uchar_t	**pip,		/* point pointer to input buf */
221 	size_t	*pileft,	/* point #bytes left in input buf */
222 	int	*errno,		/* point variable to errno */
223 	int	flag,		/* kiconvstr flag */
224 	size_t	*rv)		/* point return valuse */
225 {
226 	if (flag & KICONV_REPLACE_INVALID)
227 		return (utf8_ucs_replace(p, pip, pileft, rv));
228 	else
229 		return (utf8_ucs(p, pip, pileft, errno));
230 }
231 
232 static size_t
233 write_unicode(
234 	uint_t	u32,		/* UTF-32 to write */
235 	char	**pop,		/* point pointer to output buf */
236 	size_t	*poleft,	/* point #bytes left in output buf */
237 	int	*errno)		/* point variable to errno */
238 {
239 	char	*op = *pop;
240 	size_t	oleft = *poleft;
241 	size_t	rv = 0;			/* return value */
242 
243 	if (u32 <= 0x7f) {
244 		KICONV_JA_NPUT((uchar_t)(u32));
245 		rv = 1;
246 	} else if (u32 <= 0x7ff) {
247 		KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x1f) | 0xc0));
248 		KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
249 		rv = 2;
250 	} else if ((u32 >= 0xd800) && (u32 <= 0xdfff)) {
251 		KICONV_JA_RETERROR(EILSEQ)
252 	} else if (u32 <= 0xffff) {
253 		KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x0f) | 0xe0));
254 		KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80));
255 		KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
256 		rv = 3;
257 	} else if (u32 <= 0x10ffff) {
258 		KICONV_JA_NPUT((uchar_t)((((u32)>>18) & 0x07) | 0xf0));
259 		KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x3f) | 0x80));
260 		KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80));
261 		KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
262 		rv = 4;
263 	} else {
264 		KICONV_JA_RETERROR(EILSEQ)
265 	}
266 
267 ret:
268 	if (rv != (size_t)-1) {
269 		/* update *pop and *poleft only on successful return */
270 		*pop = op;
271 		*poleft = oleft;
272 	}
273 
274 	return (rv);
275 }
276 
277 static void *
278 _kiconv_ja_open_unicode(uint8_t id)
279 {
280 	kiconv_state_t	kcd;
281 
282 	kcd = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t),
283 	    KM_SLEEP);
284 	kcd->id = id;
285 	kcd->bom_processed = 0;
286 	return ((void *)kcd);
287 }
288 
289 static void *
290 open_eucjp(void)
291 {
292 	return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP));
293 }
294 
295 static void *
296 open_eucjpms(void)
297 {
298 	return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP_MS));
299 }
300 
301 static void *
302 open_sjis(void)
303 {
304 	return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_SJIS));
305 }
306 
307 static void *
308 open_cp932(void)
309 {
310 	return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_CP932));
311 }
312 
313 int
314 close_ja(void *kcd)
315 {
316 	if (! kcd || kcd == (void *)-1)
317 		return (EBADF);
318 
319 	kmem_free(kcd, sizeof (kiconv_state_data_t));
320 
321 	return (0);
322 }
323 
324 static size_t
325 _do_kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
326 		char **outbuf, size_t *outbytesleft, int *errno)
327 {
328 	uint_t		u32;		/* UTF-32 */
329 	uint_t		index;		/* index for table lookup */
330 	uchar_t		ic1, ic2, ic3;	/* 1st, 2nd, and 3rd bytes of a char */
331 	size_t		rv = 0;		/* return value of this function */
332 
333 	uchar_t	*ip;
334 	size_t		ileft;
335 	char		*op;
336 	size_t		oleft;
337 	size_t		id = ((kiconv_state_t)kcd)->id;
338 
339 	if ((inbuf == NULL) || (*inbuf == NULL)) {
340 		return (0);
341 	}
342 
343 	ip = (uchar_t *)*inbuf;
344 	ileft = *inbytesleft;
345 	op = *outbuf;
346 	oleft = *outbytesleft;
347 
348 	while (ileft != 0) {
349 		KICONV_JA_NGET(ic1); 		/* get 1st byte */
350 
351 		if (KICONV_JA_ISASC(ic1)) { 	/* ASCII; 1 byte */
352 			u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1];
353 			KICONV_JA_PUTU(u32);
354 		} else if (KICONV_JA_ISCS1(ic1)) { /* 0208 or UDC; 2 bytes */
355 			KICONV_JA_NGET(ic2);
356 			if (KICONV_JA_ISCS1(ic2)) { /* 2nd byte check passed */
357 				ic1 &= KICONV_JA_CMASK;
358 				ic2 &= KICONV_JA_CMASK;
359 				KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2);
360 				if (u32 == KICONV_JA_NODEST) {
361 					index = (ic1 - 0x21) * 94 + ic2 - 0x21;
362 					u32 = kiconv_ja_jisx0208_to_ucs2[index];
363 				}
364 				if (u32 == KICONV_JA_REPLACE)
365 					rv++;
366 				KICONV_JA_PUTU(u32);
367 			} else { /* 2nd byte check failed */
368 				KICONV_JA_RETERROR(EILSEQ)
369 			}
370 		} else if (ic1 == SS2) { /* JIS X 0201 Kana; 2 bytes */
371 			KICONV_JA_NGET(ic2);
372 			if (KICONV_JA_ISCS2(ic2)) { /* 2nd byte check passed */
373 				index = (ic2 - 0xa1);
374 				u32 = kiconv_ja_jisx0201kana_to_ucs2[index];
375 				KICONV_JA_PUTU(u32);
376 			} else { /* 2nd byte check failed */
377 				KICONV_JA_RETERROR(EILSEQ)
378 			}
379 		} else if (ic1 == SS3) { /* JIS X 0212 or UDC; 3 bytes */
380 			KICONV_JA_NGET(ic2);
381 			if (KICONV_JA_ISCS3(ic2)) { /* 2nd byte check passed */
382 				KICONV_JA_NGET(ic3);
383 				if (KICONV_JA_ISCS3(ic3)) {
384 					/* 3rd byte check passed */
385 					ic2 &= KICONV_JA_CMASK;
386 					ic3 &= KICONV_JA_CMASK;
387 					KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32,
388 					    ic2, ic3);
389 					if (u32 == KICONV_JA_NODEST) {
390 						index = ((ic2 - 0x21) * 94 +
391 						    (ic3 - 0x21));
392 						u32 = kiconv_ja_jisx0212_to_ucs2
393 						    [index];
394 					}
395 					if (u32 == KICONV_JA_REPLACE)
396 						rv++;
397 					KICONV_JA_PUTU(u32);
398 				} else { /* 3rd byte check failed */
399 					KICONV_JA_RETERROR(EILSEQ)
400 				}
401 			} else { /* 2nd byte check failed */
402 				KICONV_JA_RETERROR(EILSEQ)
403 			}
404 		} else if (KICONV_JA_ISC1CTRLEUC(ic1)) {
405 			/* C1 control; 1 byte */
406 			u32 = ic1;
407 			KICONV_JA_PUTU(u32);
408 		} else { /* 1st byte check failed */
409 			KICONV_JA_RETERROR(EILSEQ)
410 		}
411 
412 		/*
413 		 * One character successfully converted so update
414 		 * values outside of this function's stack.
415 		 */
416 		*inbuf = (char *)ip;
417 		*inbytesleft = ileft;
418 		*outbuf = op;
419 		*outbytesleft = oleft;
420 	}
421 
422 ret:
423 	return (rv);
424 }
425 
426 static size_t
427 _do_kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
428 		char **outbuf, size_t *outbytesleft, int *errno)
429 {
430 	uchar_t		ic;
431 	size_t		rv = 0;
432 	uint_t		ucs4;
433 	ushort_t	euc16;
434 
435 	uchar_t	*ip;
436 	size_t		ileft;
437 	char		*op;
438 	size_t		oleft;
439 	size_t		read_len;
440 
441 	size_t		id = ((kiconv_state_t)kcd)->id;
442 
443 	if ((inbuf == NULL) || (*inbuf == NULL)) {
444 		return (0);
445 	}
446 
447 	ip = (uchar_t *)*inbuf;
448 	ileft = *inbytesleft;
449 	op = *outbuf;
450 	oleft = *outbytesleft;
451 
452 	KICONV_JA_CHECK_UTF8_BOM(ip, ileft);
453 
454 	while (ileft != 0) {
455 		KICONV_JA_GETU(&ucs4, 0);
456 
457 		if (ucs4 > 0xffff) {
458 			/* non-BMP */
459 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
460 			rv++;
461 			goto next;
462 		}
463 
464 		KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
465 		if (euc16 == KICONV_JA_NODEST) {
466 			euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
467 		}
468 		if (euc16 == KICONV_JA_NODEST) {
469 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
470 			rv++;
471 			goto next;
472 		}
473 
474 		switch (euc16 & 0x8080) {
475 		case 0x0000:	/* CS0 */
476 			ic = (uchar_t)euc16;
477 			KICONV_JA_NPUT(ic);
478 			break;
479 		case 0x8080:	/* CS1 */
480 			ic = (uchar_t)((euc16 >> 8) & 0xff);
481 			KICONV_JA_NPUT(ic);
482 			ic = (uchar_t)(euc16 & 0xff);
483 			KICONV_JA_NPUT(ic);
484 			break;
485 		case 0x0080:	/* CS2 */
486 			KICONV_JA_NPUT(SS2);
487 			ic = (uchar_t)euc16;
488 			KICONV_JA_NPUT(ic);
489 			break;
490 		case 0x8000:	/* CS3 */
491 			KICONV_JA_NPUT(SS3);
492 			ic = (uchar_t)((euc16 >> 8) & 0xff);
493 			KICONV_JA_NPUT(ic);
494 			ic = (uchar_t)(euc16 & KICONV_JA_CMASK);
495 			KICONV_JA_NPUT(ic | KICONV_JA_CMSB);
496 			break;
497 		}
498 next:
499 		/*
500 		 * One character successfully converted so update
501 		 * values outside of this function's stack.
502 		 */
503 		*inbuf = (char *)ip;
504 		*inbytesleft = ileft;
505 		*outbuf = op;
506 		*outbytesleft = oleft;
507 	}
508 
509 ret:
510 	return (rv);
511 }
512 
513 static size_t
514 _do_kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
515 	size_t *outbytesleft, int flag, int *errno, uint8_t id)
516 {
517 	uint_t		u32;		/* UTF-32 */
518 	uint_t		index;		/* index for table lookup */
519 	uchar_t		ic1, ic2, ic3;	/* 1st, 2nd, and 3rd bytes of a char */
520 	size_t		rv = 0;		/* return value of this function */
521 
522 	uchar_t	*ip;
523 	size_t		ileft;
524 	char		*op;
525 	size_t		oleft;
526 
527 	boolean_t do_not_ignore_null;
528 
529 	if ((inbuf == NULL) || (*inbuf == NULL)) {
530 		return (0);
531 	}
532 
533 	ip = (uchar_t *)inbuf;
534 	ileft = *inbytesleft;
535 	op = outbuf;
536 	oleft = *outbytesleft;
537 
538 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
539 
540 	while (ileft != 0) {
541 		KICONV_JA_NGET(ic1); 		/* get 1st byte */
542 
543 		if (KICONV_JA_ISASC(ic1)) { 	/* ASCII; 1 byte */
544 			if (ic1 == '\0' && do_not_ignore_null) {
545 				return (0);
546 			}
547 			u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1];
548 			KICONV_JA_PUTU(u32);
549 		} else if (KICONV_JA_ISCS1(ic1)) { /* 0208 or UDC; 2 bytes */
550 			if (flag & KICONV_REPLACE_INVALID) {
551 				KICONV_JA_NGET_REP_FR_MB(ic2);
552 			} else {
553 				KICONV_JA_NGET(ic2);
554 			}
555 			if (KICONV_JA_ISCS1(ic2)) { /* 2nd byte check passed */
556 				ic1 &= KICONV_JA_CMASK;
557 				ic2 &= KICONV_JA_CMASK;
558 				KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2);
559 				if (u32 == KICONV_JA_NODEST) {
560 					index = (ic1 - 0x21) * 94 + ic2 - 0x21;
561 					u32 = kiconv_ja_jisx0208_to_ucs2[index];
562 				}
563 				if (u32 == KICONV_JA_REPLACE)
564 					rv++;
565 				KICONV_JA_PUTU(u32);
566 			} else { /* 2nd byte check failed */
567 				if (flag & KICONV_REPLACE_INVALID) {
568 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
569 					rv++;
570 				} else {
571 					KICONV_JA_RETERROR(EILSEQ)
572 				}
573 			}
574 		} else if (ic1 == SS2) { /* JIS X 0201 Kana; 2bytes */
575 			if (flag & KICONV_REPLACE_INVALID) {
576 				KICONV_JA_NGET_REP_FR_MB(ic2);
577 			} else {
578 				KICONV_JA_NGET(ic2);
579 			}
580 			if (KICONV_JA_ISCS2(ic2)) { /* 2nd byte check passed */
581 				index = (ic2 - 0xa1);
582 				u32 = kiconv_ja_jisx0201kana_to_ucs2[index];
583 				KICONV_JA_PUTU(u32);
584 			} else { /* 2nd byte check failed */
585 				if (flag & KICONV_REPLACE_INVALID) {
586 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
587 					rv++;
588 				} else {
589 					KICONV_JA_RETERROR(EILSEQ)
590 				}
591 			}
592 		} else if (ic1 == SS3) { /* JIS X 0212 or UDC; 3 bytes */
593 			if (flag & KICONV_REPLACE_INVALID) {
594 				KICONV_JA_NGET_REP_FR_MB(ic2);
595 			} else {
596 				KICONV_JA_NGET(ic2);
597 			}
598 			if (KICONV_JA_ISCS3(ic2)) { /* 2nd byte check passed */
599 				if (flag & KICONV_REPLACE_INVALID) {
600 					KICONV_JA_NGET_REP_FR_MB(ic3);
601 				} else {
602 					KICONV_JA_NGET(ic3);
603 				}
604 				if (KICONV_JA_ISCS3(ic3)) {
605 					/* 3rd byte check passed */
606 					ic2 &= KICONV_JA_CMASK;
607 					ic3 &= KICONV_JA_CMASK;
608 					KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32,
609 					    ic2, ic3);
610 					if (u32 == KICONV_JA_NODEST) {
611 						index = ((ic2 - 0x21) * 94 +
612 						    (ic3 - 0x21));
613 						u32 = kiconv_ja_jisx0212_to_ucs2
614 						    [index];
615 					}
616 					if (u32 == KICONV_JA_REPLACE)
617 						rv++;
618 					KICONV_JA_PUTU(u32);
619 				} else { /* 3rd byte check failed */
620 					if (flag & KICONV_REPLACE_INVALID) {
621 						KICONV_JA_PUTU(
622 						    KICONV_JA_REPLACE);
623 						rv++;
624 					} else {
625 						KICONV_JA_RETERROR(EILSEQ)
626 					}
627 				}
628 			} else { /* 2nd byte check failed */
629 				if (flag & KICONV_REPLACE_INVALID) {
630 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
631 					rv++;
632 				} else {
633 					KICONV_JA_RETERROR(EILSEQ)
634 				}
635 			}
636 		} else if (KICONV_JA_ISC1CTRLEUC(ic1)) {
637 			/* C1 control; 1 byte */
638 			u32 = ic1;
639 			KICONV_JA_PUTU(u32);
640 		} else { /* 1st byte check failed */
641 			if (flag & KICONV_REPLACE_INVALID) {
642 				KICONV_JA_PUTU(KICONV_JA_REPLACE);
643 				rv++;
644 			} else {
645 				KICONV_JA_RETERROR(EILSEQ)
646 			}
647 		}
648 
649 next:
650 		/*
651 		 * One character successfully converted so update
652 		 * values outside of this function's stack.
653 		 */
654 		*inbytesleft = ileft;
655 		*outbytesleft = oleft;
656 	}
657 
658 ret:
659 	return (rv);
660 }
661 
662 static size_t
663 _do_kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
664 	size_t *outbytesleft, int flag, int *errno, uint8_t id)
665 {
666 	uchar_t		ic;
667 	size_t		rv = 0;
668 	uint_t		ucs4;
669 	ushort_t	euc16;
670 
671 	uchar_t	*ip;
672 	size_t		ileft;
673 	char		*op;
674 	size_t		oleft;
675 	size_t		read_len;
676 
677 	boolean_t do_not_ignore_null;
678 
679 	if ((inbuf == NULL) || (*inbuf == NULL)) {
680 		return (0);
681 	}
682 
683 	ip = (uchar_t *)inbuf;
684 	ileft = *inbytesleft;
685 	op = outbuf;
686 	oleft = *outbytesleft;
687 
688 	KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft);
689 
690 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
691 
692 	while (ileft != 0) {
693 		KICONV_JA_GETU(&ucs4, flag);
694 
695 		if (ucs4 == 0x0 && do_not_ignore_null) {
696 			return (0);
697 		}
698 
699 		if (ucs4 > 0xffff) {
700 			/* non-BMP */
701 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
702 			rv++;
703 			goto next;
704 		}
705 
706 		KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
707 		if (euc16 == KICONV_JA_NODEST) {
708 			euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
709 		}
710 		if (euc16 == KICONV_JA_NODEST) {
711 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
712 			rv++;
713 			goto next;
714 		}
715 
716 		switch (euc16 & 0x8080) {
717 		case 0x0000:	/* CS0 */
718 			ic = (uchar_t)euc16;
719 			KICONV_JA_NPUT(ic);
720 			break;
721 		case 0x8080:	/* CS1 */
722 			ic = (uchar_t)((euc16 >> 8) & 0xff);
723 			KICONV_JA_NPUT(ic);
724 			ic = (uchar_t)(euc16 & 0xff);
725 			KICONV_JA_NPUT(ic);
726 			break;
727 		case 0x0080:	/* CS2 */
728 			KICONV_JA_NPUT(SS2);
729 			ic = (uchar_t)euc16;
730 			KICONV_JA_NPUT(ic);
731 			break;
732 		case 0x8000:	/* CS3 */
733 			KICONV_JA_NPUT(SS3);
734 			ic = (uchar_t)((euc16 >> 8) & 0xff);
735 			KICONV_JA_NPUT(ic);
736 			ic = (uchar_t)(euc16 & KICONV_JA_CMASK);
737 			KICONV_JA_NPUT(ic | KICONV_JA_CMSB);
738 			break;
739 		}
740 next:
741 		/*
742 		 * One character successfully converted so update
743 		 * values outside of this function's stack.
744 		 */
745 		*inbytesleft = ileft;
746 		*outbytesleft = oleft;
747 	}
748 
749 ret:
750 	return (rv);
751 }
752 
753 static size_t
754 kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
755 		char **outbuf, size_t *outbytesleft, int *errno)
756 {
757 	if (! kcd || kcd == (void *)-1) {
758 		*errno = EBADF;
759 		return ((size_t)-1);
760 	}
761 
762 	return (_do_kiconv_fr_eucjp(kcd, inbuf, inbytesleft,
763 	    outbuf, outbytesleft, errno));
764 }
765 
766 static size_t
767 kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
768 		char **outbuf, size_t *outbytesleft, int *errno)
769 {
770 	if (! kcd || kcd == (void *)-1) {
771 		*errno = EBADF;
772 		return ((size_t)-1);
773 	}
774 
775 	return (_do_kiconv_to_eucjp(kcd, inbuf, inbytesleft,
776 	    outbuf, outbytesleft, errno));
777 }
778 
779 static size_t
780 kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
781 	size_t *outbytesleft, int flag, int *errno)
782 {
783 	return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf,
784 	    outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP));
785 }
786 
787 static size_t
788 kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
789 	size_t *outbytesleft, int flag, int *errno)
790 {
791 	return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf,
792 	    outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP));
793 }
794 
795 static size_t
796 kiconvstr_fr_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf,
797 	size_t *outbytesleft, int flag, int *errno)
798 {
799 	return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf,
800 	    outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS));
801 }
802 
803 static size_t
804 kiconvstr_to_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf,
805 	size_t *outbytesleft, int flag, int *errno)
806 {
807 	return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf,
808 	    outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS));
809 }
810 
811 static size_t
812 _do_kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
813 		char **outbuf, size_t *outbytesleft, int *errno)
814 {
815 	uint_t	uni;			/* UTF-32 */
816 	uint_t	index;			/* index for table lookup */
817 	uchar_t	ic1, ic2;		/* 1st and 2nd bytes of a char */
818 	size_t	rv = 0;			/* return value of this function */
819 
820 	uchar_t	*ip;
821 	size_t		ileft;
822 	char		*op;
823 	size_t		oleft;
824 	size_t		id = ((kiconv_state_t)kcd)->id;
825 
826 	if ((inbuf == NULL) || (*inbuf == NULL)) {
827 		return (0);
828 	}
829 
830 	ip = (uchar_t *)*inbuf;
831 	ileft = *inbytesleft;
832 	op = *outbuf;
833 	oleft = *outbytesleft;
834 
835 	while (ileft != 0) {
836 		KICONV_JA_NGET(ic1); 			/* get 1st byte */
837 
838 		if (KICONV_JA_ISASC((int)ic1)) {	/* ASCII; 1 byte */
839 			uni = kiconv_ja_jisx0201roman_to_ucs2[ic1];
840 			KICONV_JA_PUTU(uni);
841 		} else if (KICONV_JA_ISSJKANA(ic1)) { /* 0201 Kana; 1byte */
842 			uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)];
843 			KICONV_JA_PUTU(uni);
844 		} else if (KICONV_JA_ISSJKANJI1(ic1)) { /* 0208/UDC; 2bytes */
845 			KICONV_JA_NGET(ic2);
846 			if (KICONV_JA_ISSJKANJI2(ic2)) {
847 				ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
848 				if (ic2 >= 0x9f) {
849 					ic1++;
850 				}
851 				ic2 = kiconv_ja_sjtojis2[ic2];
852 				KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2);
853 				if (uni == KICONV_JA_NODEST) {
854 					index = ((ic1 - 0x21) * 94)
855 					    + (ic2 - 0x21);
856 					uni = kiconv_ja_jisx0208_to_ucs2[index];
857 				}
858 				if (uni == KICONV_JA_REPLACE)
859 					rv++;
860 				KICONV_JA_PUTU(uni);
861 			} else { /* 2nd byte check failed */
862 				KICONV_JA_RETERROR(EILSEQ)
863 				/* NOTREACHED */
864 			}
865 		} else if (KICONV_JA_ISSJSUPKANJI1(ic1)) { /* VDC, 2 bytes */
866 			KICONV_JA_NGET(ic2);
867 			if (KICONV_JA_ISSJKANJI2(ic2)) {
868 				ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
869 				if (ic2 >= 0x9f) {
870 					ic1++;
871 				}
872 				index = ((ic1 - 0x21) * 94)
873 				    + (kiconv_ja_sjtojis2[ic2] - 0x21);
874 				uni = kiconv_ja_jisx0212_to_ucs2[index];
875 				if (uni == KICONV_JA_REPLACE)
876 					rv++;
877 				KICONV_JA_PUTU(uni);
878 			} else { /* 2nd byte check failed */
879 				KICONV_JA_RETERROR(EILSEQ)
880 			}
881 		} else if (KICONV_JA_ISSJIBM(ic1) || /* Extended IBM area */
882 		    KICONV_JA_ISSJNECIBM(ic1)) { /* NEC/IBM area */
883 			/*
884 			 * We need a special treatment for each codes.
885 			 * By adding some offset number for them, we
886 			 * can process them as the same way of that of
887 			 * extended IBM chars.
888 			 */
889 			KICONV_JA_NGET(ic2);
890 			if (KICONV_JA_ISSJKANJI2(ic2)) {
891 				ushort_t dest, upper, lower;
892 				dest = (ic1 << 8) + ic2;
893 				if ((0xed40 <= dest) && (dest <= 0xeffc)) {
894 					KICONV_JA_REMAP_NEC(dest);
895 					if (dest == 0xffff) {
896 						KICONV_JA_RETERROR(EILSEQ)
897 					}
898 				}
899 				/*
900 				 * XXX: 0xfa54 and 0xfa5b must be mapped
901 				 *	to JIS0208 area. Therefore we
902 				 *	have to do special treatment.
903 				 */
904 				if ((dest == 0xfa54) || (dest == 0xfa5b)) {
905 					if (dest == 0xfa54) {
906 						upper = 0x22;
907 						lower = 0x4c;
908 					} else {
909 						upper = 0x22;
910 						lower = 0x68;
911 					}
912 					KICONV_JA_CNV_JISMS_TO_U2(id, uni,
913 					    upper, lower);
914 					if (uni == KICONV_JA_NODEST) {
915 						index = (uint_t)((upper - 0x21)
916 						    * 94 + (lower - 0x21));
917 						uni = kiconv_ja_jisx0208_to_ucs2
918 						    [index];
919 					}
920 					if (uni == KICONV_JA_REPLACE)
921 						rv++;
922 					KICONV_JA_PUTU(uni);
923 				} else {
924 					dest = dest - 0xfa40 -
925 					    (((dest>>8) - 0xfa) * 0x40);
926 					dest = kiconv_ja_sjtoibmext[dest];
927 					if (dest == 0xffff) {
928 						KICONV_JA_RETERROR(EILSEQ)
929 					}
930 					upper = (dest >> 8) & KICONV_JA_CMASK;
931 					lower = dest & KICONV_JA_CMASK;
932 					KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni,
933 					    upper, lower);
934 					if (uni == KICONV_JA_NODEST) {
935 						index = (uint_t)((upper - 0x21)
936 						    * 94 + (lower - 0x21));
937 						uni = kiconv_ja_jisx0212_to_ucs2
938 						    [index];
939 					}
940 					if (uni == KICONV_JA_REPLACE)
941 						rv++;
942 					KICONV_JA_PUTU(uni);
943 				}
944 			} else { /* 2nd byte check failed */
945 				KICONV_JA_RETERROR(EILSEQ)
946 			}
947 		} else if ((0xeb <= ic1) && (ic1 <= 0xec)) {
948 		/*
949 		 * Based on the draft convention of OSF-JVC CDEWG,
950 		 * characters in this area will be mapped to
951 		 * "CHIKAN-MOJI." (convertible character)
952 		 * We use U+FFFD in this case.
953 		 */
954 			KICONV_JA_NGET(ic2);
955 			if (KICONV_JA_ISSJKANJI2(ic2)) {
956 				uni = 0xfffd;
957 				KICONV_JA_PUTU(uni);
958 			} else { /* 2nd byte check failed */
959 				KICONV_JA_RETERROR(EILSEQ)
960 			}
961 		} else { /* 1st byte check failed */
962 			KICONV_JA_RETERROR(EILSEQ)
963 		}
964 
965 		/*
966 		 * One character successfully converted so update
967 		 * values outside of this function's stack.
968 		 */
969 		*inbuf = (char *)ip;
970 		*inbytesleft = ileft;
971 		*outbuf = op;
972 		*outbytesleft = oleft;
973 	}
974 
975 ret:
976 	return (rv);
977 }
978 
979 /*
980  * _kiconv_ja_lookuptbl()
981  * Return the index number if its index-ed number
982  * is the same as dest value.
983  */
984 static ushort_t
985 _kiconv_ja_lookuptbl(ushort_t dest)
986 {
987 	ushort_t tmp;
988 	int i;
989 	int sz = (sizeof (kiconv_ja_sjtoibmext) /
990 	    sizeof (kiconv_ja_sjtoibmext[0]));
991 
992 	for (i = 0; i < sz; i++) {
993 		tmp = (kiconv_ja_sjtoibmext[i] & 0x7f7f);
994 		if (tmp == dest)
995 			return ((i + 0xfa40 + ((i / 0xc0) * 0x40)));
996 	}
997 	return (0x3f);
998 }
999 
1000 static size_t
1001 _do_kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
1002 		char **outbuf, size_t *outbytesleft, int *errno)
1003 {
1004 	uchar_t	ic;
1005 	size_t		rv = 0;
1006 	uint_t		ucs4;
1007 	ushort_t	euc16;
1008 	ushort_t	dest;
1009 
1010 	uchar_t	*ip;
1011 	size_t		ileft;
1012 	char		*op;
1013 	size_t		oleft;
1014 	size_t		read_len;
1015 
1016 	size_t		id = ((kiconv_state_t)kcd)->id;
1017 
1018 	if ((inbuf == NULL) || (*inbuf == NULL)) {
1019 		return (0);
1020 	}
1021 
1022 	ip = (uchar_t *)*inbuf;
1023 	ileft = *inbytesleft;
1024 	op = *outbuf;
1025 	oleft = *outbytesleft;
1026 
1027 	KICONV_JA_CHECK_UTF8_BOM(ip, ileft);
1028 
1029 	while (ileft != 0) {
1030 		KICONV_JA_GETU(&ucs4, 0);
1031 
1032 		if (ucs4 > 0xffff) {
1033 			/* non-BMP */
1034 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1035 			rv++;
1036 			goto next;
1037 		}
1038 
1039 		KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
1040 		if (euc16 == KICONV_JA_NODEST) {
1041 			euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
1042 		}
1043 		if (euc16 == KICONV_JA_NODEST) {
1044 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1045 			rv++;
1046 			goto next;
1047 		}
1048 
1049 		switch (euc16 & 0x8080) {
1050 		case 0x0000:	/* CS0 */
1051 			if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) {
1052 				KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1053 				rv++;
1054 			} else {
1055 				ic = (uchar_t)euc16;
1056 				KICONV_JA_NPUT(ic);
1057 			}
1058 			break;
1059 		case 0x8080:	/* CS1 */
1060 			ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
1061 			KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]);
1062 			/*
1063 			 * for even number row (Ku), add 0x80 to
1064 			 * look latter half of kiconv_ja_jistosj2[] array
1065 			 */
1066 			ic = (uchar_t)((euc16 & KICONV_JA_CMASK)
1067 			    + (((ic % 2) == 0) ? 0x80 : 0x00));
1068 			KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
1069 			break;
1070 		case 0x0080:	/* CS2 */
1071 			ic = (uchar_t)euc16;
1072 			KICONV_JA_NPUT(ic);
1073 			break;
1074 		case 0x8000:	/* CS3 */
1075 			ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
1076 			if (euc16 == 0xa271) {
1077 				/* NUMERO SIGN */
1078 				KICONV_JA_NPUT(0x87);
1079 				KICONV_JA_NPUT(0x82);
1080 			} else if (ic < 0x75) { /* check if IBM VDC */
1081 				dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f);
1082 				if (dest == 0xffff) {
1083 					KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1084 				} else {
1085 					/* avoid putting NUL ('\0') */
1086 					if (dest > 0xff) {
1087 						KICONV_JA_NPUT(
1088 						    (dest >> 8) & 0xff);
1089 						KICONV_JA_NPUT(dest & 0xff);
1090 					} else {
1091 						KICONV_JA_NPUT(dest & 0xff);
1092 					}
1093 				}
1094 			} else {
1095 				KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]);
1096 				/*
1097 				 * for even number row (Ku), add 0x80 to
1098 				 * look latter half of kiconv_ja_jistosj2[]
1099 				 */
1100 				ic = (ushort_t)((euc16 & KICONV_JA_CMASK)
1101 				    + (((ic % 2) == 0) ? 0x80 : 0x00));
1102 				KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
1103 			}
1104 			break;
1105 		}
1106 
1107 next:
1108 		/*
1109 		 * One character successfully converted so update
1110 		 * values outside of this function's stack.
1111 		 */
1112 		*inbuf = (char *)ip;
1113 		*inbytesleft = ileft;
1114 		*outbuf = op;
1115 		*outbytesleft = oleft;
1116 	}
1117 
1118 ret:
1119 	return (rv);
1120 }
1121 
1122 static size_t
1123 _do_kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
1124 	size_t *outbytesleft, int flag, int *errno, uint8_t id)
1125 {
1126 	uint_t		uni;		/* UTF-32 */
1127 	uint_t		index;		/* index for table lookup */
1128 	uchar_t		ic1, ic2;	/* 1st and 2nd bytes of a char */
1129 	size_t		rv = 0;		/* return value of this function */
1130 
1131 	uchar_t	*ip;
1132 	size_t		ileft;
1133 	char		*op;
1134 	size_t		oleft;
1135 
1136 	boolean_t do_not_ignore_null;
1137 
1138 	if ((inbuf == NULL) || (*inbuf == NULL)) {
1139 		return (0);
1140 	}
1141 
1142 	ip = (uchar_t *)inbuf;
1143 	ileft = *inbytesleft;
1144 	op = outbuf;
1145 	oleft = *outbytesleft;
1146 
1147 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
1148 
1149 	while (ileft != 0) {
1150 		KICONV_JA_NGET(ic1); 			/* get 1st byte */
1151 
1152 		if (KICONV_JA_ISASC((int)ic1)) {	/* ASCII; 1 byte */
1153 			if (ic1 == '\0' && do_not_ignore_null) {
1154 				return (0);
1155 			}
1156 			uni = kiconv_ja_jisx0201roman_to_ucs2[ic1];
1157 			KICONV_JA_PUTU(uni);
1158 		} else if (KICONV_JA_ISSJKANA(ic1)) {
1159 			/* JIS X 0201 Kana; 1 byte */
1160 			uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)];
1161 			KICONV_JA_PUTU(uni);
1162 		} else if (KICONV_JA_ISSJKANJI1(ic1)) {
1163 			/* JIS X 0208 or UDC; 2 bytes */
1164 			if (flag & KICONV_REPLACE_INVALID) {
1165 				KICONV_JA_NGET_REP_FR_MB(ic2);
1166 			} else {
1167 				KICONV_JA_NGET(ic2);
1168 			}
1169 			if (KICONV_JA_ISSJKANJI2(ic2)) {
1170 				ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
1171 				if (ic2 >= 0x9f) {
1172 					ic1++;
1173 				}
1174 				ic2 = kiconv_ja_sjtojis2[ic2];
1175 				KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2);
1176 				if (uni == KICONV_JA_NODEST) {
1177 					index = ((ic1 - 0x21) * 94)
1178 					    + (ic2 - 0x21);
1179 					uni = kiconv_ja_jisx0208_to_ucs2[index];
1180 				}
1181 				if (uni == KICONV_JA_REPLACE)
1182 					rv++;
1183 				KICONV_JA_PUTU(uni);
1184 			} else { /* 2nd byte check failed */
1185 				if (flag & KICONV_REPLACE_INVALID) {
1186 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
1187 					rv++;
1188 				} else {
1189 					KICONV_JA_RETERROR(EILSEQ)
1190 				}
1191 				/* NOTREACHED */
1192 			}
1193 		} else if (KICONV_JA_ISSJSUPKANJI1(ic1)) { /* VDC, 2 bytes */
1194 			if (flag & KICONV_REPLACE_INVALID) {
1195 				KICONV_JA_NGET_REP_FR_MB(ic2);
1196 			} else {
1197 				KICONV_JA_NGET(ic2);
1198 			}
1199 			if (KICONV_JA_ISSJKANJI2(ic2)) {
1200 				ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
1201 				if (ic2 >= 0x9f) {
1202 					ic1++;
1203 				}
1204 				index = ((ic1 - 0x21) * 94)
1205 				    + (kiconv_ja_sjtojis2[ic2] - 0x21);
1206 				uni = kiconv_ja_jisx0212_to_ucs2[index];
1207 				if (uni == KICONV_JA_REPLACE)
1208 					rv++;
1209 				KICONV_JA_PUTU(uni);
1210 			} else { /* 2nd byte check failed */
1211 				if (flag & KICONV_REPLACE_INVALID) {
1212 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
1213 					rv++;
1214 				} else {
1215 					KICONV_JA_RETERROR(EILSEQ)
1216 				}
1217 			}
1218 		} else if (KICONV_JA_ISSJIBM(ic1) || /* Extended IBM area */
1219 		    KICONV_JA_ISSJNECIBM(ic1)) { /* NEC/IBM area */
1220 			/*
1221 			 * We need a special treatment for each codes.
1222 			 * By adding some offset number for them, we
1223 			 * can process them as the same way of that of
1224 			 * extended IBM chars.
1225 			 */
1226 			if (flag & KICONV_REPLACE_INVALID) {
1227 				KICONV_JA_NGET_REP_FR_MB(ic2);
1228 			} else {
1229 				KICONV_JA_NGET(ic2);
1230 			}
1231 			if (KICONV_JA_ISSJKANJI2(ic2)) {
1232 				ushort_t dest, upper, lower;
1233 				dest = (ic1 << 8) + ic2;
1234 				if ((0xed40 <= dest) && (dest <= 0xeffc)) {
1235 					KICONV_JA_REMAP_NEC(dest);
1236 					if (dest == 0xffff) {
1237 						if (flag &
1238 						    KICONV_REPLACE_INVALID) {
1239 							KICONV_JA_PUTU(
1240 							    KICONV_JA_REPLACE);
1241 							rv++;
1242 						} else {
1243 							KICONV_JA_RETERROR(
1244 							    EILSEQ)
1245 						}
1246 					}
1247 				}
1248 				/*
1249 				 * XXX: 0xfa54 and 0xfa5b must be mapped
1250 				 *	to JIS0208 area. Therefore we
1251 				 *	have to do special treatment.
1252 				 */
1253 				if ((dest == 0xfa54) || (dest == 0xfa5b)) {
1254 					if (dest == 0xfa54) {
1255 						upper = 0x22;
1256 						lower = 0x4c;
1257 					} else {
1258 						upper = 0x22;
1259 						lower = 0x68;
1260 					}
1261 					KICONV_JA_CNV_JISMS_TO_U2(id, uni,
1262 					    upper, lower);
1263 					if (uni == KICONV_JA_NODEST) {
1264 						index = (uint_t)((upper - 0x21)
1265 						    * 94 + (lower - 0x21));
1266 						uni = kiconv_ja_jisx0208_to_ucs2
1267 						    [index];
1268 					}
1269 					if (uni == KICONV_JA_REPLACE)
1270 						rv++;
1271 					KICONV_JA_PUTU(uni);
1272 				} else {
1273 					dest = dest - 0xfa40 -
1274 					    (((dest>>8) - 0xfa) * 0x40);
1275 					dest = kiconv_ja_sjtoibmext[dest];
1276 					if (dest == 0xffff) {
1277 						if (flag &
1278 						    KICONV_REPLACE_INVALID) {
1279 							KICONV_JA_PUTU(
1280 							    KICONV_JA_REPLACE);
1281 							rv++;
1282 						} else {
1283 							KICONV_JA_RETERROR(
1284 							    EILSEQ)
1285 						}
1286 					}
1287 					upper = (dest >> 8) & KICONV_JA_CMASK;
1288 					lower = dest & KICONV_JA_CMASK;
1289 					KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni,
1290 					    upper, lower);
1291 					if (uni == KICONV_JA_NODEST) {
1292 						index = (uint_t)((upper - 0x21)
1293 						    * 94 + (lower - 0x21));
1294 						uni = kiconv_ja_jisx0212_to_ucs2
1295 						    [index];
1296 					}
1297 					if (uni == KICONV_JA_REPLACE)
1298 						rv++;
1299 					KICONV_JA_PUTU(uni);
1300 				}
1301 			} else { /* 2nd byte check failed */
1302 				if (flag & KICONV_REPLACE_INVALID) {
1303 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
1304 					rv++;
1305 				} else {
1306 					KICONV_JA_RETERROR(EILSEQ)
1307 				}
1308 			}
1309 		} else if ((0xeb <= ic1) && (ic1 <= 0xec)) {
1310 		/*
1311 		 * Based on the draft convention of OSF-JVC CDEWG,
1312 		 * characters in this area will be mapped to
1313 		 * "CHIKAN-MOJI." (convertible character)
1314 		 * We use U+FFFD in this case.
1315 		 */
1316 			if (flag & KICONV_REPLACE_INVALID) {
1317 				KICONV_JA_NGET_REP_FR_MB(ic2);
1318 			} else {
1319 				KICONV_JA_NGET(ic2);
1320 			}
1321 			if (KICONV_JA_ISSJKANJI2(ic2)) {
1322 				uni = 0xfffd;
1323 				KICONV_JA_PUTU(uni);
1324 			} else { /* 2nd byte check failed */
1325 				if (flag & KICONV_REPLACE_INVALID) {
1326 					KICONV_JA_PUTU(KICONV_JA_REPLACE);
1327 					rv++;
1328 				} else {
1329 					KICONV_JA_RETERROR(EILSEQ)
1330 				}
1331 			}
1332 		} else { /* 1st byte check failed */
1333 			if (flag & KICONV_REPLACE_INVALID) {
1334 				KICONV_JA_PUTU(KICONV_JA_REPLACE);
1335 				rv++;
1336 			} else {
1337 				KICONV_JA_RETERROR(EILSEQ)
1338 			}
1339 		}
1340 
1341 next:
1342 		/*
1343 		 * One character successfully converted so update
1344 		 * values outside of this function's stack.
1345 		 */
1346 		*inbytesleft = ileft;
1347 		*outbytesleft = oleft;
1348 	}
1349 
1350 ret:
1351 	return (rv);
1352 }
1353 
1354 static size_t
1355 _do_kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
1356 	size_t *outbytesleft, int flag, int *errno, uint8_t id)
1357 {
1358 	uchar_t		ic;
1359 	size_t		rv = 0;
1360 	uint_t		ucs4;
1361 	ushort_t	euc16;
1362 	ushort_t	dest;
1363 
1364 	uchar_t	*ip;
1365 	size_t		ileft;
1366 	char		*op;
1367 	size_t		oleft;
1368 	size_t		read_len;
1369 
1370 	boolean_t do_not_ignore_null;
1371 
1372 	if ((inbuf == NULL) || (*inbuf == NULL)) {
1373 		return (0);
1374 	}
1375 
1376 	ip = (uchar_t *)inbuf;
1377 	ileft = *inbytesleft;
1378 	op = outbuf;
1379 	oleft = *outbytesleft;
1380 
1381 	KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft);
1382 
1383 	do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
1384 
1385 	while (ileft != 0) {
1386 		KICONV_JA_GETU(&ucs4, flag);
1387 
1388 		if (ucs4 == 0x0 && do_not_ignore_null) {
1389 			return (0);
1390 		}
1391 
1392 		if (ucs4 > 0xffff) {
1393 			/* non-BMP */
1394 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1395 			rv++;
1396 			goto next;
1397 		}
1398 
1399 		KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
1400 		if (euc16 == KICONV_JA_NODEST) {
1401 			euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
1402 		}
1403 		if (euc16 == KICONV_JA_NODEST) {
1404 			KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1405 			rv++;
1406 			goto next;
1407 		}
1408 
1409 		switch (euc16 & 0x8080) {
1410 		case 0x0000:	/* CS0 */
1411 			if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) {
1412 				KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1413 				rv++;
1414 			} else {
1415 				ic = (uchar_t)euc16;
1416 				KICONV_JA_NPUT(ic);
1417 			}
1418 			break;
1419 		case 0x8080:	/* CS1 */
1420 			ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
1421 			KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]);
1422 			/*
1423 			 * for even number row (Ku), add 0x80 to
1424 			 * look latter half of kiconv_ja_jistosj2[] array
1425 			 */
1426 			ic = (uchar_t)((euc16 & KICONV_JA_CMASK)
1427 			    + (((ic % 2) == 0) ? 0x80 : 0x00));
1428 			KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
1429 			break;
1430 		case 0x0080:	/* CS2 */
1431 			ic = (uchar_t)euc16;
1432 			KICONV_JA_NPUT(ic);
1433 			break;
1434 		case 0x8000:	/* CS3 */
1435 			ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
1436 			if (euc16 == 0xa271) {
1437 				/* NUMERO SIGN */
1438 				KICONV_JA_NPUT(0x87);
1439 				KICONV_JA_NPUT(0x82);
1440 			} else if (ic < 0x75) { /* check if IBM VDC */
1441 				dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f);
1442 				if (dest == 0xffff) {
1443 					KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
1444 				} else {
1445 					/* avoid putting NUL ('\0') */
1446 					if (dest > 0xff) {
1447 						KICONV_JA_NPUT(
1448 						    (dest >> 8) & 0xff);
1449 						KICONV_JA_NPUT(dest & 0xff);
1450 					} else {
1451 						KICONV_JA_NPUT(dest & 0xff);
1452 					}
1453 				}
1454 			} else {
1455 				KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]);
1456 				/*
1457 				 * for even number row (Ku), add 0x80 to
1458 				 * look latter half of kiconv_ja_jistosj2[]
1459 				 */
1460 				ic = (ushort_t)((euc16 & KICONV_JA_CMASK)
1461 				    + (((ic % 2) == 0) ? 0x80 : 0x00));
1462 				KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
1463 			}
1464 			break;
1465 		}
1466 
1467 next:
1468 		/*
1469 		 * One character successfully converted so update
1470 		 * values outside of this function's stack.
1471 		 */
1472 		*inbytesleft = ileft;
1473 		*outbytesleft = oleft;
1474 	}
1475 
1476 ret:
1477 	return (rv);
1478 }
1479 
1480 static size_t
1481 kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
1482 		char **outbuf, size_t *outbytesleft, int *errno)
1483 {
1484 	if (! kcd || kcd == (void *)-1) {
1485 		*errno = EBADF;
1486 		return ((size_t)-1);
1487 	}
1488 
1489 	return (_do_kiconv_fr_sjis(kcd, inbuf, inbytesleft,
1490 	    outbuf, outbytesleft, errno));
1491 }
1492 
1493 static size_t
1494 kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
1495 		char **outbuf, size_t *outbytesleft, int *errno)
1496 {
1497 	if (! kcd || kcd == (void *)-1) {
1498 		*errno = EBADF;
1499 		return ((size_t)-1);
1500 	}
1501 
1502 	return (_do_kiconv_to_sjis(kcd, inbuf, inbytesleft,
1503 	    outbuf, outbytesleft, errno));
1504 }
1505 
1506 static size_t
1507 kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
1508 	size_t *outbytesleft, int flag, int *errno)
1509 {
1510 	return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf,
1511 	    outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS));
1512 }
1513 
1514 static size_t
1515 kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
1516 	size_t *outbytesleft, int flag, int *errno)
1517 {
1518 	return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf,
1519 	    outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS));
1520 }
1521 
1522 static size_t
1523 kiconvstr_fr_cp932(char *inbuf, size_t *inbytesleft, char *outbuf,
1524 	size_t *outbytesleft, int flag, int *errno)
1525 {
1526 	return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf,
1527 	    outbytesleft, flag, errno, KICONV_JA_TBLID_CP932));
1528 }
1529 
1530 static size_t
1531 kiconvstr_to_cp932(char *inbuf, size_t *inbytesleft, char *outbuf,
1532 	size_t *outbytesleft, int flag, int *errno)
1533 {
1534 	return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf,
1535 	    outbytesleft, flag, errno, KICONV_JA_TBLID_CP932));
1536 }
1537 
1538 static kiconv_ops_t kiconv_ja_ops_tbl[] = {
1539 	{
1540 		"eucjp", "utf-8", open_eucjp,
1541 		kiconv_to_eucjp, close_ja, kiconvstr_to_eucjp
1542 	},
1543 	{
1544 		"utf-8", "eucjp", open_eucjp,
1545 		kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjp
1546 	},
1547 	{
1548 		"eucjpms", "utf-8", open_eucjpms,
1549 		kiconv_to_eucjp, close_ja, kiconvstr_to_eucjpms
1550 	},
1551 	{
1552 		"utf-8", "eucjpms", open_eucjpms,
1553 		kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjpms
1554 	},
1555 	{
1556 		"sjis", "utf-8", open_sjis,
1557 		kiconv_to_sjis, close_ja, kiconvstr_to_sjis
1558 	},
1559 	{
1560 		"utf-8", "sjis", open_sjis,
1561 		kiconv_fr_sjis, close_ja, kiconvstr_fr_sjis
1562 	},
1563 	{
1564 		"cp932", "utf-8", open_cp932,
1565 		kiconv_to_sjis, close_ja, kiconvstr_to_cp932
1566 	},
1567 	{
1568 		"utf-8", "cp932", open_cp932,
1569 		kiconv_fr_sjis, close_ja, kiconvstr_fr_cp932
1570 	}
1571 };
1572 
1573 static char *kiconv_ja_aliases[] = {"932", "shiftjis", "pck"};
1574 static char *kiconv_ja_canonicals[] = {"cp932", "sjis", "sjis"};
1575 
1576 #define	KICONV_JA_MAX_JA_OPS \
1577 	(sizeof (kiconv_ja_ops_tbl) / sizeof (kiconv_ops_t))
1578 #define	KICONV_JA_MAX_JA_ALIAS \
1579 	(sizeof (kiconv_ja_aliases) / sizeof (char *))
1580 
1581 static kiconv_module_info_t kiconv_ja_info = {
1582 	"kiconv_ja",		/* module name */
1583 	KICONV_JA_MAX_JA_OPS,	/* number of conversion in kiconv_ja */
1584 	kiconv_ja_ops_tbl,	/* kiconv_ja ops table */
1585 	KICONV_JA_MAX_JA_ALIAS,	/* number of alias in kiconv_ja */
1586 	kiconv_ja_aliases,	/* kiconv_ja aliases */
1587 	kiconv_ja_canonicals,	/* kiconv_ja canonicals */
1588 	0
1589 };
1590 
1591 static struct modlkiconv modlkiconv_ja = {
1592 	&mod_kiconvops,
1593 	"kiconv module for Japanese",
1594 	&kiconv_ja_info
1595 };
1596 
1597 static struct modlinkage modlinkage = {
1598 	MODREV_1,
1599 	(void *)&modlkiconv_ja,
1600 	NULL
1601 };
1602 
1603 int
1604 _init(void)
1605 {
1606 	int err;
1607 
1608 	err = mod_install(&modlinkage);
1609 	if (err)
1610 		cmn_err(CE_WARN, "kiconv_ja: failed to load kernel module");
1611 
1612 	return (err);
1613 }
1614 
1615 int
1616 _info(struct modinfo *modinfop)
1617 {
1618 	return (mod_info(&modlinkage, modinfop));
1619 }
1620 
1621 int
1622 _fini(void)
1623 {
1624 	int err;
1625 
1626 	/*
1627 	 * If this module is being used, then, we cannot remove the module.
1628 	 * The following checking will catch pretty much all usual cases.
1629 	 *
1630 	 * Any remaining will be catached by the kiconv_unregister_module()
1631 	 * during mod_remove() at below.
1632 	 */
1633 	if (kiconv_module_ref_count(KICONV_MODULE_ID_JA))
1634 		return (EBUSY);
1635 
1636 	err = mod_remove(&modlinkage);
1637 	if (err)
1638 		cmn_err(CE_WARN, "kiconv_ja: failed to remove kernel module");
1639 
1640 	return (err);
1641 }
1642