1 /*
2  * "streamable kanji code filter and converter"
3  * Copyright (c) 1998-2002 HappySize, Inc. All rights reserved.
4  *
5  * LICENSE NOTICES
6  *
7  * This file is part of "streamable kanji code filter and converter",
8  * which is distributed under the terms of GNU Lesser General Public
9  * License (version 2) as published by the Free Software Foundation.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with "streamable kanji code filter and converter";
18  * if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19  * Suite 330, Boston, MA  02111-1307  USA
20  *
21  * The author of this file:
22  *
23  */
24 /*
25  * The source code included in this files was separated from mbfilter_sjis.c
26  * by rui hirokawa <hirokawa@php.net> on 15 aug 2011.
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include "mbfilter.h"
35 #include "mbfilter_sjis_2004.h"
36 
37 #include "unicode_table_jis2004.h"
38 #include "unicode_table_jis.h"
39 
40 extern const unsigned char mblen_table_sjis[];
41 
42 static int mbfl_filt_ident_sjis2004(int c, mbfl_identify_filter *filter);
43 
44 extern int mbfl_filt_ident_sjis(int c, mbfl_identify_filter *filter);
45 extern int mbfl_bisec_srch(int w, const unsigned short *tbl, int n);
46 extern int mbfl_bisec_srch2(int w, const unsigned short tbl[], int n);
47 
48 static const char *mbfl_encoding_sjis2004_aliases[] = {"SJIS2004","Shift_JIS-2004", NULL};
49 
50 const mbfl_encoding mbfl_encoding_sjis2004 = {
51 	mbfl_no_encoding_sjis2004,
52 	"SJIS-2004",
53 	"Shift_JIS",
54 	(const char *(*)[])&mbfl_encoding_sjis2004_aliases,
55 	mblen_table_sjis,
56 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE,
57 	&vtbl_sjis2004_wchar,
58 	&vtbl_wchar_sjis2004
59 };
60 
61 const struct mbfl_identify_vtbl vtbl_identify_sjis2004 = {
62 	mbfl_no_encoding_sjis2004,
63 	mbfl_filt_ident_common_ctor,
64 	mbfl_filt_ident_common_dtor,
65 	mbfl_filt_ident_sjis
66 };
67 
68 const struct mbfl_convert_vtbl vtbl_sjis2004_wchar = {
69 	mbfl_no_encoding_sjis2004,
70 	mbfl_no_encoding_wchar,
71 	mbfl_filt_conv_common_ctor,
72 	mbfl_filt_conv_common_dtor,
73 	mbfl_filt_conv_jis2004_wchar,
74 	mbfl_filt_conv_common_flush
75 };
76 
77 const struct mbfl_convert_vtbl vtbl_wchar_sjis2004 = {
78 	mbfl_no_encoding_wchar,
79 	mbfl_no_encoding_sjis2004,
80 	mbfl_filt_conv_common_ctor,
81 	mbfl_filt_conv_common_dtor,
82 	mbfl_filt_conv_wchar_jis2004,
83 	mbfl_filt_conv_jis2004_flush
84 };
85 
86 #define CK(statement)	do { if ((statement) < 0) return (-1); } while (0)
87 
88 #define SJIS_ENCODE(c1,c2,s1,s2)	\
89 		do {						\
90 			s1 = c1;				\
91 			s1--;					\
92 			s1 >>= 1;				\
93 			if ((c1) < 0x5f) {		\
94 				s1 += 0x71;			\
95 			} else {				\
96 				s1 += 0xb1;			\
97 			}						\
98 			s2 = c2;				\
99 			if ((c1) & 1) {			\
100 				if ((c2) < 0x60) {	\
101 					s2--;			\
102 				}					\
103 				s2 += 0x20;			\
104 			} else {				\
105 				s2 += 0x7e;			\
106 			}						\
107 		} while (0)
108 
109 #define SJIS_DECODE(c1,c2,s1,s2)	\
110 		do {						\
111 			s1 = c1;				\
112 			if (s1 < 0xa0) {		\
113 				s1 -= 0x81;			\
114 			} else {				\
115 				s1 -= 0xc1;			\
116 			}						\
117 			s1 <<= 1;				\
118 			s1 += 0x21;				\
119 			s2 = c2;				\
120 			if (s2 < 0x9f) {		\
121 				if (s2 < 0x7f) {	\
122 					s2++;			\
123 				}					\
124 				s2 -= 0x20;			\
125 			} else {				\
126 				s1++;				\
127 				s2 -= 0x7e;			\
128 			}						\
129 		} while (0)
130 
131 
132 /*
133  * JIS-2004 => wchar
134  */
135 int
mbfl_filt_conv_jis2004_wchar(int c,mbfl_convert_filter * filter)136 mbfl_filt_conv_jis2004_wchar(int c, mbfl_convert_filter *filter)
137 {
138 	int k;
139 	int c1, c2, s, s1 = 0, s2 = 0, w = 0, w1;
140 
141 retry:
142 	switch (filter->status & 0xf) {
143 	case 0:
144 		if (c >= 0 && c < 0x80) {	/* latin */
145 			if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
146 				CK((*filter->output_function)(c, filter->data));
147 			} else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
148 				if (c == 0x5c) {
149 					CK((*filter->output_function)(0x00a5, filter->data));
150 				} else if (c == 0x7e) {
151 					CK((*filter->output_function)(0x203e, filter->data));
152 				} else {
153 					CK((*filter->output_function)(c, filter->data));
154 				}
155 			} else { /* ISO-2022-JP-2004 */
156 				if (c == 0x1b) {
157 					filter->status += 6;
158 				} else if ((filter->status == 0x80 || filter->status == 0x90 || filter->status == 0xa0)
159 				   && c > 0x20 && c < 0x7f) {		/* kanji first char */
160 					filter->cache = c;
161 					if (filter->status == 0x90) {
162 						filter->status += 1; /* JIS X 0213 plane 1 */
163 					} else if (filter->status == 0xa0) {
164 						filter->status += 4; /* JIS X 0213 plane 2 */
165 					} else {
166 						filter->status += 5; /* JIS X 0208 */
167 					}
168 				} else {
169 					CK((*filter->output_function)(c, filter->data));
170 				}
171 			}
172 		} else {
173 			if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
174 				if (c > 0xa0 && c < 0xff) {	/* X 0213 plane 1 first char */
175 					filter->status = 1;
176 					filter->cache = c;
177 				} else if (c == 0x8e) {	/* kana first char */
178 					filter->status = 2;
179 				} else if (c == 0x8f) {	/* X 0213 plane 2 first char */
180 					filter->status = 3;
181 				} else {
182 					w = c & MBFL_WCSGROUP_MASK;
183 					w |= MBFL_WCSGROUP_THROUGH;
184 					CK((*filter->output_function)(w, filter->data));
185 				}
186 			} else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
187 				if (c > 0xa0 && c < 0xe0) {	/* kana */
188 					CK((*filter->output_function)(0xfec0 + c, filter->data));
189 				} else if (c > 0x80 && c < 0xfd && c != 0xa0) {	/* kanji first char */
190 					filter->status = 1;
191 					filter->cache = c;
192 				} else {
193 					w = c & MBFL_WCSGROUP_MASK;
194 					w |= MBFL_WCSGROUP_THROUGH;
195 					CK((*filter->output_function)(w, filter->data));
196 				}
197 			} else {
198 				w = c & MBFL_WCSGROUP_MASK;
199 				w |= MBFL_WCSGROUP_THROUGH;
200 				CK((*filter->output_function)(w, filter->data));
201 			}
202 		}
203 		break;
204 
205 	case 1:		/* kanji second char */
206 		filter->status &= ~0xf;
207 		c1 = filter->cache;
208 
209 		if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
210 			if (c > 0xa0 && c < 0xff) {
211 				s1 = c1 - 0x80;
212 				s2 = c - 0x80;
213 			}
214 		} else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
215 			if (c >= 0x40 && c <= 0xfc && c != 0x7f) {
216 				SJIS_DECODE(c1, c, s1, s2);
217 			}
218 		} else {
219 			s1 = c1;
220 			s2 = c;
221 		}
222 		w1 = (s1 << 8) | s2;
223 
224 		if (w1 >= 0x2121) {
225 			/* conversion for combining characters */
226 			if ((w1 >= 0x2477 && w1 <= 0x2479) || (w1 >= 0x2479 && w1 <= 0x247B) ||
227 				(w1 >= 0x2577 && w1 <= 0x257E) || w1 == 0x2678 || w1 == 0x2B44 ||
228 				(w1 >= 0x2B48 && w1 <= 0x2B4F) || (w1 >= 0x2B65 && w1 <= 0x2B66)) {
229 				k = mbfl_bisec_srch2(w1, jisx0213_u2_key, jisx0213_u2_tbl_len);
230 				if (k >= 0) {
231 					w = jisx0213_u2_tbl[2*k];
232 					CK((*filter->output_function)(w, filter->data));
233 					w = jisx0213_u2_tbl[2*k+1];
234 				}
235 			}
236 
237 			/* conversion for BMP  */
238 			if (w <= 0) {
239 				w1 = (s1 - 0x21)*94 + s2 - 0x21;
240 				if (w1 >= 0 && w1 < jisx0213_ucs_table_size) {
241 					w = jisx0213_ucs_table[w1];
242 				}
243 			}
244 
245 			/* conversion for CJK Unified Ideographs ext.B (U+2XXXX) */
246 			if (w <= 0) {
247 				w1 = (s1 << 8) | s2;
248 				k = mbfl_bisec_srch2(w1, jisx0213_jis_u5_key, jisx0213_u5_tbl_len);
249 				if (k >= 0) {
250 					w = jisx0213_jis_u5_tbl[k] + 0x20000;
251 				}
252 			}
253 
254 			if (w <= 0) {
255 				if (s1 < 0x7f && s2 < 0x7f) {
256 					w = (s1 << 8) | s2;
257 					w &= MBFL_WCSPLANE_MASK;
258 					w |= MBFL_WCSPLANE_JIS0213;
259 				} else {
260 					w = (c1 << 8) | c;
261 					w &= MBFL_WCSGROUP_MASK;
262 					w |= MBFL_WCSGROUP_THROUGH;
263 				}
264 			}
265 			CK((*filter->output_function)(w, filter->data));
266 		} else if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
267 			CK((*filter->output_function)(c, filter->data));
268 		} else {
269 			w = (c1 << 8) | c;
270 			w &= MBFL_WCSGROUP_MASK;
271 			w |= MBFL_WCSGROUP_THROUGH;
272 			CK((*filter->output_function)(w, filter->data));
273 		}
274 		break;
275 
276 	case 2:	/* got 0x8e : EUC-JP-2004 kana */
277 		filter->status = 0;
278 		if (c > 0xa0 && c < 0xe0) {
279 			w = 0xfec0 + c;
280 			CK((*filter->output_function)(w, filter->data));
281 		} else if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
282 			CK((*filter->output_function)(c, filter->data));
283 		} else {
284 			w = 0x8e00 | c;
285 			w &= MBFL_WCSGROUP_MASK;
286 			w |= MBFL_WCSGROUP_THROUGH;
287 			CK((*filter->output_function)(w, filter->data));
288 		}
289 		break;
290 
291 	case 3:	/* X 0213 plane 2 first char : EUC-JP-2004 (0x8f), ISO-2022-JP-2004 */
292 		if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
293 			CK((*filter->output_function)(c, filter->data));
294 			filter->status = 0;
295 		} else {
296 			if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
297 				s1 = c - 0x80;
298 			} else {
299 				s1 = c;
300 			}
301 			if (s1 > 0x20 && s1 < 0x80) {
302 				filter->cache = s1;
303 				filter->status++;
304 			} else {
305 				if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
306 					w = c | 0x8f00;
307 					w &= MBFL_WCSGROUP_MASK;
308 					w |= MBFL_WCSGROUP_THROUGH;
309 				} else {
310 					w = c & 0x7f;
311 					w &= MBFL_WCSPLANE_MASK;
312 					w |= MBFL_WCSPLANE_JIS0213;
313 				}
314 				CK((*filter->output_function)(w, filter->data));
315 			}
316 		}
317 		break;
318 
319 	case 4:	/* X 0213 plane 2 second char : EUC-JP-2004, ISO-2022-JP-2004 */
320 
321 		filter->status &= ~0xf;
322 		c1 = filter->cache;
323 		if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
324 			c2 = c - 0x80;
325 		} else {
326 			c2 = c;
327 		}
328 		s1 = c1 - 0x21;
329 		s2 = c2 - 0x21;
330 
331 		if (((s1 >= 0 && s1 <= 4 && s1 != 1) || s1 == 7 || (s1 >= 11 && s1 <= 14) ||
332 			(s1 >= 77 && s1 < 94)) && s2 >= 0 && s2 < 94) {
333 			/* calc offset from ku */
334 			for (k = 0; k < jisx0213_p2_ofst_len; k++) {
335 				if (s1 == jisx0213_p2_ofst[k]-1) {
336 					break;
337 				}
338 			}
339 			k = k - (jisx0213_p2_ofst[k]-1);
340 
341 			/* check for japanese chars in BMP */
342 			s = (s1 + 94 + k)*94 + s2;
343 			if (s >= 0 && s < jisx0213_ucs_table_size) {
344 				w = jisx0213_ucs_table[s];
345 			} else {
346 				w = 0;
347 			}
348 
349 			/* check for japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */
350 			if (w <= 0) {
351 				w1 = ((c1 + k + 94) << 8) | c2;
352 				k = mbfl_bisec_srch2(w1, jisx0213_jis_u5_key, jisx0213_u5_tbl_len);
353 				if (k >= 0) {
354 					w = jisx0213_jis_u5_tbl[k] + 0x20000;
355 				}
356 			}
357 
358 			if (w <= 0) {
359 				w = ((c1 & 0x7f) << 8) | (c2 & 0x7f);
360 				w &= MBFL_WCSPLANE_MASK;
361 				w |= MBFL_WCSPLANE_JIS0213;
362 			}
363 
364 			CK((*filter->output_function)(w, filter->data));
365 		} else if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
366 			CK((*filter->output_function)(c, filter->data));
367 		} else {
368 			if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
369 				w = (c1 << 8) | c | 0x8f0000;
370 				w &= MBFL_WCSGROUP_MASK;
371 				w |= MBFL_WCSGROUP_THROUGH;
372 			} else {
373 				w = ((c1 & 0x7f) << 8) | (c2 & 0x7f);
374 				w &= MBFL_WCSPLANE_MASK;
375 				w |= MBFL_WCSPLANE_JIS0213;
376 			}
377 			CK((*filter->output_function)(w, filter->data));
378 		}
379 
380 		break;
381 
382 	case 5:	/* X 0208 : ISO-2022-JP-2004 */
383 		filter->status &= ~0xf;
384 		c1 = filter->cache;
385 		if (c > 0x20 && c < 0x7f) {
386 			s = (c1 - 0x21)*94 + c - 0x21;
387 			if (s >= 0 && s < jisx0208_ucs_table_size) {
388 				w = jisx0208_ucs_table[s];
389 			}
390 		}
391 		if (w <= 0) {
392 			w = (c1 << 8) | c;
393 			w &= MBFL_WCSPLANE_MASK;
394 			w |= MBFL_WCSPLANE_JIS0208;
395 		}
396 		CK((*filter->output_function)(w, filter->data));
397 		break;
398 
399 	/* ESC : ISO-2022-JP-2004 */
400 /*	case 0x06:	*/
401 /*	case 0x16:	*/
402 /*	case 0x26:	*/
403 /*	case 0x86:	*/
404 /*	case 0x96:	*/
405 /*	case 0xa6:	*/
406 	case 6:
407 		if (c == 0x24) {		/* '$' */
408 			filter->status++;
409 		} else if (c == 0x28) {		/* '(' */
410 			filter->status += 3;
411 		} else {
412 			filter->status &= ~0xf;
413 			CK((*filter->output_function)(0x1b, filter->data));
414 			goto retry;
415 		}
416 		break;
417 
418 	/* ESC $ : ISO-2022-JP-2004 */
419 /*	case 0x07:	*/
420 /*	case 0x17:	*/
421 /*	case 0x27:	*/
422 /*	case 0x87:	*/
423 /*	case 0x97:	*/
424 /*	case 0xa7:	*/
425 	case 7:
426 		if (c == 0x42) {	/* 'B' -> JIS X 0208-1983 */
427 			filter->status = 0x80;
428 		} else if (c == 0x28) {			/* '(' */
429 			filter->status++;
430 		} else {
431 			filter->status &= ~0xf;
432 			CK((*filter->output_function)(0x1b, filter->data));
433 			CK((*filter->output_function)(0x24, filter->data));
434 			goto retry;
435 		}
436 		break;
437 
438 		break;
439 
440 	/* ESC $ ( : ISO-2022-JP-2004 */
441 /*	case 0x08:	*/
442 /*	case 0x18:	*/
443 /*	case 0x28:	*/
444 /*	case 0x88:	*/
445 /*	case 0x98:	*/
446 /*	case 0xa8:	*/
447 	case 8:
448 		if (c == 0x51) {	/* JIS X 0213 plane 1 */
449 			filter->status = 0x90;
450 		} else if (c == 0x50) {			/* JIS X 0213 plane 2 */
451 			filter->status = 0xa0;
452 		} else {
453 			filter->status &= ~0xf;
454 			CK((*filter->output_function)(0x1b, filter->data));
455 			CK((*filter->output_function)(0x24, filter->data));
456 			CK((*filter->output_function)(0x28, filter->data));
457 			goto retry;
458 		}
459 		break;
460 
461 	/* ESC ( : ISO-2022-JP-2004 */
462 /*	case 0x09:	*/
463 /*	case 0x19:	*/
464 /*	case 0x29:	*/
465 /*	case 0x89:	*/
466 /*	case 0x99:	*/
467 	case 9:
468 		if (c == 0x42) {		/* 'B' : ASCII */
469 			filter->status = 0;
470 		} else {
471 			filter->status &= ~0xf;
472 			CK((*filter->output_function)(0x1b, filter->data));
473 			CK((*filter->output_function)(0x28, filter->data));
474 			goto retry;
475 		}
476 		break;
477 
478 	default:
479 		filter->status = 0;
480 		break;
481 	}
482 
483 	return c;
484 }
485 
486 int
mbfl_filt_conv_wchar_jis2004(int c,mbfl_convert_filter * filter)487 mbfl_filt_conv_wchar_jis2004(int c, mbfl_convert_filter *filter) {
488 	int k;
489 	int c1, c2, s1 = 0, s2;
490 
491 retry:
492 
493 	/* check for 1st char of combining characters */
494 	if ((filter->status & 0xf)== 0 && (
495 			c == 0x00E6 ||
496 			(c >= 0x0254 && c <= 0x02E9) ||
497 			(c >= 0x304B && c <= 0x3053) ||
498 			(c >= 0x30AB && c <= 0x30C8) ||
499 			c == 0x31F7)) {
500 		for (k=0;k<jisx0213_u2_tbl_len;k++) {
501 			if (c == jisx0213_u2_tbl[2*k]) {
502 				filter->status++;
503 				filter->cache = k;
504 				return c;
505 			}
506 		}
507 	}
508 
509 	/* check for 2nd char of combining characters */
510 	if ((filter->status & 0xf) == 1 &&
511 		filter->cache >= 0 && filter->cache <= jisx0213_u2_tbl_len) {
512 		k = filter->cache;
513 		filter->status &= ~0xf;
514 		filter->cache = 0;
515 
516 		c1 = jisx0213_u2_tbl[2*k];
517 		if ((c1 == 0x0254 || c1 == 0x028C || c1 == 0x0259 || c1 == 0x025A)
518 			&& c == 0x0301) {
519 			k++;
520 		}
521 		if (c == jisx0213_u2_tbl[2*k+1]) {
522 			s1 = jisx0213_u2_key[k];
523 		} else { /* fallback */
524 			s1 = jisx0213_u2_fb_tbl[k];
525 
526 			if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
527 				c1 = (s1 >> 8) & 0xff;
528 				c2 = s1 & 0xff;
529 				SJIS_ENCODE(c1, c2, s1, s2);
530 			} else if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
531 				s2 = (s1 & 0xff) + 0x80;
532 				s1 = ((s1 >> 8) & 0xff) + 0x80;
533 			} else {
534 				if (filter->status != 0x200) {
535 					CK((*filter->output_function)(0x1b, filter->data));
536 					CK((*filter->output_function)(0x24, filter->data));
537 					CK((*filter->output_function)(0x28, filter->data));
538 					CK((*filter->output_function)(0x51, filter->data));
539 				}
540 				filter->status = 0x200;
541 
542 				s2 = s1 & 0x7f;
543 				s1 = (s1 >> 8) & 0x7f;
544 			}
545 
546 			CK((*filter->output_function)(s1, filter->data));
547 			CK((*filter->output_function)(s2, filter->data));
548 			goto retry;
549 		}
550 	}
551 
552 	/* check for major japanese chars: U+4E00 - U+9FFF */
553 	if (s1 <= 0) {
554 		for (k=0; k < uni2jis_tbl_len ;k++) {
555 			if (c >= uni2jis_tbl_range[k][0] && c <= uni2jis_tbl_range[k][1]) {
556 				s1 = uni2jis_tbl[k][c-uni2jis_tbl_range[k][0]];
557 				break;
558 			}
559 		}
560 	}
561 
562 	/* check for japanese chars in compressed mapping area: U+1E00 - U+4DBF */
563 	if (s1 <= 0 && c >= ucs_c1_jisx0213_min && c <= ucs_c1_jisx0213_max) {
564 		k = mbfl_bisec_srch(c, ucs_c1_jisx0213_tbl, ucs_c1_jisx0213_tbl_len);
565 		if (k >= 0) {
566 			s1 = ucs_c1_jisx0213_ofst[k] + c - ucs_c1_jisx0213_tbl[2*k];
567 		}
568 	}
569 
570 	/* check for japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */
571 	if (s1 <= 0 && c >= jisx0213_u5_tbl_min && c <= jisx0213_u5_tbl_max) {
572 		k = mbfl_bisec_srch2(c - 0x20000, jisx0213_u5_jis_key, jisx0213_u5_tbl_len);
573 		if (k >= 0) {
574 			s1 = jisx0213_u5_jis_tbl[k];
575 		}
576 	}
577 
578 	if (s1 <= 0) {
579 		/* CJK Compatibility Forms: U+FE30 - U+FE4F */
580 		if (c == 0xfe45) {
581 			s1 = 0x233e;
582 		} else if (c == 0xfe46) {
583 			s1 = 0x233d;
584 		} else if (c >= 0xf91d && c <= 0xf9dc) {
585 			/* CJK Compatibility Ideographs: U+F900 - U+F92A */
586 			k = mbfl_bisec_srch2(c, ucs_r2b_jisx0213_cmap_key, ucs_r2b_jisx0213_cmap_len);
587 			if (k >= 0) {
588 				s1 = ucs_r2b_jisx0213_cmap_val[k];
589 			}
590 		}
591 	}
592 
593 	if (s1 <= 0) {
594 		c1 = c & ~MBFL_WCSPLANE_MASK;
595 		if (c1 == MBFL_WCSPLANE_JIS0213) {
596 			s1 = c & MBFL_WCSPLANE_MASK;
597 		}
598 		if (c == 0) {
599 			s1 = 0;
600 		} else if (s1 <= 0) {
601 			s1 = -1;
602 		}
603 	} else if (s1 >= 0x9980) {
604 		s1 = -1;
605 	}
606 
607 	if (s1 >= 0) {
608 		if (s1 < 0x80) { /* ASCII */
609 			if (filter->to->no_encoding == mbfl_no_encoding_2022jp_2004 &&
610 				(filter->status & 0xff00) != 0) {
611 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
612 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
613 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
614 			}
615 			filter->status = 0;
616 			CK((*filter->output_function)(s1, filter->data));
617 		} else if (s1 < 0x100) { /* latin or kana */
618 			if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
619 				CK((*filter->output_function)(0x8e, filter->data));
620 			}
621 			CK((*filter->output_function)(s1, filter->data));
622 		} else if (s1 < 0x7f00) { /* X 0213 plane 1 */
623 			if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
624 				c1 = (s1 >> 8) & 0xff;
625 				c2 = s1 & 0xff;
626 				SJIS_ENCODE(c1, c2, s1, s2);
627 			} else if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
628 				s2 = (s1 & 0xff) + 0x80;
629 				s1 = ((s1 >> 8) & 0xff) + 0x80;
630 			} else {
631 				if ((filter->status & 0xff00) != 0x200) {
632 					CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
633 					CK((*filter->output_function)(0x24, filter->data));		/* '$' */
634 					CK((*filter->output_function)(0x28, filter->data));		/* '(' */
635 					CK((*filter->output_function)(0x51, filter->data));		/* 'Q' */
636 				}
637 				filter->status = 0x200;
638 				s2 = s1 & 0xff;
639 				s1 = (s1 >> 8) & 0xff;
640 			}
641 			CK((*filter->output_function)(s1, filter->data));
642 			CK((*filter->output_function)(s2, filter->data));
643 		} else { /* X 0213 plane 2 */
644 			if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
645 				c1 = (s1 >> 8) & 0xff;
646 				c2 = s1 & 0xff;
647 				SJIS_ENCODE(c1, c2, s1, s2);
648 			} else {
649 				s2 = s1 & 0xff;
650 				k = ((s1 >> 8) & 0xff) - 0x7f;
651 				if (k >= 0 && k < jisx0213_p2_ofst_len) {
652 					s1  = jisx0213_p2_ofst[k] - 1 + 0x21;
653 				}
654 				if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
655 					s2 |= 0x80;
656 					s1 |= 0x80;
657 					CK((*filter->output_function)(0x8f, filter->data));
658 				} else {
659 					if ((filter->status & 0xff00) != 0x200) {
660 						CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
661 						CK((*filter->output_function)(0x24, filter->data));		/* '$' */
662 						CK((*filter->output_function)(0x28, filter->data));		/* '(' */
663 						CK((*filter->output_function)(0x50, filter->data));		/* 'P' */
664 					}
665 					filter->status = 0x200;
666 				}
667 			}
668 
669 			CK((*filter->output_function)(s1, filter->data));
670 			CK((*filter->output_function)(s2, filter->data));
671 		}
672 	} else {
673 		if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
674 			CK(mbfl_filt_conv_illegal_output(c, filter));
675 		}
676 	}
677 
678 	return c;
679 }
680 
681 int
mbfl_filt_conv_jis2004_flush(mbfl_convert_filter * filter)682 mbfl_filt_conv_jis2004_flush(mbfl_convert_filter *filter)
683 {
684 	int k, c1, c2, s1, s2;
685 
686 	k = filter->cache;
687 	filter->cache = 0;
688 
689 	if (filter->status == 1 && k >= 0 && k <= jisx0213_u2_tbl_len) {
690 		s1 = jisx0213_u2_fb_tbl[k];
691 
692 		if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
693 			c1 = (s1 >> 8) & 0xff;
694 			c2 = s1 & 0xff;
695 			SJIS_ENCODE(c1, c2, s1, s2);
696 		} else if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
697 			s2 = (s1 & 0xff) | 0x80;
698 			s1 = ((s1 >> 8) & 0xff) | 0x80;
699 		} else {
700 			s2 = s1 & 0x7f;
701 			s1 = (s1 >> 8) & 0x7f;
702 			if ((filter->status & 0xff00) != 0x200) {
703 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
704 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
705 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
706 				CK((*filter->output_function)(0x51, filter->data));		/* 'Q' */
707 			}
708 			filter->status = 0x200;
709 		}
710 
711 		CK((*filter->output_function)(s1, filter->data));
712 		CK((*filter->output_function)(s2, filter->data));
713 	}
714 
715 	/* back to latin */
716 	if ((filter->status & 0xff00) != 0) {
717 		CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
718 		CK((*filter->output_function)(0x28, filter->data));		/* '(' */
719 		CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
720 	}
721 
722 	filter->status = 0;
723 
724 	if (filter->flush_function != NULL) {
725 		return (*filter->flush_function)(filter->data);
726 	}
727 
728 	return 0;
729 }
730