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: Moriyoshi Koizumi <koizumi@gree.co.jp>
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "mbfilter.h"
30 #include "mbfilter_cp5022x.h"
31 #include "mbfilter_jis.h"
32 #include "mbfilter_tl_jisx0201_jisx0208.h"
33 
34 #include "unicode_table_cp932_ext.h"
35 #include "unicode_table_jis.h"
36 #include "cp932_table.h"
37 
38 typedef struct _mbfl_filt_conv_wchar_cp50220_ctx {
39 	mbfl_filt_tl_jisx0201_jisx0208_param tl_param;
40 	mbfl_convert_filter last;
41 } mbfl_filt_conv_wchar_cp50220_ctx;
42 
43 static int mbfl_filt_ident_jis_ms(int c, mbfl_identify_filter *filter);
44 static int mbfl_filt_ident_cp50220(int c, mbfl_identify_filter *filter);
45 static int mbfl_filt_ident_cp50221(int c, mbfl_identify_filter *filter);
46 static int mbfl_filt_ident_cp50222(int c, mbfl_identify_filter *filter);
47 static void mbfl_filt_conv_wchar_cp50220_ctor(mbfl_convert_filter *filt);
48 static void mbfl_filt_conv_wchar_cp50220_dtor(mbfl_convert_filter *filt);
49 static void mbfl_filt_conv_wchar_cp50220_copy(mbfl_convert_filter *src, mbfl_convert_filter *dest);
50 
51 const mbfl_encoding mbfl_encoding_jis_ms = {
52 	mbfl_no_encoding_jis_ms,
53 	"JIS-ms",
54 	"ISO-2022-JP",
55 	NULL,
56 	NULL,
57 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_SHFTCODE | MBFL_ENCTYPE_GL_UNSAFE,
58 	&vtbl_jis_ms_wchar,
59 	&vtbl_wchar_jis_ms
60 };
61 
62 const mbfl_encoding mbfl_encoding_cp50220 = {
63 	mbfl_no_encoding_cp50220,
64 	"CP50220",
65 	"ISO-2022-JP",
66 	(const char *(*)[])NULL,
67 	NULL,
68 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_SHFTCODE | MBFL_ENCTYPE_GL_UNSAFE,
69 	&vtbl_cp50220_wchar,
70 	&vtbl_wchar_cp50220
71 };
72 
73 const mbfl_encoding mbfl_encoding_cp50220raw = {
74 	mbfl_no_encoding_cp50220raw,
75 	"CP50220raw",
76 	"ISO-2022-JP",
77 	(const char *(*)[])NULL,
78 	NULL,
79 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_SHFTCODE | MBFL_ENCTYPE_GL_UNSAFE,
80 	&vtbl_cp50220raw_wchar,
81 	&vtbl_wchar_cp50220raw
82 };
83 
84 const mbfl_encoding mbfl_encoding_cp50221 = {
85 	mbfl_no_encoding_cp50221,
86 	"CP50221",
87 	"ISO-2022-JP",
88 	NULL,
89 	NULL,
90 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_SHFTCODE | MBFL_ENCTYPE_GL_UNSAFE,
91 	&vtbl_cp50221_wchar,
92 	&vtbl_wchar_cp50221
93 };
94 
95 const mbfl_encoding mbfl_encoding_cp50222 = {
96 	mbfl_no_encoding_cp50222,
97 	"CP50222",
98 	"ISO-2022-JP",
99 	NULL,
100 	NULL,
101 	MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_SHFTCODE | MBFL_ENCTYPE_GL_UNSAFE,
102 	&vtbl_cp50222_wchar,
103 	&vtbl_wchar_cp50222
104 };
105 
106 const struct mbfl_identify_vtbl vtbl_identify_jis_ms = {
107 	mbfl_no_encoding_jis_ms,
108 	mbfl_filt_ident_common_ctor,
109 	mbfl_filt_ident_common_dtor,
110 	mbfl_filt_ident_jis_ms
111 };
112 
113 const struct mbfl_identify_vtbl vtbl_identify_cp50220 = {
114 	mbfl_no_encoding_cp50220,
115 	mbfl_filt_ident_common_ctor,
116 	mbfl_filt_ident_common_dtor,
117 	mbfl_filt_ident_cp50220
118 };
119 
120 const struct mbfl_identify_vtbl vtbl_identify_cp50220raw = {
121 	mbfl_no_encoding_cp50220raw,
122 	mbfl_filt_ident_common_ctor,
123 	mbfl_filt_ident_common_dtor,
124 	mbfl_filt_ident_cp50220
125 };
126 
127 const struct mbfl_identify_vtbl vtbl_identify_cp50221 = {
128 	mbfl_no_encoding_cp50221,
129 	mbfl_filt_ident_common_ctor,
130 	mbfl_filt_ident_common_dtor,
131 	mbfl_filt_ident_cp50221
132 };
133 
134 const struct mbfl_identify_vtbl vtbl_identify_cp50222 = {
135 	mbfl_no_encoding_cp50222,
136 	mbfl_filt_ident_common_ctor,
137 	mbfl_filt_ident_common_dtor,
138 	mbfl_filt_ident_cp50222
139 };
140 
141 const struct mbfl_convert_vtbl vtbl_jis_ms_wchar = {
142 	mbfl_no_encoding_jis_ms,
143 	mbfl_no_encoding_wchar,
144 	mbfl_filt_conv_common_ctor,
145 	mbfl_filt_conv_common_dtor,
146 	mbfl_filt_conv_jis_ms_wchar,
147 	mbfl_filt_conv_common_flush,
148 };
149 
150 const struct mbfl_convert_vtbl vtbl_wchar_jis_ms = {
151 	mbfl_no_encoding_wchar,
152 	mbfl_no_encoding_jis_ms,
153 	mbfl_filt_conv_common_ctor,
154 	mbfl_filt_conv_common_dtor,
155 	mbfl_filt_conv_wchar_jis_ms,
156 	mbfl_filt_conv_any_jis_flush
157 };
158 
159 const struct mbfl_convert_vtbl vtbl_cp50220_wchar = {
160 	mbfl_no_encoding_cp50220,
161 	mbfl_no_encoding_wchar,
162 	mbfl_filt_conv_common_ctor,
163 	mbfl_filt_conv_common_dtor,
164 	mbfl_filt_conv_jis_ms_wchar,
165 	mbfl_filt_conv_common_flush
166 };
167 
168 const struct mbfl_convert_vtbl vtbl_wchar_cp50220 = {
169 	mbfl_no_encoding_wchar,
170 	mbfl_no_encoding_cp50220,
171 	mbfl_filt_conv_wchar_cp50220_ctor,
172 	mbfl_filt_conv_wchar_cp50220_dtor,
173 	mbfl_filt_conv_wchar_cp50221,
174 	mbfl_filt_conv_any_jis_flush,
175 	mbfl_filt_conv_wchar_cp50220_copy
176 };
177 
178 const struct mbfl_convert_vtbl vtbl_cp50220raw_wchar = {
179 	mbfl_no_encoding_cp50220raw,
180 	mbfl_no_encoding_wchar,
181 	mbfl_filt_conv_common_ctor,
182 	mbfl_filt_conv_common_dtor,
183 	mbfl_filt_conv_jis_ms_wchar,
184 	mbfl_filt_conv_common_flush
185 };
186 
187 const struct mbfl_convert_vtbl vtbl_wchar_cp50220raw = {
188 	mbfl_no_encoding_wchar,
189 	mbfl_no_encoding_cp50220raw,
190 	mbfl_filt_conv_wchar_cp50220_ctor,
191 	mbfl_filt_conv_wchar_cp50220_dtor,
192 	mbfl_filt_conv_wchar_cp50220raw,
193 	mbfl_filt_conv_any_jis_flush,
194 	mbfl_filt_conv_wchar_cp50220_copy
195 };
196 
197 const struct mbfl_convert_vtbl vtbl_cp50221_wchar = {
198 	mbfl_no_encoding_cp50221,
199 	mbfl_no_encoding_wchar,
200 	mbfl_filt_conv_common_ctor,
201 	mbfl_filt_conv_common_dtor,
202 	mbfl_filt_conv_jis_ms_wchar,
203 	mbfl_filt_conv_common_flush
204 };
205 
206 const struct mbfl_convert_vtbl vtbl_wchar_cp50221 = {
207 	mbfl_no_encoding_wchar,
208 	mbfl_no_encoding_cp50221,
209 	mbfl_filt_conv_common_ctor,
210 	mbfl_filt_conv_common_dtor,
211 	mbfl_filt_conv_wchar_cp50221,
212 	mbfl_filt_conv_any_jis_flush
213 };
214 
215 const struct mbfl_convert_vtbl vtbl_cp50222_wchar = {
216 	mbfl_no_encoding_cp50222,
217 	mbfl_no_encoding_wchar,
218 	mbfl_filt_conv_common_ctor,
219 	mbfl_filt_conv_common_dtor,
220 	mbfl_filt_conv_jis_ms_wchar,
221 	mbfl_filt_conv_common_flush
222 };
223 
224 const struct mbfl_convert_vtbl vtbl_wchar_cp50222 = {
225 	mbfl_no_encoding_wchar,
226 	mbfl_no_encoding_cp50222,
227 	mbfl_filt_conv_common_ctor,
228 	mbfl_filt_conv_common_dtor,
229 	mbfl_filt_conv_wchar_cp50222,
230 	mbfl_filt_conv_wchar_cp50222_flush
231 };
232 
233 #define CK(statement)	do { if ((statement) < 0) return (-1); } while (0)
234 
235 /*
236  * JIS-ms => wchar
237  */
238 int
mbfl_filt_conv_jis_ms_wchar(int c,mbfl_convert_filter * filter)239 mbfl_filt_conv_jis_ms_wchar(int c, mbfl_convert_filter *filter)
240 {
241 	int c1, s, w;
242 
243 retry:
244 	switch (filter->status & 0xf) {
245 /*	case 0x00:	 ASCII */
246 /*	case 0x10:	 X 0201 latin */
247 /*	case 0x20:	 X 0201 kana */
248 /*	case 0x80:	 X 0208 */
249 /*	case 0x90:	 X 0212 */
250 	case 0:
251 		if (c == 0x1b) {
252 			filter->status += 2;
253 		} else if (c == 0x0e) {		/* "kana in" */
254 			filter->status = 0x20;
255 		} else if (c == 0x0f) {		/* "kana out" */
256 			filter->status = 0;
257 		} else if (filter->status == 0x10 && c == 0x5c) {	/* YEN SIGN */
258 			CK((*filter->output_function)(0xa5, filter->data));
259 		} else if (filter->status == 0x10 && c == 0x7e) {	/* OVER LINE */
260 			CK((*filter->output_function)(0x203e, filter->data));
261 		} else if (filter->status == 0x20 && c > 0x20 && c < 0x60) {		/* kana */
262 			CK((*filter->output_function)(0xff40 + c, filter->data));
263 		} else if ((filter->status == 0x80 || filter->status == 0x90) && c > 0x20 && c < 0x93) {		/* kanji first char */
264 			filter->cache = c;
265 			filter->status += 1;
266 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
267 			CK((*filter->output_function)(c, filter->data));
268 		} else if (c > 0xa0 && c < 0xe0) {	/* GR kana */
269 			CK((*filter->output_function)(0xfec0 + c, filter->data));
270 		} else {
271 			w = c & MBFL_WCSGROUP_MASK;
272 			w |= MBFL_WCSGROUP_THROUGH;
273 			CK((*filter->output_function)(w, filter->data));
274 		}
275 		break;
276 
277 /*	case 0x81:	 X 0208 second char */
278 /*	case 0x91:	 X 0212 second char */
279 	case 1:
280 		filter->status &= ~0xf;
281 		c1 = filter->cache;
282 		if (c > 0x20 && c < 0x7f) {
283 			s = (c1 - 0x21)*94 + c - 0x21;
284 			if (filter->status == 0x80) {
285 				if (s >= 0 && s < jisx0208_ucs_table_size) {
286 					w = jisx0208_ucs_table[s];
287 				} else if (s >= cp932ext1_ucs_table_min && s < cp932ext1_ucs_table_max) {
288 					w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min];
289 				} else if (s >= cp932ext2_ucs_table_min && s < cp932ext2_ucs_table_max) {
290 					w = cp932ext2_ucs_table[s - cp932ext2_ucs_table_min];
291 				} else if (s >= cp932ext3_ucs_table_min && s < cp932ext3_ucs_table_max) {
292 					w = cp932ext3_ucs_table[s - cp932ext3_ucs_table_min];
293 				} else if (s >= 94 * 94 && s < 114 * 94) {
294 					/* user-defined => PUA (Microsoft extended) */
295 					w = s - 94*94 + 0xe000;
296 				} else {
297 					w = 0;
298 				}
299 				if (w <= 0) {
300 					w = (c1 << 8) | c;
301 					w &= MBFL_WCSPLANE_MASK;
302 					w |= MBFL_WCSPLANE_JIS0208;
303 				}
304 			} else {
305 				if (s >= 0 && s < jisx0212_ucs_table_size) {
306 					w = jisx0212_ucs_table[s];
307 				} else {
308 					w = 0;
309 				}
310 				if (w <= 0) {
311 					w = (c1 << 8) | c;
312 					w &= MBFL_WCSPLANE_MASK;
313 					w |= MBFL_WCSPLANE_JIS0212;
314 				}
315 			}
316 			CK((*filter->output_function)(w, filter->data));
317 		} else if (c == 0x1b) {
318 			filter->status += 2;
319 		} else if ((c >= 0 && c < 0x21) || c == 0x7f) {		/* CTLs */
320 			CK((*filter->output_function)(c, filter->data));
321 		} else {
322 			w = (c1 << 8) | c;
323 			w &= MBFL_WCSGROUP_MASK;
324 			w |= MBFL_WCSGROUP_THROUGH;
325 			CK((*filter->output_function)(w, filter->data));
326 		}
327 		break;
328 
329 	/* ESC */
330 /*	case 0x02:	*/
331 /*	case 0x12:	*/
332 /*	case 0x22:	*/
333 /*	case 0x82:	*/
334 /*	case 0x92:	*/
335 	case 2:
336 		if (c == 0x24) {		/* '$' */
337 			filter->status++;
338 		} else if (c == 0x28) {		/* '(' */
339 			filter->status += 3;
340 		} else {
341 			filter->status &= ~0xf;
342 			CK((*filter->output_function)(0x1b, filter->data));
343 			goto retry;
344 		}
345 		break;
346 
347 	/* ESC $ */
348 /*	case 0x03:	*/
349 /*	case 0x13:	*/
350 /*	case 0x23:	*/
351 /*	case 0x83:	*/
352 /*	case 0x93:	*/
353 	case 3:
354 		if (c == 0x40 || c == 0x42) {	/* '@' or 'B' */
355 			filter->status = 0x80;
356 		} else if (c == 0x28) {			/* '(' */
357 			filter->status++;
358 		} else {
359 			filter->status &= ~0xf;
360 			CK((*filter->output_function)(0x1b, filter->data));
361 			CK((*filter->output_function)(0x24, filter->data));
362 			goto retry;
363 		}
364 		break;
365 
366 	/* ESC $ ( */
367 /*	case 0x04:	*/
368 /*	case 0x14:	*/
369 /*	case 0x24:	*/
370 /*	case 0x84:	*/
371 /*	case 0x94:	*/
372 	case 4:
373 		if (c == 0x40 || c == 0x42) {	/* '@' or 'B' */
374 			filter->status = 0x80;
375 		} else if (c == 0x44) {			/* 'D' */
376 			filter->status = 0x90;
377 		} else {
378 			filter->status &= ~0xf;
379 			CK((*filter->output_function)(0x1b, filter->data));
380 			CK((*filter->output_function)(0x24, filter->data));
381 			CK((*filter->output_function)(0x28, filter->data));
382 			goto retry;
383 		}
384 		break;
385 
386 	/* ESC ( */
387 /*	case 0x05:	*/
388 /*	case 0x15:	*/
389 /*	case 0x25:	*/
390 /*	case 0x85:	*/
391 /*	case 0x95:	*/
392 	case 5:
393 		if (c == 0x42 || c == 0x48) {		/* 'B' or 'H' */
394 			filter->status = 0;
395 		} else if (c == 0x4a) {		/* 'J' */
396 			filter->status = 0x10;
397 		} else if (c == 0x49) {		/* 'I' */
398 			filter->status = 0x20;
399 		} else {
400 			filter->status &= ~0xf;
401 			CK((*filter->output_function)(0x1b, filter->data));
402 			CK((*filter->output_function)(0x28, filter->data));
403 			goto retry;
404 		}
405 		break;
406 
407 	default:
408 		filter->status = 0;
409 		break;
410 	}
411 
412 	return c;
413 }
414 
415 /*
416  * wchar => JIS
417  */
418 int
mbfl_filt_conv_wchar_jis_ms(int c,mbfl_convert_filter * filter)419 mbfl_filt_conv_wchar_jis_ms(int c, mbfl_convert_filter *filter)
420 {
421 	int c1, s;
422 
423 	s = 0;
424 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
425 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
426 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
427 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
428 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
429 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
430 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
431 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
432 	} else if (c >= 0xe000 && c < (0xe000 + 10 * 94)) {
433 		/* PUE => Microsoft extended (pseudo 95ku - 114ku) */
434 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
435 		s = c - 0xe000;
436 		s = (s / 94 + 0x75) << 8 | (s % 94 + 0x21);
437 	} else if (c >= (0xe000 + 10 * 94) && c <= (0xe000 + 20 * 94)) {
438 		/* PUE => JISX0212 user-defined (G3 85ku - 94ku) */
439 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
440 		s = c - (0xe000 + 10 * 94);
441 		s = (s / 94 + 0xf5) << 8 | (s % 94 + 0xa1);
442 	}
443 
444 	/* do some transliteration */
445 	if (s <= 0) {
446 		c1 = c & ~MBFL_WCSPLANE_MASK;
447 		if (c1 == MBFL_WCSPLANE_JIS0208) {
448 			s = c & MBFL_WCSPLANE_MASK;
449 		} else if (c1 == MBFL_WCSPLANE_JIS0212) {
450 			s = c & MBFL_WCSPLANE_MASK;
451 			s |= 0x8080;
452 		} else if (c == 0xa5) {		/* YEN SIGN */
453 			s = 0x1005c;
454 		} else if (c == 0x203e) {	/* OVER LINE */
455 			s = 0x1007e;
456 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
457 			s = 0x2140;
458 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
459 			s = 0x2141;
460 		} else if (c == 0x2225) {	/* PARALLEL TO */
461 			s = 0x2142;
462 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
463 			s = 0x215d;
464 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
465 			s = 0x2171;
466 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
467 			s = 0x2172;
468 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
469 			s = 0x224c;
470 		}
471 	}
472 	if (s <= 0 || (s >= 0x8080 && s < 0x10000)) {
473 		int i;
474 		s = -1;
475 
476 		for (i = 0;
477 				i < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; i++) {
478 			const int oh = cp932ext1_ucs_table_min / 94;
479 
480 			if (c == cp932ext1_ucs_table[i]) {
481 				s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
482 				break;
483 			}
484 		}
485 
486 		if (s < 0) {
487 			const int oh = cp932ext2_ucs_table_min / 94;
488 			const int cp932ext2_ucs_table_size =
489 					cp932ext2_ucs_table_max - cp932ext2_ucs_table_min;
490 			for (i = 0; i < cp932ext2_ucs_table_size; i++) {
491 				if (c == cp932ext2_ucs_table[i]) {
492 					s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
493 					break;
494 				}
495 			}
496 		}
497 
498 		if (s < 0) {
499 			const int cp932ext3_ucs_table_size =
500 					cp932ext3_ucs_table_max - cp932ext3_ucs_table_min;
501 			const int limit = cp932ext3_ucs_table_size >
502 					cp932ext3_eucjp_table_size ?
503 						cp932ext3_eucjp_table_size:
504 						cp932ext3_ucs_table_size;
505 			for (i = 0; i < limit; i++) {
506 				if (c == cp932ext3_ucs_table[i]) {
507 					s = cp932ext3_eucjp_table[i];
508 					break;
509 				}
510 			}
511 		}
512 
513 		if (c == 0) {
514 			s = 0;
515 		} else if (s <= 0) {
516 			s = -1;
517 		}
518 	}
519 
520 	if (s >= 0) {
521 		if (s < 0x80) { /* ASCII */
522 			if ((filter->status & 0xff00) != 0) {
523 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
524 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
525 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
526 			}
527 			filter->status = 0;
528 			CK((*filter->output_function)(s, filter->data));
529 		} else if (s < 0x100) { /* kana */
530 			if ((filter->status & 0xff00) != 0x100) {
531 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
532 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
533 				CK((*filter->output_function)(0x49, filter->data));		/* 'I' */
534 			}
535 			filter->status = 0x100;
536 			CK((*filter->output_function)(s & 0x7f, filter->data));
537 		} else if (s < 0x8080) { /* X 0208 */
538 			if ((filter->status & 0xff00) != 0x200) {
539 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
540 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
541 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
542 			}
543 			filter->status = 0x200;
544 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
545 			CK((*filter->output_function)(s & 0x7f, filter->data));
546 		} else if (s < 0x10000) { /* X 0212 */
547 			if ((filter->status & 0xff00) != 0x300) {
548 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
549 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
550 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
551 				CK((*filter->output_function)(0x44, filter->data));		/* 'D' */
552 			}
553 			filter->status = 0x300;
554 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
555 			CK((*filter->output_function)(s & 0x7f, filter->data));
556 		} else { /* X 0201 latin */
557 			if ((filter->status & 0xff00) != 0x400) {
558 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
559 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
560 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
561 			}
562 			filter->status = 0x400;
563 			CK((*filter->output_function)(s & 0x7f, filter->data));
564 		}
565 	} else {
566 		if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
567 			CK(mbfl_filt_conv_illegal_output(c, filter));
568 		}
569 	}
570 
571 	return c;
572 }
573 
574 /*
575  * wchar => CP50220
576  */
577 static void
mbfl_filt_conv_wchar_cp50220_ctor(mbfl_convert_filter * filt)578 mbfl_filt_conv_wchar_cp50220_ctor(mbfl_convert_filter *filt)
579 {
580 	mbfl_filt_conv_wchar_cp50220_ctx *ctx;
581 
582 	mbfl_filt_conv_common_ctor(filt);
583 
584 	ctx = mbfl_malloc(sizeof(mbfl_filt_conv_wchar_cp50220_ctx));
585 	if (ctx == NULL) {
586 		mbfl_filt_conv_common_dtor(filt);
587 		return;
588 	}
589 
590 	ctx->tl_param.mode = MBFL_FILT_TL_HAN2ZEN_KATAKANA | MBFL_FILT_TL_HAN2ZEN_GLUE;
591 
592 	ctx->last = *filt;
593 	ctx->last.opaque = ctx;
594 	ctx->last.data = filt->data;
595 	filt->filter_function = vtbl_tl_jisx0201_jisx0208.filter_function;
596 	filt->filter_flush = vtbl_tl_jisx0201_jisx0208.filter_flush;
597 	filt->output_function = (int(*)(int, void *))ctx->last.filter_function;
598 	filt->flush_function = (int(*)(void *))ctx->last.filter_flush;
599 	filt->data = &ctx->last;
600 	filt->opaque = ctx;
601 	vtbl_tl_jisx0201_jisx0208.filter_ctor(filt);
602 }
603 
604 static void
mbfl_filt_conv_wchar_cp50220_copy(mbfl_convert_filter * src,mbfl_convert_filter * dest)605 mbfl_filt_conv_wchar_cp50220_copy(mbfl_convert_filter *src, mbfl_convert_filter *dest)
606 {
607 	mbfl_filt_conv_wchar_cp50220_ctx *ctx;
608 
609 	*dest = *src;
610 	ctx = mbfl_malloc(sizeof(mbfl_filt_conv_wchar_cp50220_ctx));
611 	if (ctx != NULL) {
612 		*ctx = *(mbfl_filt_conv_wchar_cp50220_ctx*)src->opaque;
613 	}
614 
615 	dest->opaque = ctx;
616 	dest->data = &ctx->last;
617 }
618 
619 static void
mbfl_filt_conv_wchar_cp50220_dtor(mbfl_convert_filter * filt)620 mbfl_filt_conv_wchar_cp50220_dtor(mbfl_convert_filter *filt)
621 {
622 	vtbl_tl_jisx0201_jisx0208.filter_dtor(filt);
623 
624 	if (filt->opaque != NULL) {
625 		mbfl_free(filt->opaque);
626 	}
627 
628 	mbfl_filt_conv_common_dtor(filt);
629 }
630 
631 /*
632  * wchar => cp50220raw
633  */
634 int
mbfl_filt_conv_wchar_cp50220raw(int c,mbfl_convert_filter * filter)635 mbfl_filt_conv_wchar_cp50220raw(int c, mbfl_convert_filter *filter)
636 {
637 	if (c & MBFL_WCSPLANE_JIS0208) {
638 		const int s = c & MBFL_WCSPLANE_MASK;
639 
640 		if ((filter->status & 0xff00) != 0x200) {
641 			CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
642 			CK((*filter->output_function)(0x24, filter->data));		/* '$' */
643 			CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
644 			filter->status = 0x200;
645 		}
646 		CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
647 		CK((*filter->output_function)(s & 0x7f, filter->data));
648 		return c;
649 	} else {
650 		return mbfl_filt_conv_wchar_cp50221(c, filter);
651 	}
652 }
653 
654 /*
655  * wchar => CP50221
656  */
657 int
mbfl_filt_conv_wchar_cp50221(int c,mbfl_convert_filter * filter)658 mbfl_filt_conv_wchar_cp50221(int c, mbfl_convert_filter *filter)
659 {
660 	int s = 0;
661 
662 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
663 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
664 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
665 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
666 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
667 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
668 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
669 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
670 	} else if (c >= 0xe000 && c < (0xe000 + 10 * 94)) {
671 		/* PUE => Microsoft extended */
672 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
673 		s = c - 0xe000;
674 		s = (s / 94 + 0x75) << 8 | (s % 94 + 0x21);
675 	} else if (c >= (0xe000 + 10 * 94) && c <= (0xe000 + 20 * 94)) {
676 		/* PUE => JISX0212 user-defined (G3 85ku - 94ku) */
677 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
678 		s = c - (0xe000 + 10 * 94);
679 		s = (s / 94 + 0xf5) << 8 | (s % 94 + 0xa1);
680 	}
681 
682 	if (s <= 0) {
683 		if (c == 0xa5) {			/* YEN SIGN */
684 			s = 0x1005c;
685 		} else if (c == 0x203e) {	/* OVER LINE */
686 			s = 0x1007e;
687 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
688 			s = 0x2140;
689 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
690 			s = 0x2141;
691 		} else if (c == 0x2225) {	/* PARALLEL TO */
692 			s = 0x2142;
693 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
694 			s = 0x215d;
695 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
696 			s = 0x2171;
697 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
698 			s = 0x2172;
699 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
700 			s = 0x224c;
701 		}
702 	}
703 	if (s <= 0 || (s >= 0x8080 && s < 0x10000)) {
704 		int i;
705 		s = -1;
706 
707 		for (i = 0;
708 				i < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min;
709 				i++) {
710 			const int oh = cp932ext1_ucs_table_min / 94;
711 
712 			if (c == cp932ext1_ucs_table[i]) {
713 				s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
714 				break;
715 			}
716 		}
717 
718 		if (s < 0) {
719 			const int oh = cp932ext2_ucs_table_min / 94;
720 			const int cp932ext2_ucs_table_size =
721 					cp932ext2_ucs_table_max - cp932ext2_ucs_table_min;
722 			for (i = 0; i < cp932ext2_ucs_table_size; i++) {
723 				if (c == cp932ext2_ucs_table[i]) {
724 					s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
725 					break;
726 				}
727 			}
728 		}
729 
730 		if (s < 0) {
731 			const int cp932ext3_ucs_table_size =
732 					cp932ext3_ucs_table_max - cp932ext3_ucs_table_min;
733 			const int limit = cp932ext3_ucs_table_size >
734 					cp932ext3_eucjp_table_size ?
735 						cp932ext3_eucjp_table_size:
736 						cp932ext3_ucs_table_size;
737 			for (i = 0; i < limit; i++) {
738 				if (c == cp932ext3_ucs_table[i]) {
739 					s = cp932ext3_eucjp_table[i];
740 					break;
741 				}
742 			}
743 		}
744 
745 		if (c == 0) {
746 			s = 0;
747 		} else if (s <= 0) {
748 			s = -1;
749 		}
750 	}
751 
752 	if (s >= 0) {
753 		if (s < 0x80) { /* ASCII */
754 			if ((filter->status & 0xff00) != 0) {
755 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
756 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
757 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
758 				filter->status = 0;
759 			}
760 			CK((*filter->output_function)(s, filter->data));
761 		} else if (s >= 0xa0 && s < 0xe0) { /* X 0201 kana */
762 			if ((filter->status & 0xff00) != 0x500) {
763 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
764 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
765 				CK((*filter->output_function)(0x49, filter->data));		/* 'I' */
766 				filter->status = 0x500;
767 			}
768 			CK((*filter->output_function)(s - 0x80, filter->data));
769 		} else if (s < 0x8080) { /* X 0208 */
770 			if ((filter->status & 0xff00) != 0x200) {
771 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
772 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
773 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
774 				filter->status = 0x200;
775 			}
776 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
777 			CK((*filter->output_function)(s & 0x7f, filter->data));
778 		} else if (s < 0x10000) { /* X0212 */
779 			if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
780 				CK(mbfl_filt_conv_illegal_output(c, filter));
781 			}
782 		} else { /* X 0201 latin */
783 			if ((filter->status & 0xff00) != 0x400) {
784 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
785 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
786 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
787 			}
788 			filter->status = 0x400;
789 			CK((*filter->output_function)(s & 0x7f, filter->data));
790 		}
791 	} else {
792 		if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
793 			CK(mbfl_filt_conv_illegal_output(c, filter));
794 		}
795 	}
796 
797 	return c;
798 }
799 
800 /*
801  * wchar => CP50222
802  */
803 int
mbfl_filt_conv_wchar_cp50222(int c,mbfl_convert_filter * filter)804 mbfl_filt_conv_wchar_cp50222(int c, mbfl_convert_filter *filter)
805 {
806 	int s;
807 
808 	s = 0;
809 
810 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
811 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
812 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
813 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
814 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
815 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
816 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
817 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
818 	} else if (c >= 0xe000 && c < (0xe000 + 10 * 94)) {
819 		/* PUE => Microsoft extended */
820 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
821 		s = c - 0xe000;
822 		s = (s / 94 + 0x75) << 8 | (s % 94 + 0x21);
823 	} else if (c >= (0xe000 + 10 * 94) && c <= (0xe000 + 20 * 94)) {
824 		/* PUE => JISX0212 user-defined (G3 85ku - 94ku) */
825 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
826 		s = c - (0xe000 + 10 * 94);
827 		s = (s / 94 + 0xf5) << 8 | (s % 94 + 0xa1);
828 	}
829 
830 	if (s <= 0) {
831 		if (c == 0xa5) {			/* YEN SIGN */
832 			s = 0x1005c;
833 		} else if (c == 0x203e) {	/* OVER LINE */
834 			s = 0x1007e;
835 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
836 			s = 0x2140;
837 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
838 			s = 0x2141;
839 		} else if (c == 0x2225) {	/* PARALLEL TO */
840 			s = 0x2142;
841 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
842 			s = 0x215d;
843 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
844 			s = 0x2171;
845 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
846 			s = 0x2172;
847 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
848 			s = 0x224c;
849 		}
850 	}
851 	if (s <= 0 || (s >= 0x8080 && s < 0x10000)) {
852 		int i;
853 		s = -1;
854 
855 		for (i = 0;
856 				i < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; i++) {
857 			const int oh = cp932ext1_ucs_table_min / 94;
858 
859 			if (c == cp932ext1_ucs_table[i]) {
860 				s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
861 				break;
862 			}
863 		}
864 
865 		if (s <= 0) {
866 			const int oh = cp932ext2_ucs_table_min / 94;
867 			const int cp932ext2_ucs_table_size =
868 					cp932ext2_ucs_table_max - cp932ext2_ucs_table_min;
869 			for (i = 0; i < cp932ext2_ucs_table_size; i++) {
870 				if (c == cp932ext2_ucs_table[i]) {
871 					s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
872 					break;
873 				}
874 			}
875 		}
876 
877 		if (s <= 0) {
878 			const int cp932ext3_ucs_table_size =
879 					cp932ext3_ucs_table_max - cp932ext3_ucs_table_min;
880 			const int limit = cp932ext3_ucs_table_size >
881 					cp932ext3_eucjp_table_size ?
882 						cp932ext3_eucjp_table_size:
883 						cp932ext3_ucs_table_size;
884 			for (i = 0; i < limit; i++) {
885 				if (c == cp932ext3_ucs_table[i]) {
886 					s = cp932ext3_eucjp_table[i];
887 					break;
888 				}
889 			}
890 		}
891 
892 		if (c == 0) {
893 			s = 0;
894 		} else if (s <= 0) {
895 			s = -1;
896 		}
897 	}
898 
899 	if (s >= 0) {
900 		if (s < 0x80) { /* ASCII */
901 			if ((filter->status & 0xff00) == 0x500) {
902 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
903 				filter->status = 0;
904 			} else if ((filter->status & 0xff00) != 0) {
905 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
906 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
907 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
908 				filter->status = 0;
909 			}
910 			CK((*filter->output_function)(s, filter->data));
911 		} else if (s >= 0xa0 && s < 0xe0) { /* X 0201 kana */
912 			if ((filter->status & 0xff00) != 0x500) {
913 				CK((*filter->output_function)(0x0e, filter->data));		/* SI */
914 				filter->status = 0x500;
915 			}
916 			CK((*filter->output_function)(s - 0x80, filter->data));
917 		} else if (s < 0x8080) { /* X 0208 */
918 			if ((filter->status & 0xff00) == 0x500) {
919 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
920 				filter->status = 0;
921 			}
922 			if ((filter->status & 0xff00) != 0x200) {
923 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
924 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
925 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
926 				filter->status = 0x200;
927 			}
928 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
929 			CK((*filter->output_function)(s & 0x7f, filter->data));
930 		} else if (s < 0x10000) { /* X0212 */
931 			if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
932 				CK(mbfl_filt_conv_illegal_output(c, filter));
933 			}
934 		} else { /* X 0201 latin */
935 			if ((filter->status & 0xff00) == 0x500) {
936 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
937 				filter->status = 0;
938 			}
939 			if ((filter->status & 0xff00) != 0x400) {
940 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
941 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
942 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
943 			}
944 			filter->status = 0x400;
945 			CK((*filter->output_function)(s & 0x7f, filter->data));
946 		}
947 	} else {
948 		if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
949 			CK(mbfl_filt_conv_illegal_output(c, filter));
950 		}
951 	}
952 
953 	return c;
954 }
955 
956 int
mbfl_filt_conv_wchar_cp50222_flush(mbfl_convert_filter * filter)957 mbfl_filt_conv_wchar_cp50222_flush(mbfl_convert_filter *filter)
958 {
959 	/* back to latin */
960 	if ((filter->status & 0xff00) == 0x500) {
961 		CK((*filter->output_function)(0x0f, filter->data));		/* SO */
962 	} else if ((filter->status & 0xff00) != 0) {
963 		CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
964 		CK((*filter->output_function)(0x28, filter->data));		/* '(' */
965 		CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
966 	}
967 	filter->status &= 0xff;
968 
969 	if (filter->flush_function != NULL) {
970 		return (*filter->flush_function)(filter->data);
971 	}
972 
973 	return 0;
974 }
975 
976 
mbfl_filt_ident_jis_ms(int c,mbfl_identify_filter * filter)977 static int mbfl_filt_ident_jis_ms(int c, mbfl_identify_filter *filter)
978 {
979 retry:
980 	switch (filter->status & 0xf) {
981 /*	case 0x00:	 ASCII */
982 /*	case 0x10:	 X 0201 latin */
983 /*	case 0x20:	 X 0201 kana */
984 /*	case 0x80:	 X 0208 */
985 /*	case 0x90:	 X 0212 */
986 	case 0:
987 		if (c == 0x1b) {
988 			filter->status += 2;
989 		} else if (c == 0x0e) {			/* "kana in" */
990 			filter->status = 0x20;
991 		} else if (c == 0x0f) {			/* "kana out" */
992 			filter->status = 0;
993 		} else if ((filter->status == 0x80 || filter->status == 0x90) && c > 0x20 && c < 0x7f) {		/* kanji first char */
994 			filter->status += 1;
995 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
996 			;
997 		} else {
998 			filter->flag = 1;	/* bad */
999 		}
1000 		break;
1001 
1002 /*	case 0x81:	 X 0208 second char */
1003 /*	case 0x91:	 X 0212 second char */
1004 	case 1:
1005 		filter->status &= ~0xf;
1006 		if (c == 0x1b) {
1007 			goto retry;
1008 		} else if (c < 0x21 || c > 0x7e) {		/* bad */
1009 			filter->flag = 1;
1010 		}
1011 		break;
1012 
1013 	/* ESC */
1014 	case 2:
1015 		if (c == 0x24) {		/* '$' */
1016 			filter->status++;
1017 		} else if (c == 0x28) {		/* '(' */
1018 			filter->status += 3;
1019 		} else {
1020 			filter->flag = 1;	/* bad */
1021 			filter->status &= ~0xf;
1022 			goto retry;
1023 		}
1024 		break;
1025 
1026 	/* ESC $ */
1027 	case 3:
1028 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1029 			filter->status = 0x80;
1030 		} else if (c == 0x28) {		/* '(' */
1031 			filter->status++;
1032 		} else {
1033 			filter->flag = 1;	/* bad */
1034 			filter->status &= ~0xf;
1035 			goto retry;
1036 		}
1037 		break;
1038 
1039 	/* ESC $ ( */
1040 	case 4:
1041 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1042 			filter->status = 0x80;
1043 		} else if (c == 0x44) {		/* 'D' */
1044 			filter->status = 0x90;
1045 		} else {
1046 			filter->flag = 1;	/* bad */
1047 			filter->status &= ~0xf;
1048 			goto retry;
1049 		}
1050 		break;
1051 
1052 	/* ESC ( */
1053 	case 5:
1054 		if (c == 0x42 || c == 0x48) {		/* 'B' or 'H' */
1055 			filter->status = 0;
1056 		} else if (c == 0x4a) {		/* 'J' */
1057 			filter->status = 0x10;
1058 		} else if (c == 0x49) {		/* 'I' */
1059 			filter->status = 0x20;
1060 		} else {
1061 			filter->flag = 1;	/* bad */
1062 			filter->status &= ~0xf;
1063 			goto retry;
1064 		}
1065 		break;
1066 
1067 	default:
1068 		filter->status = 0;
1069 		break;
1070 	}
1071 
1072 	return c;
1073 }
1074 
mbfl_filt_ident_cp50220(int c,mbfl_identify_filter * filter)1075 static int mbfl_filt_ident_cp50220(int c, mbfl_identify_filter *filter)
1076 {
1077 retry:
1078 	switch (filter->status & 0xf) {
1079 /*	case 0x00:	 ASCII */
1080 /*	case 0x10:	 X 0201 latin */
1081 /*	case 0x80:	 X 0208 */
1082 	case 0:
1083 		if (c == 0x1b) {
1084 			filter->status += 2;
1085 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1086 			filter->status += 1;
1087 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1088 			;
1089 		} else {
1090 			filter->flag = 1;	/* bad */
1091 		}
1092 		break;
1093 
1094 /*	case 0x81:	 X 0208 second char */
1095 	case 1:
1096 		if (c == 0x1b) {
1097 			filter->status++;
1098 		} else {
1099 			filter->status &= ~0xf;
1100 			if (c < 0x21 || c > 0x7e) {		/* bad */
1101 				filter->flag = 1;
1102 			}
1103 		}
1104 		break;
1105 
1106 	/* ESC */
1107 	case 2:
1108 		if (c == 0x24) {		/* '$' */
1109 			filter->status++;
1110 		} else if (c == 0x28) {		/* '(' */
1111 			filter->status += 3;
1112 		} else {
1113 			filter->flag = 1;	/* bad */
1114 			filter->status &= ~0xf;
1115 			goto retry;
1116 		}
1117 		break;
1118 
1119 	/* ESC $ */
1120 	case 3:
1121 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1122 			filter->status = 0x80;
1123 		} else {
1124 			filter->flag = 1;	/* bad */
1125 			filter->status &= ~0xf;
1126 			goto retry;
1127 		}
1128 		break;
1129 
1130 	/* ESC ( */
1131 	case 5:
1132 		if (c == 0x42) {		/* 'B' */
1133 			filter->status = 0;
1134 		} else if (c == 0x4a) {		/* 'J' */
1135 			filter->status = 0x10;
1136 		} else {
1137 			filter->flag = 1;	/* bad */
1138 			filter->status &= ~0xf;
1139 			goto retry;
1140 		}
1141 		break;
1142 
1143 	default:
1144 		filter->status = 0;
1145 		break;
1146 	}
1147 
1148 	return c;
1149 }
1150 
mbfl_filt_ident_cp50221(int c,mbfl_identify_filter * filter)1151 static int mbfl_filt_ident_cp50221(int c, mbfl_identify_filter *filter)
1152 {
1153 retry:
1154 	switch (filter->status & 0xf) {
1155 /*	case 0x00:	 ASCII */
1156 /*	case 0x10:	 X 0201 latin */
1157 /*	case 0x80:	 X 0208 */
1158 	case 0:
1159 		if (c == 0x1b) {
1160 			filter->status += 2;
1161 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1162 			filter->status += 1;
1163 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1164 			;
1165 		} else {
1166 			filter->flag = 1;	/* bad */
1167 		}
1168 		break;
1169 
1170 /*	case 0x81:	 X 0208 second char */
1171 	case 1:
1172 		if (c == 0x1b) {
1173 			filter->status++;
1174 		} else {
1175 			filter->status &= ~0xf;
1176 			if (c < 0x21 || c > 0x7e) {		/* bad */
1177 				filter->flag = 1;
1178 			}
1179 		}
1180 		break;
1181 
1182 	/* ESC */
1183 	case 2:
1184 		if (c == 0x24) {		/* '$' */
1185 			filter->status++;
1186 		} else if (c == 0x28) {		/* '(' */
1187 			filter->status += 3;
1188 		} else {
1189 			filter->flag = 1;	/* bad */
1190 			filter->status &= ~0xf;
1191 			goto retry;
1192 		}
1193 		break;
1194 
1195 	/* ESC $ */
1196 	case 3:
1197 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1198 			filter->status = 0x80;
1199 		} else {
1200 			filter->flag = 1;	/* bad */
1201 			filter->status &= ~0xf;
1202 			goto retry;
1203 		}
1204 		break;
1205 
1206 	/* ESC ( */
1207 	case 5:
1208 		if (c == 0x42) {		/* 'B' */
1209 			filter->status = 0;
1210 		} else if (c == 0x4a) {		/* 'J' */
1211 			filter->status = 0x10;
1212 		} else if (c == 0x49) {		/* 'I' */
1213 			filter->status = 0x20;
1214 		} else {
1215 			filter->flag = 1;	/* bad */
1216 			filter->status &= ~0xf;
1217 			goto retry;
1218 		}
1219 		break;
1220 
1221 	default:
1222 		filter->status = 0;
1223 		break;
1224 	}
1225 
1226 	return c;
1227 }
1228 
mbfl_filt_ident_cp50222(int c,mbfl_identify_filter * filter)1229 static int mbfl_filt_ident_cp50222(int c, mbfl_identify_filter *filter)
1230 {
1231 retry:
1232 	switch (filter->status & 0xf) {
1233 /*	case 0x00:	 ASCII */
1234 /*	case 0x10:	 X 0201 latin */
1235 /*	case 0x80:	 X 0208 */
1236 	case 0:
1237 		if (c == 0x1b) {
1238 			filter->status += 2;
1239 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1240 			filter->status += 1;
1241 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1242 			;
1243 		} else {
1244 			filter->flag = 1;	/* bad */
1245 		}
1246 		break;
1247 
1248 /*	case 0x81:	 X 0208 second char */
1249 	case 1:
1250 		if (c == 0x1b) {
1251 			filter->status++;
1252 		} else {
1253 			filter->status &= ~0xf;
1254 			if (c < 0x21 || c > 0x7e) {		/* bad */
1255 				filter->flag = 1;
1256 			}
1257 		}
1258 		break;
1259 
1260 	/* ESC */
1261 	case 2:
1262 		if (c == 0x24) {		/* '$' */
1263 			filter->status++;
1264 		} else if (c == 0x28) {		/* '(' */
1265 			filter->status += 3;
1266 		} else {
1267 			filter->flag = 1;	/* bad */
1268 			filter->status &= ~0xf;
1269 			goto retry;
1270 		}
1271 		break;
1272 
1273 	/* ESC $ */
1274 	case 3:
1275 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1276 			filter->status = 0x80;
1277 		} else {
1278 			filter->flag = 1;	/* bad */
1279 			filter->status &= ~0xf;
1280 			goto retry;
1281 		}
1282 		break;
1283 
1284 	/* ESC ( */
1285 	case 5:
1286 		if (c == 0x42) {		/* 'B' */
1287 			filter->status = 0;
1288 		} else if (c == 0x4a) {		/* 'J' */
1289 			filter->status = 0x10;
1290 		} else {
1291 			filter->flag = 1;	/* bad */
1292 			filter->status &= ~0xf;
1293 			goto retry;
1294 		}
1295 		break;
1296 
1297 	default:
1298 		filter->status = 0;
1299 		break;
1300 	}
1301 
1302 	return c;
1303 }
1304