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