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_ja.c
26  * by moriyoshi koizumi <moriyoshi@php.net> on 4 dec 2002.
27  *
28  */
29 
30 #include "mbfilter.h"
31 #include "mbfilter_jis.h"
32 
33 #include "unicode_table_cp932_ext.h"
34 #include "unicode_table_jis.h"
35 
36 static int mbfl_filt_ident_jis(int c, mbfl_identify_filter *filter);
37 static int mbfl_filt_ident_2022jp(int c, mbfl_identify_filter *filter);
38 
39 const mbfl_encoding mbfl_encoding_jis = {
40 	mbfl_no_encoding_jis,
41 	"JIS",
42 	"ISO-2022-JP",
43 	NULL,
44 	NULL,
45 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE,
46 	&vtbl_jis_wchar,
47 	&vtbl_wchar_jis
48 };
49 
50 const mbfl_encoding mbfl_encoding_2022jp = {
51 	mbfl_no_encoding_2022jp,
52 	"ISO-2022-JP",
53 	"ISO-2022-JP",
54 	NULL,
55 	NULL,
56 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE,
57 	&vtbl_2022jp_wchar,
58 	&vtbl_wchar_2022jp
59 };
60 
61 const struct mbfl_identify_vtbl vtbl_identify_jis = {
62 	mbfl_no_encoding_jis,
63 	mbfl_filt_ident_common_ctor,
64 	mbfl_filt_ident_jis
65 };
66 
67 const struct mbfl_identify_vtbl vtbl_identify_2022jp = {
68 	mbfl_no_encoding_2022jp,
69 	mbfl_filt_ident_common_ctor,
70 	mbfl_filt_ident_2022jp
71 };
72 
73 const struct mbfl_convert_vtbl vtbl_jis_wchar = {
74 	mbfl_no_encoding_jis,
75 	mbfl_no_encoding_wchar,
76 	mbfl_filt_conv_common_ctor,
77 	NULL,
78 	mbfl_filt_conv_jis_wchar,
79 	mbfl_filt_conv_common_flush,
80 	NULL,
81 };
82 
83 const struct mbfl_convert_vtbl vtbl_wchar_jis = {
84 	mbfl_no_encoding_wchar,
85 	mbfl_no_encoding_jis,
86 	mbfl_filt_conv_common_ctor,
87 	NULL,
88 	mbfl_filt_conv_wchar_jis,
89 	mbfl_filt_conv_any_jis_flush,
90 	NULL,
91 };
92 
93 const struct mbfl_convert_vtbl vtbl_2022jp_wchar = {
94 	mbfl_no_encoding_2022jp,
95 	mbfl_no_encoding_wchar,
96 	mbfl_filt_conv_common_ctor,
97 	NULL,
98 	mbfl_filt_conv_jis_wchar,
99 	mbfl_filt_conv_common_flush,
100 	NULL,
101 };
102 
103 const struct mbfl_convert_vtbl vtbl_wchar_2022jp = {
104 	mbfl_no_encoding_wchar,
105 	mbfl_no_encoding_2022jp,
106 	mbfl_filt_conv_common_ctor,
107 	NULL,
108 	mbfl_filt_conv_wchar_2022jp,
109 	mbfl_filt_conv_any_jis_flush,
110 	NULL,
111 };
112 
113 #define CK(statement)	do { if ((statement) < 0) return (-1); } while (0)
114 
115 /*
116  * JIS => wchar
117  */
118 int
mbfl_filt_conv_jis_wchar(int c,mbfl_convert_filter * filter)119 mbfl_filt_conv_jis_wchar(int c, mbfl_convert_filter *filter)
120 {
121 	int c1, s, w;
122 
123 retry:
124 	switch (filter->status & 0xf) {
125 /*	case 0x00:	 ASCII */
126 /*	case 0x10:	 X 0201 latin */
127 /*	case 0x20:	 X 0201 kana */
128 /*	case 0x80:	 X 0208 */
129 /*	case 0x90:	 X 0212 */
130 	case 0:
131 		if (c == 0x1b) {
132 			filter->status += 2;
133 		} else if (c == 0x0e) {		/* "kana in" */
134 			filter->status = 0x20;
135 		} else if (c == 0x0f) {		/* "kana out" */
136 			filter->status = 0;
137 		} else if (filter->status == 0x10 && c == 0x5c) {	/* YEN SIGN */
138 			CK((*filter->output_function)(0xa5, filter->data));
139 		} else if (filter->status == 0x10 && c == 0x7e) {	/* OVER LINE */
140 			CK((*filter->output_function)(0x203e, filter->data));
141 		} else if (filter->status == 0x20 && c > 0x20 && c < 0x60) {		/* kana */
142 			CK((*filter->output_function)(0xff40 + c, filter->data));
143 		} else if ((filter->status == 0x80 || filter->status == 0x90) && c > 0x20 && c < 0x7f) {		/* kanji first char */
144 			filter->cache = c;
145 			filter->status += 1;
146 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
147 			CK((*filter->output_function)(c, filter->data));
148 		} else if (c > 0xa0 && c < 0xe0) {	/* GR kana */
149 			CK((*filter->output_function)(0xfec0 + c, filter->data));
150 		} else {
151 			w = c & MBFL_WCSGROUP_MASK;
152 			w |= MBFL_WCSGROUP_THROUGH;
153 			CK((*filter->output_function)(w, filter->data));
154 		}
155 		break;
156 
157 /*	case 0x81:	 X 0208 second char */
158 /*	case 0x91:	 X 0212 second char */
159 	case 1:
160 		filter->status &= ~0xf;
161 		c1 = filter->cache;
162 		if (c > 0x20 && c < 0x7f) {
163 			s = (c1 - 0x21)*94 + c - 0x21;
164 			if (filter->status == 0x80) {
165 				if (s >= 0 && s < jisx0208_ucs_table_size) {
166 					w = jisx0208_ucs_table[s];
167 				} else {
168 					w = 0;
169 				}
170 				if (w <= 0) {
171 					w = (c1 << 8) | c;
172 					w &= MBFL_WCSPLANE_MASK;
173 					w |= MBFL_WCSPLANE_JIS0208;
174 				}
175 			} else {
176 				if (s >= 0 && s < jisx0212_ucs_table_size) {
177 					w = jisx0212_ucs_table[s];
178 				} else {
179 					w = 0;
180 				}
181 				if (w <= 0) {
182 					w = (c1 << 8) | c;
183 					w &= MBFL_WCSPLANE_MASK;
184 					w |= MBFL_WCSPLANE_JIS0212;
185 				}
186 			}
187 			CK((*filter->output_function)(w, filter->data));
188 		} else if (c == 0x1b) {
189 			filter->status += 2;
190 		} else if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
191 			CK((*filter->output_function)(c, filter->data));
192 		} else {
193 			w = (c1 << 8) | c;
194 			w &= MBFL_WCSGROUP_MASK;
195 			w |= MBFL_WCSGROUP_THROUGH;
196 			CK((*filter->output_function)(w, filter->data));
197 		}
198 		break;
199 
200 	/* ESC */
201 /*	case 0x02:	*/
202 /*	case 0x12:	*/
203 /*	case 0x22:	*/
204 /*	case 0x82:	*/
205 /*	case 0x92:	*/
206 	case 2:
207 		if (c == 0x24) {		/* '$' */
208 			filter->status++;
209 		} else if (c == 0x28) {		/* '(' */
210 			filter->status += 3;
211 		} else {
212 			filter->status &= ~0xf;
213 			CK((*filter->output_function)(0x1b, filter->data));
214 			goto retry;
215 		}
216 		break;
217 
218 	/* ESC $ */
219 /*	case 0x03:	*/
220 /*	case 0x13:	*/
221 /*	case 0x23:	*/
222 /*	case 0x83:	*/
223 /*	case 0x93:	*/
224 	case 3:
225 		if (c == 0x40 || c == 0x42) {	/* '@' or 'B' */
226 			filter->status = 0x80;
227 		} else if (c == 0x28) {			/* '(' */
228 			filter->status++;
229 		} else {
230 			filter->status &= ~0xf;
231 			CK((*filter->output_function)(0x1b, filter->data));
232 			CK((*filter->output_function)(0x24, filter->data));
233 			goto retry;
234 		}
235 		break;
236 
237 	/* ESC $ ( */
238 /*	case 0x04:	*/
239 /*	case 0x14:	*/
240 /*	case 0x24:	*/
241 /*	case 0x84:	*/
242 /*	case 0x94:	*/
243 	case 4:
244 		if (c == 0x40 || c == 0x42) {	/* '@' or 'B' */
245 			filter->status = 0x80;
246 		} else if (c == 0x44) {			/* 'D' */
247 			filter->status = 0x90;
248 		} else {
249 			filter->status &= ~0xf;
250 			CK((*filter->output_function)(0x1b, filter->data));
251 			CK((*filter->output_function)(0x24, filter->data));
252 			CK((*filter->output_function)(0x28, filter->data));
253 			goto retry;
254 		}
255 		break;
256 
257 	/* ESC ( */
258 /*	case 0x05:	*/
259 /*	case 0x15:	*/
260 /*	case 0x25:	*/
261 /*	case 0x85:	*/
262 /*	case 0x95:	*/
263 	case 5:
264 		if (c == 0x42 || c == 0x48) {		/* 'B' or 'H' */
265 			filter->status = 0;
266 		} else if (c == 0x4a) {		/* 'J' */
267 			filter->status = 0x10;
268 		} else if (c == 0x49) {		/* 'I' */
269 			filter->status = 0x20;
270 		} else {
271 			filter->status &= ~0xf;
272 			CK((*filter->output_function)(0x1b, filter->data));
273 			CK((*filter->output_function)(0x28, filter->data));
274 			goto retry;
275 		}
276 		break;
277 
278 	default:
279 		filter->status = 0;
280 		break;
281 	}
282 
283 	return c;
284 }
285 
286 /*
287  * wchar => JIS
288  */
289 int
mbfl_filt_conv_wchar_jis(int c,mbfl_convert_filter * filter)290 mbfl_filt_conv_wchar_jis(int c, mbfl_convert_filter *filter)
291 {
292 	int c1, s;
293 
294 	s = 0;
295 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
296 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
297 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
298 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
299 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
300 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
301 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
302 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
303 	}
304 	if (s <= 0) {
305 		c1 = c & ~MBFL_WCSPLANE_MASK;
306 		if (c1 == MBFL_WCSPLANE_JIS0208) {
307 			s = c & MBFL_WCSPLANE_MASK;
308 		} else if (c1 == MBFL_WCSPLANE_JIS0212) {
309 			s = c & MBFL_WCSPLANE_MASK;
310 			s |= 0x8080;
311 		} else if (c == 0xa5) {		/* YEN SIGN */
312 			s = 0x1005c;
313 		} else if (c == 0x203e) {	/* OVER LINE */
314 			s = 0x1007e;
315 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
316 			s = 0x2140;
317 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
318 			s = 0x2141;
319 		} else if (c == 0x2225) {	/* PARALLEL TO */
320 			s = 0x2142;
321 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
322 			s = 0x215d;
323 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
324 			s = 0x2171;
325 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
326 			s = 0x2172;
327 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
328 			s = 0x224c;
329 		}
330 		if (c == 0) {
331 			s = 0;
332 		} else if (s <= 0) {
333 			s = -1;
334 		}
335 	}
336 	if (s >= 0) {
337 		if (s < 0x80) { /* ASCII */
338 			if ((filter->status & 0xff00) != 0) {
339 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
340 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
341 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
342 			}
343 			filter->status = 0;
344 			CK((*filter->output_function)(s, filter->data));
345 		} else if (s < 0x100) { /* kana */
346 			if ((filter->status & 0xff00) != 0x100) {
347 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
348 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
349 				CK((*filter->output_function)(0x49, filter->data));		/* 'I' */
350 			}
351 			filter->status = 0x100;
352 			CK((*filter->output_function)(s & 0x7f, filter->data));
353 		} else if (s < 0x8080) { /* X 0208 */
354 			if ((filter->status & 0xff00) != 0x200) {
355 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
356 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
357 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
358 			}
359 			filter->status = 0x200;
360 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
361 			CK((*filter->output_function)(s & 0x7f, filter->data));
362 		} else if (s < 0x10000) { /* X 0212 */
363 			if ((filter->status & 0xff00) != 0x300) {
364 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
365 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
366 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
367 				CK((*filter->output_function)(0x44, filter->data));		/* 'D' */
368 			}
369 			filter->status = 0x300;
370 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
371 			CK((*filter->output_function)(s & 0x7f, filter->data));
372 		} else { /* X 0201 latin */
373 			if ((filter->status & 0xff00) != 0x400) {
374 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
375 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
376 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
377 			}
378 			filter->status = 0x400;
379 			CK((*filter->output_function)(s & 0x7f, filter->data));
380 		}
381 	} else {
382 		CK(mbfl_filt_conv_illegal_output(c, filter));
383 	}
384 
385 	return c;
386 }
387 
388 
389 /*
390  * wchar => ISO-2022-JP
391  */
392 int
mbfl_filt_conv_wchar_2022jp(int c,mbfl_convert_filter * filter)393 mbfl_filt_conv_wchar_2022jp(int c, mbfl_convert_filter *filter)
394 {
395 	int s;
396 
397 	s = 0;
398 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
399 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
400 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
401 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
402 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
403 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
404 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
405 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
406 	}
407 	if (s <= 0) {
408 		if (c == 0xa5) {			/* YEN SIGN */
409 			s = 0x1005c;
410 		} else if (c == 0x203e) {	/* OVER LINE */
411 			s = 0x1007e;
412 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
413 			s = 0x2140;
414 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
415 			s = 0x2141;
416 		} else if (c == 0x2225) {	/* PARALLEL TO */
417 			s = 0x2142;
418 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
419 			s = 0x215d;
420 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
421 			s = 0x2171;
422 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
423 			s = 0x2172;
424 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
425 			s = 0x224c;
426 		}
427 		if (c == 0) {
428 			s = 0;
429 		} else if (s <= 0) {
430 			s = -1;
431 		}
432 	} else if ((s >= 0x80 && s < 0x2121) || (s > 0x8080)) {
433 		s = -1;
434 	}
435 	if (s >= 0) {
436 		if (s < 0x80) { /* ASCII */
437 			if ((filter->status & 0xff00) != 0) {
438 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
439 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
440 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
441 			}
442 			filter->status = 0;
443 			CK((*filter->output_function)(s, filter->data));
444 		} else if (s < 0x10000) { /* X 0208 */
445 			if ((filter->status & 0xff00) != 0x200) {
446 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
447 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
448 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
449 			}
450 			filter->status = 0x200;
451 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
452 			CK((*filter->output_function)(s & 0x7f, filter->data));
453 		} else { /* X 0201 latin */
454 			if ((filter->status & 0xff00) != 0x400) {
455 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
456 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
457 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
458 			}
459 			filter->status = 0x400;
460 			CK((*filter->output_function)(s & 0x7f, filter->data));
461 		}
462 	} else {
463 		CK(mbfl_filt_conv_illegal_output(c, filter));
464 	}
465 
466 	return c;
467 }
468 
469 int
mbfl_filt_conv_any_jis_flush(mbfl_convert_filter * filter)470 mbfl_filt_conv_any_jis_flush(mbfl_convert_filter *filter)
471 {
472 	/* back to latin */
473 	if ((filter->status & 0xff00) != 0) {
474 		CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
475 		CK((*filter->output_function)(0x28, filter->data));		/* '(' */
476 		CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
477 	}
478 	filter->status &= 0xff;
479 
480 	if (filter->flush_function != NULL) {
481 		return (*filter->flush_function)(filter->data);
482 	}
483 
484 	return 0;
485 }
486 
mbfl_filt_ident_jis(int c,mbfl_identify_filter * filter)487 static int mbfl_filt_ident_jis(int c, mbfl_identify_filter *filter)
488 {
489 retry:
490 	switch (filter->status & 0xf) {
491 /*	case 0x00:	 ASCII */
492 /*	case 0x10:	 X 0201 latin */
493 /*	case 0x20:	 X 0201 kana */
494 /*	case 0x80:	 X 0208 */
495 /*	case 0x90:	 X 0212 */
496 	case 0:
497 		if (c == 0x1b) {
498 			filter->status += 2;
499 		} else if (c == 0x0e) {			/* "kana in" */
500 			filter->status = 0x20;
501 		} else if (c == 0x0f) {			/* "kana out" */
502 			filter->status = 0;
503 		} else if ((filter->status == 0x80 || filter->status == 0x90) && c > 0x20 && c < 0x7f) {		/* kanji first char */
504 			filter->status += 1;
505 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
506 			;
507 		} else {
508 			filter->flag = 1;	/* bad */
509 		}
510 		break;
511 
512 /*	case 0x81:	 X 0208 second char */
513 /*	case 0x91:	 X 0212 second char */
514 	case 1:
515 		filter->status &= ~0xf;
516 		if (c == 0x1b) {
517 			goto retry;
518 		} else if (c < 0x21 || c > 0x7e) {		/* bad */
519 			filter->flag = 1;
520 		}
521 		break;
522 
523 	/* ESC */
524 	case 2:
525 		if (c == 0x24) {		/* '$' */
526 			filter->status++;
527 		} else if (c == 0x28) {		/* '(' */
528 			filter->status += 3;
529 		} else {
530 			filter->flag = 1;	/* bad */
531 			filter->status &= ~0xf;
532 			goto retry;
533 		}
534 		break;
535 
536 	/* ESC $ */
537 	case 3:
538 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
539 			filter->status = 0x80;
540 		} else if (c == 0x28) {		/* '(' */
541 			filter->status++;
542 		} else {
543 			filter->flag = 1;	/* bad */
544 			filter->status &= ~0xf;
545 			goto retry;
546 		}
547 		break;
548 
549 	/* ESC $ ( */
550 	case 4:
551 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
552 			filter->status = 0x80;
553 		} else if (c == 0x44) {		/* 'D' */
554 			filter->status = 0x90;
555 		} else {
556 			filter->flag = 1;	/* bad */
557 			filter->status &= ~0xf;
558 			goto retry;
559 		}
560 		break;
561 
562 	/* ESC ( */
563 	case 5:
564 		if (c == 0x42 || c == 0x48) {		/* 'B' or 'H' */
565 			filter->status = 0;
566 		} else if (c == 0x4a) {		/* 'J' */
567 			filter->status = 0x10;
568 		} else if (c == 0x49) {		/* 'I' */
569 			filter->status = 0x20;
570 		} else {
571 			filter->flag = 1;	/* bad */
572 			filter->status &= ~0xf;
573 			goto retry;
574 		}
575 		break;
576 
577 	default:
578 		filter->status = 0;
579 		break;
580 	}
581 
582 	return c;
583 }
584 
mbfl_filt_ident_2022jp(int c,mbfl_identify_filter * filter)585 static int mbfl_filt_ident_2022jp(int c, mbfl_identify_filter *filter)
586 {
587 retry:
588 	switch (filter->status & 0xf) {
589 /*	case 0x00:	 ASCII */
590 /*	case 0x10:	 X 0201 latin */
591 /*	case 0x80:	 X 0208 */
592 	case 0:
593 		if (c == 0x1b) {
594 			filter->status += 2;
595 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
596 			filter->status += 1;
597 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
598 			;
599 		} else {
600 			filter->flag = 1;	/* bad */
601 		}
602 		break;
603 
604 /*	case 0x81:	 X 0208 second char */
605 	case 1:
606 		if (c == 0x1b) {
607 			filter->status++;
608 		} else {
609 			filter->status &= ~0xf;
610 			if (c < 0x21 || c > 0x7e) {		/* bad */
611 				filter->flag = 1;
612 			}
613 		}
614 		break;
615 
616 	/* ESC */
617 	case 2:
618 		if (c == 0x24) {		/* '$' */
619 			filter->status++;
620 		} else if (c == 0x28) {		/* '(' */
621 			filter->status += 3;
622 		} else {
623 			filter->flag = 1;	/* bad */
624 			filter->status &= ~0xf;
625 			goto retry;
626 		}
627 		break;
628 
629 	/* ESC $ */
630 	case 3:
631 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
632 			filter->status = 0x80;
633 		} else {
634 			filter->flag = 1;	/* bad */
635 			filter->status &= ~0xf;
636 			goto retry;
637 		}
638 		break;
639 
640 	/* ESC ( */
641 	case 5:
642 		if (c == 0x42) {		/* 'B' */
643 			filter->status = 0;
644 		} else if (c == 0x4a) {		/* 'J' */
645 			filter->status = 0x10;
646 		} else {
647 			filter->flag = 1;	/* bad */
648 			filter->status &= ~0xf;
649 			goto retry;
650 		}
651 		break;
652 
653 	default:
654 		filter->status = 0;
655 		break;
656 	}
657 
658 	return c;
659 }
660