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 		CK(mbfl_filt_conv_illegal_output(c, filter));
567 	}
568 
569 	return c;
570 }
571 
572 /*
573  * wchar => CP50220
574  */
575 static void
mbfl_filt_conv_wchar_cp50220_ctor(mbfl_convert_filter * filt)576 mbfl_filt_conv_wchar_cp50220_ctor(mbfl_convert_filter *filt)
577 {
578 	mbfl_filt_conv_wchar_cp50220_ctx *ctx;
579 
580 	mbfl_filt_conv_common_ctor(filt);
581 
582 	ctx = mbfl_malloc(sizeof(mbfl_filt_conv_wchar_cp50220_ctx));
583 	if (ctx == NULL) {
584 		mbfl_filt_conv_common_dtor(filt);
585 		return;
586 	}
587 
588 	ctx->tl_param.mode = MBFL_FILT_TL_HAN2ZEN_KATAKANA | MBFL_FILT_TL_HAN2ZEN_GLUE;
589 
590 	ctx->last = *filt;
591 	ctx->last.opaque = ctx;
592 	ctx->last.data = filt->data;
593 	filt->filter_function = vtbl_tl_jisx0201_jisx0208.filter_function;
594 	filt->filter_flush = vtbl_tl_jisx0201_jisx0208.filter_flush;
595 	filt->output_function = (int(*)(int, void *))ctx->last.filter_function;
596 	filt->flush_function = (int(*)(void *))ctx->last.filter_flush;
597 	filt->data = &ctx->last;
598 	filt->opaque = ctx;
599 	vtbl_tl_jisx0201_jisx0208.filter_ctor(filt);
600 }
601 
602 static void
mbfl_filt_conv_wchar_cp50220_copy(mbfl_convert_filter * src,mbfl_convert_filter * dest)603 mbfl_filt_conv_wchar_cp50220_copy(mbfl_convert_filter *src, mbfl_convert_filter *dest)
604 {
605 	mbfl_filt_conv_wchar_cp50220_ctx *ctx;
606 
607 	*dest = *src;
608 	ctx = mbfl_malloc(sizeof(mbfl_filt_conv_wchar_cp50220_ctx));
609 	if (ctx != NULL) {
610 		*ctx = *(mbfl_filt_conv_wchar_cp50220_ctx*)src->opaque;
611 	}
612 
613 	dest->opaque = ctx;
614 	dest->data = &ctx->last;
615 }
616 
617 static void
mbfl_filt_conv_wchar_cp50220_dtor(mbfl_convert_filter * filt)618 mbfl_filt_conv_wchar_cp50220_dtor(mbfl_convert_filter *filt)
619 {
620 	vtbl_tl_jisx0201_jisx0208.filter_dtor(filt);
621 
622 	if (filt->opaque != NULL) {
623 		mbfl_free(filt->opaque);
624 	}
625 
626 	mbfl_filt_conv_common_dtor(filt);
627 }
628 
629 /*
630  * wchar => cp50220raw
631  */
632 int
mbfl_filt_conv_wchar_cp50220raw(int c,mbfl_convert_filter * filter)633 mbfl_filt_conv_wchar_cp50220raw(int c, mbfl_convert_filter *filter)
634 {
635 	if (c & MBFL_WCSPLANE_JIS0208) {
636 		const int s = c & MBFL_WCSPLANE_MASK;
637 
638 		if ((filter->status & 0xff00) != 0x200) {
639 			CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
640 			CK((*filter->output_function)(0x24, filter->data));		/* '$' */
641 			CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
642 			filter->status = 0x200;
643 		}
644 		CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
645 		CK((*filter->output_function)(s & 0x7f, filter->data));
646 		return c;
647 	} else {
648 		return mbfl_filt_conv_wchar_cp50221(c, filter);
649 	}
650 }
651 
652 /*
653  * wchar => CP50221
654  */
655 int
mbfl_filt_conv_wchar_cp50221(int c,mbfl_convert_filter * filter)656 mbfl_filt_conv_wchar_cp50221(int c, mbfl_convert_filter *filter)
657 {
658 	int s = 0;
659 
660 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
661 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
662 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
663 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
664 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
665 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
666 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
667 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
668 	} else if (c >= 0xe000 && c < (0xe000 + 10 * 94)) {
669 		/* PUE => Microsoft extended */
670 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
671 		s = c - 0xe000;
672 		s = (s / 94 + 0x75) << 8 | (s % 94 + 0x21);
673 	} else if (c >= (0xe000 + 10 * 94) && c <= (0xe000 + 20 * 94)) {
674 		/* PUE => JISX0212 user-defined (G3 85ku - 94ku) */
675 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
676 		s = c - (0xe000 + 10 * 94);
677 		s = (s / 94 + 0xf5) << 8 | (s % 94 + 0xa1);
678 	}
679 
680 	if (s <= 0) {
681 		if (c == 0xa5) {			/* YEN SIGN */
682 			s = 0x1005c;
683 		} else if (c == 0x203e) {	/* OVER LINE */
684 			s = 0x1007e;
685 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
686 			s = 0x2140;
687 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
688 			s = 0x2141;
689 		} else if (c == 0x2225) {	/* PARALLEL TO */
690 			s = 0x2142;
691 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
692 			s = 0x215d;
693 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
694 			s = 0x2171;
695 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
696 			s = 0x2172;
697 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
698 			s = 0x224c;
699 		}
700 	}
701 	if (s <= 0 || (s >= 0x8080 && s < 0x10000)) {
702 		int i;
703 		s = -1;
704 
705 		for (i = 0;
706 				i < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min;
707 				i++) {
708 			const int oh = cp932ext1_ucs_table_min / 94;
709 
710 			if (c == cp932ext1_ucs_table[i]) {
711 				s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
712 				break;
713 			}
714 		}
715 
716 		if (s < 0) {
717 			const int oh = cp932ext2_ucs_table_min / 94;
718 			const int cp932ext2_ucs_table_size =
719 					cp932ext2_ucs_table_max - cp932ext2_ucs_table_min;
720 			for (i = 0; i < cp932ext2_ucs_table_size; i++) {
721 				if (c == cp932ext2_ucs_table[i]) {
722 					s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
723 					break;
724 				}
725 			}
726 		}
727 
728 		if (s < 0) {
729 			const int cp932ext3_ucs_table_size =
730 					cp932ext3_ucs_table_max - cp932ext3_ucs_table_min;
731 			const int limit = cp932ext3_ucs_table_size >
732 					cp932ext3_eucjp_table_size ?
733 						cp932ext3_eucjp_table_size:
734 						cp932ext3_ucs_table_size;
735 			for (i = 0; i < limit; i++) {
736 				if (c == cp932ext3_ucs_table[i]) {
737 					s = cp932ext3_eucjp_table[i];
738 					break;
739 				}
740 			}
741 		}
742 
743 		if (c == 0) {
744 			s = 0;
745 		} else if (s <= 0) {
746 			s = -1;
747 		}
748 	}
749 
750 	if (s >= 0) {
751 		if (s < 0x80) { /* ASCII */
752 			if ((filter->status & 0xff00) != 0) {
753 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
754 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
755 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
756 				filter->status = 0;
757 			}
758 			CK((*filter->output_function)(s, filter->data));
759 		} else if (s >= 0xa0 && s < 0xe0) { /* X 0201 kana */
760 			if ((filter->status & 0xff00) != 0x500) {
761 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
762 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
763 				CK((*filter->output_function)(0x49, filter->data));		/* 'I' */
764 				filter->status = 0x500;
765 			}
766 			CK((*filter->output_function)(s - 0x80, filter->data));
767 		} else if (s < 0x8080) { /* X 0208 */
768 			if ((filter->status & 0xff00) != 0x200) {
769 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
770 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
771 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
772 				filter->status = 0x200;
773 			}
774 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
775 			CK((*filter->output_function)(s & 0x7f, filter->data));
776 		} else if (s < 0x10000) { /* X0212 */
777 			CK(mbfl_filt_conv_illegal_output(c, filter));
778 		} else { /* X 0201 latin */
779 			if ((filter->status & 0xff00) != 0x400) {
780 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
781 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
782 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
783 			}
784 			filter->status = 0x400;
785 			CK((*filter->output_function)(s & 0x7f, filter->data));
786 		}
787 	} else {
788 		CK(mbfl_filt_conv_illegal_output(c, filter));
789 	}
790 
791 	return c;
792 }
793 
794 /*
795  * wchar => CP50222
796  */
797 int
mbfl_filt_conv_wchar_cp50222(int c,mbfl_convert_filter * filter)798 mbfl_filt_conv_wchar_cp50222(int c, mbfl_convert_filter *filter)
799 {
800 	int s;
801 
802 	s = 0;
803 
804 	if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) {
805 		s = ucs_a1_jis_table[c - ucs_a1_jis_table_min];
806 	} else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) {
807 		s = ucs_a2_jis_table[c - ucs_a2_jis_table_min];
808 	} else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) {
809 		s = ucs_i_jis_table[c - ucs_i_jis_table_min];
810 	} else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) {
811 		s = ucs_r_jis_table[c - ucs_r_jis_table_min];
812 	} else if (c >= 0xe000 && c < (0xe000 + 10 * 94)) {
813 		/* PUE => Microsoft extended */
814 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
815 		s = c - 0xe000;
816 		s = (s / 94 + 0x75) << 8 | (s % 94 + 0x21);
817 	} else if (c >= (0xe000 + 10 * 94) && c <= (0xe000 + 20 * 94)) {
818 		/* PUE => JISX0212 user-defined (G3 85ku - 94ku) */
819 		/* See http://www.opengroup.or.jp/jvc/cde/ucs-conv.html#ch4_2 */
820 		s = c - (0xe000 + 10 * 94);
821 		s = (s / 94 + 0xf5) << 8 | (s % 94 + 0xa1);
822 	}
823 
824 	if (s <= 0) {
825 		if (c == 0xa5) {			/* YEN SIGN */
826 			s = 0x1005c;
827 		} else if (c == 0x203e) {	/* OVER LINE */
828 			s = 0x1007e;
829 		} else if (c == 0xff3c) {	/* FULLWIDTH REVERSE SOLIDUS */
830 			s = 0x2140;
831 		} else if (c == 0xff5e) {	/* FULLWIDTH TILDE */
832 			s = 0x2141;
833 		} else if (c == 0x2225) {	/* PARALLEL TO */
834 			s = 0x2142;
835 		} else if (c == 0xff0d) {	/* FULLWIDTH HYPHEN-MINUS */
836 			s = 0x215d;
837 		} else if (c == 0xffe0) {	/* FULLWIDTH CENT SIGN */
838 			s = 0x2171;
839 		} else if (c == 0xffe1) {	/* FULLWIDTH POUND SIGN */
840 			s = 0x2172;
841 		} else if (c == 0xffe2) {	/* FULLWIDTH NOT SIGN */
842 			s = 0x224c;
843 		}
844 	}
845 	if (s <= 0 || (s >= 0x8080 && s < 0x10000)) {
846 		int i;
847 		s = -1;
848 
849 		for (i = 0;
850 				i < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; i++) {
851 			const int oh = cp932ext1_ucs_table_min / 94;
852 
853 			if (c == cp932ext1_ucs_table[i]) {
854 				s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
855 				break;
856 			}
857 		}
858 
859 		if (s <= 0) {
860 			const int oh = cp932ext2_ucs_table_min / 94;
861 			const int cp932ext2_ucs_table_size =
862 					cp932ext2_ucs_table_max - cp932ext2_ucs_table_min;
863 			for (i = 0; i < cp932ext2_ucs_table_size; i++) {
864 				if (c == cp932ext2_ucs_table[i]) {
865 					s = ((i / 94 + oh + 0x21) << 8) + (i % 94 + 0x21);
866 					break;
867 				}
868 			}
869 		}
870 
871 		if (s <= 0) {
872 			const int cp932ext3_ucs_table_size =
873 					cp932ext3_ucs_table_max - cp932ext3_ucs_table_min;
874 			const int limit = cp932ext3_ucs_table_size >
875 					cp932ext3_eucjp_table_size ?
876 						cp932ext3_eucjp_table_size:
877 						cp932ext3_ucs_table_size;
878 			for (i = 0; i < limit; i++) {
879 				if (c == cp932ext3_ucs_table[i]) {
880 					s = cp932ext3_eucjp_table[i];
881 					break;
882 				}
883 			}
884 		}
885 
886 		if (c == 0) {
887 			s = 0;
888 		} else if (s <= 0) {
889 			s = -1;
890 		}
891 	}
892 
893 	if (s >= 0) {
894 		if (s < 0x80) { /* ASCII */
895 			if ((filter->status & 0xff00) == 0x500) {
896 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
897 				filter->status = 0;
898 			} else if ((filter->status & 0xff00) != 0) {
899 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
900 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
901 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
902 				filter->status = 0;
903 			}
904 			CK((*filter->output_function)(s, filter->data));
905 		} else if (s >= 0xa0 && s < 0xe0) { /* X 0201 kana */
906 			if ((filter->status & 0xff00) != 0x500) {
907 				CK((*filter->output_function)(0x0e, filter->data));		/* SI */
908 				filter->status = 0x500;
909 			}
910 			CK((*filter->output_function)(s - 0x80, filter->data));
911 		} else if (s < 0x8080) { /* X 0208 */
912 			if ((filter->status & 0xff00) == 0x500) {
913 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
914 				filter->status = 0;
915 			}
916 			if ((filter->status & 0xff00) != 0x200) {
917 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
918 				CK((*filter->output_function)(0x24, filter->data));		/* '$' */
919 				CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
920 				filter->status = 0x200;
921 			}
922 			CK((*filter->output_function)((s >> 8) & 0x7f, filter->data));
923 			CK((*filter->output_function)(s & 0x7f, filter->data));
924 		} else if (s < 0x10000) { /* X0212 */
925 			CK(mbfl_filt_conv_illegal_output(c, filter));
926 		} else { /* X 0201 latin */
927 			if ((filter->status & 0xff00) == 0x500) {
928 				CK((*filter->output_function)(0x0f, filter->data));		/* SO */
929 				filter->status = 0;
930 			}
931 			if ((filter->status & 0xff00) != 0x400) {
932 				CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
933 				CK((*filter->output_function)(0x28, filter->data));		/* '(' */
934 				CK((*filter->output_function)(0x4a, filter->data));		/* 'J' */
935 			}
936 			filter->status = 0x400;
937 			CK((*filter->output_function)(s & 0x7f, filter->data));
938 		}
939 	} else {
940 		CK(mbfl_filt_conv_illegal_output(c, filter));
941 	}
942 
943 	return c;
944 }
945 
946 int
mbfl_filt_conv_wchar_cp50222_flush(mbfl_convert_filter * filter)947 mbfl_filt_conv_wchar_cp50222_flush(mbfl_convert_filter *filter)
948 {
949 	/* back to latin */
950 	if ((filter->status & 0xff00) == 0x500) {
951 		CK((*filter->output_function)(0x0f, filter->data));		/* SO */
952 	} else if ((filter->status & 0xff00) != 0) {
953 		CK((*filter->output_function)(0x1b, filter->data));		/* ESC */
954 		CK((*filter->output_function)(0x28, filter->data));		/* '(' */
955 		CK((*filter->output_function)(0x42, filter->data));		/* 'B' */
956 	}
957 	filter->status &= 0xff;
958 
959 	if (filter->flush_function != NULL) {
960 		return (*filter->flush_function)(filter->data);
961 	}
962 
963 	return 0;
964 }
965 
966 
mbfl_filt_ident_jis_ms(int c,mbfl_identify_filter * filter)967 static int mbfl_filt_ident_jis_ms(int c, mbfl_identify_filter *filter)
968 {
969 retry:
970 	switch (filter->status & 0xf) {
971 /*	case 0x00:	 ASCII */
972 /*	case 0x10:	 X 0201 latin */
973 /*	case 0x20:	 X 0201 kana */
974 /*	case 0x80:	 X 0208 */
975 /*	case 0x90:	 X 0212 */
976 	case 0:
977 		if (c == 0x1b) {
978 			filter->status += 2;
979 		} else if (c == 0x0e) {			/* "kana in" */
980 			filter->status = 0x20;
981 		} else if (c == 0x0f) {			/* "kana out" */
982 			filter->status = 0;
983 		} else if ((filter->status == 0x80 || filter->status == 0x90) && c > 0x20 && c < 0x7f) {		/* kanji first char */
984 			filter->status += 1;
985 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
986 			;
987 		} else {
988 			filter->flag = 1;	/* bad */
989 		}
990 		break;
991 
992 /*	case 0x81:	 X 0208 second char */
993 /*	case 0x91:	 X 0212 second char */
994 	case 1:
995 		filter->status &= ~0xf;
996 		if (c == 0x1b) {
997 			goto retry;
998 		} else if (c < 0x21 || c > 0x7e) {		/* bad */
999 			filter->flag = 1;
1000 		}
1001 		break;
1002 
1003 	/* ESC */
1004 	case 2:
1005 		if (c == 0x24) {		/* '$' */
1006 			filter->status++;
1007 		} else if (c == 0x28) {		/* '(' */
1008 			filter->status += 3;
1009 		} else {
1010 			filter->flag = 1;	/* bad */
1011 			filter->status &= ~0xf;
1012 			goto retry;
1013 		}
1014 		break;
1015 
1016 	/* ESC $ */
1017 	case 3:
1018 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1019 			filter->status = 0x80;
1020 		} else if (c == 0x28) {		/* '(' */
1021 			filter->status++;
1022 		} else {
1023 			filter->flag = 1;	/* bad */
1024 			filter->status &= ~0xf;
1025 			goto retry;
1026 		}
1027 		break;
1028 
1029 	/* ESC $ ( */
1030 	case 4:
1031 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1032 			filter->status = 0x80;
1033 		} else if (c == 0x44) {		/* 'D' */
1034 			filter->status = 0x90;
1035 		} else {
1036 			filter->flag = 1;	/* bad */
1037 			filter->status &= ~0xf;
1038 			goto retry;
1039 		}
1040 		break;
1041 
1042 	/* ESC ( */
1043 	case 5:
1044 		if (c == 0x42 || c == 0x48) {		/* 'B' or 'H' */
1045 			filter->status = 0;
1046 		} else if (c == 0x4a) {		/* 'J' */
1047 			filter->status = 0x10;
1048 		} else if (c == 0x49) {		/* 'I' */
1049 			filter->status = 0x20;
1050 		} else {
1051 			filter->flag = 1;	/* bad */
1052 			filter->status &= ~0xf;
1053 			goto retry;
1054 		}
1055 		break;
1056 
1057 	default:
1058 		filter->status = 0;
1059 		break;
1060 	}
1061 
1062 	return c;
1063 }
1064 
mbfl_filt_ident_cp50220(int c,mbfl_identify_filter * filter)1065 static int mbfl_filt_ident_cp50220(int c, mbfl_identify_filter *filter)
1066 {
1067 retry:
1068 	switch (filter->status & 0xf) {
1069 /*	case 0x00:	 ASCII */
1070 /*	case 0x10:	 X 0201 latin */
1071 /*	case 0x80:	 X 0208 */
1072 	case 0:
1073 		if (c == 0x1b) {
1074 			filter->status += 2;
1075 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1076 			filter->status += 1;
1077 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1078 			;
1079 		} else {
1080 			filter->flag = 1;	/* bad */
1081 		}
1082 		break;
1083 
1084 /*	case 0x81:	 X 0208 second char */
1085 	case 1:
1086 		if (c == 0x1b) {
1087 			filter->status++;
1088 		} else {
1089 			filter->status &= ~0xf;
1090 			if (c < 0x21 || c > 0x7e) {		/* bad */
1091 				filter->flag = 1;
1092 			}
1093 		}
1094 		break;
1095 
1096 	/* ESC */
1097 	case 2:
1098 		if (c == 0x24) {		/* '$' */
1099 			filter->status++;
1100 		} else if (c == 0x28) {		/* '(' */
1101 			filter->status += 3;
1102 		} else {
1103 			filter->flag = 1;	/* bad */
1104 			filter->status &= ~0xf;
1105 			goto retry;
1106 		}
1107 		break;
1108 
1109 	/* ESC $ */
1110 	case 3:
1111 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1112 			filter->status = 0x80;
1113 		} else {
1114 			filter->flag = 1;	/* bad */
1115 			filter->status &= ~0xf;
1116 			goto retry;
1117 		}
1118 		break;
1119 
1120 	/* ESC ( */
1121 	case 5:
1122 		if (c == 0x42) {		/* 'B' */
1123 			filter->status = 0;
1124 		} else if (c == 0x4a) {		/* 'J' */
1125 			filter->status = 0x10;
1126 		} else {
1127 			filter->flag = 1;	/* bad */
1128 			filter->status &= ~0xf;
1129 			goto retry;
1130 		}
1131 		break;
1132 
1133 	default:
1134 		filter->status = 0;
1135 		break;
1136 	}
1137 
1138 	return c;
1139 }
1140 
mbfl_filt_ident_cp50221(int c,mbfl_identify_filter * filter)1141 static int mbfl_filt_ident_cp50221(int c, mbfl_identify_filter *filter)
1142 {
1143 retry:
1144 	switch (filter->status & 0xf) {
1145 /*	case 0x00:	 ASCII */
1146 /*	case 0x10:	 X 0201 latin */
1147 /*	case 0x80:	 X 0208 */
1148 	case 0:
1149 		if (c == 0x1b) {
1150 			filter->status += 2;
1151 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1152 			filter->status += 1;
1153 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1154 			;
1155 		} else {
1156 			filter->flag = 1;	/* bad */
1157 		}
1158 		break;
1159 
1160 /*	case 0x81:	 X 0208 second char */
1161 	case 1:
1162 		if (c == 0x1b) {
1163 			filter->status++;
1164 		} else {
1165 			filter->status &= ~0xf;
1166 			if (c < 0x21 || c > 0x7e) {		/* bad */
1167 				filter->flag = 1;
1168 			}
1169 		}
1170 		break;
1171 
1172 	/* ESC */
1173 	case 2:
1174 		if (c == 0x24) {		/* '$' */
1175 			filter->status++;
1176 		} else if (c == 0x28) {		/* '(' */
1177 			filter->status += 3;
1178 		} else {
1179 			filter->flag = 1;	/* bad */
1180 			filter->status &= ~0xf;
1181 			goto retry;
1182 		}
1183 		break;
1184 
1185 	/* ESC $ */
1186 	case 3:
1187 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1188 			filter->status = 0x80;
1189 		} else {
1190 			filter->flag = 1;	/* bad */
1191 			filter->status &= ~0xf;
1192 			goto retry;
1193 		}
1194 		break;
1195 
1196 	/* ESC ( */
1197 	case 5:
1198 		if (c == 0x42) {		/* 'B' */
1199 			filter->status = 0;
1200 		} else if (c == 0x4a) {		/* 'J' */
1201 			filter->status = 0x10;
1202 		} else if (c == 0x49) {		/* 'I' */
1203 			filter->status = 0x20;
1204 		} else {
1205 			filter->flag = 1;	/* bad */
1206 			filter->status &= ~0xf;
1207 			goto retry;
1208 		}
1209 		break;
1210 
1211 	default:
1212 		filter->status = 0;
1213 		break;
1214 	}
1215 
1216 	return c;
1217 }
1218 
mbfl_filt_ident_cp50222(int c,mbfl_identify_filter * filter)1219 static int mbfl_filt_ident_cp50222(int c, mbfl_identify_filter *filter)
1220 {
1221 retry:
1222 	switch (filter->status & 0xf) {
1223 /*	case 0x00:	 ASCII */
1224 /*	case 0x10:	 X 0201 latin */
1225 /*	case 0x80:	 X 0208 */
1226 	case 0:
1227 		if (c == 0x1b) {
1228 			filter->status += 2;
1229 		} else if (filter->status == 0x80 && c > 0x20 && c < 0x7f) {		/* kanji first char */
1230 			filter->status += 1;
1231 		} else if (c >= 0 && c < 0x80) {		/* latin, CTLs */
1232 			;
1233 		} else {
1234 			filter->flag = 1;	/* bad */
1235 		}
1236 		break;
1237 
1238 /*	case 0x81:	 X 0208 second char */
1239 	case 1:
1240 		if (c == 0x1b) {
1241 			filter->status++;
1242 		} else {
1243 			filter->status &= ~0xf;
1244 			if (c < 0x21 || c > 0x7e) {		/* bad */
1245 				filter->flag = 1;
1246 			}
1247 		}
1248 		break;
1249 
1250 	/* ESC */
1251 	case 2:
1252 		if (c == 0x24) {		/* '$' */
1253 			filter->status++;
1254 		} else if (c == 0x28) {		/* '(' */
1255 			filter->status += 3;
1256 		} else {
1257 			filter->flag = 1;	/* bad */
1258 			filter->status &= ~0xf;
1259 			goto retry;
1260 		}
1261 		break;
1262 
1263 	/* ESC $ */
1264 	case 3:
1265 		if (c == 0x40 || c == 0x42) {		/* '@' or 'B' */
1266 			filter->status = 0x80;
1267 		} else {
1268 			filter->flag = 1;	/* bad */
1269 			filter->status &= ~0xf;
1270 			goto retry;
1271 		}
1272 		break;
1273 
1274 	/* ESC ( */
1275 	case 5:
1276 		if (c == 0x42) {		/* 'B' */
1277 			filter->status = 0;
1278 		} else if (c == 0x4a) {		/* 'J' */
1279 			filter->status = 0x10;
1280 		} else {
1281 			filter->flag = 1;	/* bad */
1282 			filter->status &= ~0xf;
1283 			goto retry;
1284 		}
1285 		break;
1286 
1287 	default:
1288 		filter->status = 0;
1289 		break;
1290 	}
1291 
1292 	return c;
1293 }
1294