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