1/*
2 * "streamable kanji code filter and converter"
3 * Copyright (c) 1998-2002 HappySize, Inc. All rights reserved.
4 *
5 * LICENSE NOTICES
6 *
7 * This file is part of "streamable kanji code filter and converter",
8 * which is distributed under the terms of GNU Lesser General Public
9 * License (version 2) as published by the Free Software Foundation.
10 *
11 * This software is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with "streamable kanji code filter and converter";
18 * if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 * Suite 330, Boston, MA  02111-1307  USA
20 *
21 * The author of this file:
22 *
23 */
24/*
25 * The source code included in this files was separated from mbfilter_sjis.c
26 * by rui hirokawa <hirokawa@php.net> on 15 aug 2011.
27 *
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "mbfilter.h"
35#include "mbfilter_sjis_2004.h"
36
37#include "unicode_table_jis2004.h"
38#include "unicode_table_jis.h"
39
40extern const unsigned char mblen_table_sjis[];
41
42static int mbfl_filt_ident_sjis2004(int c, mbfl_identify_filter *filter);
43
44extern int mbfl_filt_ident_sjis(int c, mbfl_identify_filter *filter);
45extern int mbfl_bisec_srch(int w, const unsigned short *tbl, int n);
46extern int mbfl_bisec_srch2(int w, const unsigned short tbl[], int n);
47
48static const char *mbfl_encoding_sjis2004_aliases[] = {"SJIS2004","Shift_JIS-2004", NULL};
49
50const mbfl_encoding mbfl_encoding_sjis2004 = {
51    mbfl_no_encoding_sjis2004,
52    "SJIS-2004",
53    "Shift_JIS",
54    (const char *(*)[])&mbfl_encoding_sjis2004_aliases,
55    mblen_table_sjis,
56    MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
57};
58
59const struct mbfl_identify_vtbl vtbl_identify_sjis2004 = {
60    mbfl_no_encoding_sjis2004,
61    mbfl_filt_ident_common_ctor,
62    mbfl_filt_ident_common_dtor,
63    mbfl_filt_ident_sjis
64};
65
66const struct mbfl_convert_vtbl vtbl_sjis2004_wchar = {
67    mbfl_no_encoding_sjis2004,
68    mbfl_no_encoding_wchar,
69    mbfl_filt_conv_common_ctor,
70    mbfl_filt_conv_common_dtor,
71    mbfl_filt_conv_jis2004_wchar,
72    mbfl_filt_conv_common_flush
73};
74
75const struct mbfl_convert_vtbl vtbl_wchar_sjis2004 = {
76    mbfl_no_encoding_wchar,
77    mbfl_no_encoding_sjis2004,
78    mbfl_filt_conv_common_ctor,
79    mbfl_filt_conv_common_dtor,
80    mbfl_filt_conv_wchar_jis2004,
81    mbfl_filt_conv_jis2004_flush
82};
83
84#define CK(statement)   do { if ((statement) < 0) return (-1); } while (0)
85
86#define SJIS_ENCODE(c1,c2,s1,s2)    \
87        do {                        \
88            s1 = c1;                \
89            s1--;                   \
90            s1 >>= 1;               \
91            if ((c1) < 0x5f) {      \
92                s1 += 0x71;         \
93            } else {                \
94                s1 += 0xb1;         \
95            }                       \
96            s2 = c2;                \
97            if ((c1) & 1) {         \
98                if ((c2) < 0x60) {  \
99                    s2--;           \
100                }                   \
101                s2 += 0x20;         \
102            } else {                \
103                s2 += 0x7e;         \
104            }                       \
105        } while (0)
106
107#define SJIS_DECODE(c1,c2,s1,s2)    \
108        do {                        \
109            s1 = c1;                \
110            if (s1 < 0xa0) {        \
111                s1 -= 0x81;         \
112            } else {                \
113                s1 -= 0xc1;         \
114            }                       \
115            s1 <<= 1;               \
116            s1 += 0x21;             \
117            s2 = c2;                \
118            if (s2 < 0x9f) {        \
119                if (s2 < 0x7f) {    \
120                    s2++;           \
121                }                   \
122                s2 -= 0x20;         \
123            } else {                \
124                s1++;               \
125                s2 -= 0x7e;         \
126            }                       \
127        } while (0)
128
129
130/*
131 * JIS-2004 => wchar
132 */
133int
134mbfl_filt_conv_jis2004_wchar(int c, mbfl_convert_filter *filter)
135{
136    int k;
137    int c1, c2, s, s1 = 0, s2 = 0, w = 0, w1;
138
139retry:
140    switch (filter->status & 0xf) {
141    case 0:
142        if (c >= 0 && c < 0x80) {   /* latin */
143            if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
144                CK((*filter->output_function)(c, filter->data));
145            } else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
146                if (c == 0x5c) {
147                    CK((*filter->output_function)(0x00a5, filter->data));
148                } else if (c == 0x7e) {
149                    CK((*filter->output_function)(0x203e, filter->data));
150                } else {
151                    CK((*filter->output_function)(c, filter->data));
152                }
153            } else { /* ISO-2022-JP-2004 */
154                if (c == 0x1b) {
155                    filter->status += 6;
156                } else if ((filter->status == 0x80 || filter->status == 0x90 || filter->status == 0xa0)
157                   && c > 0x20 && c < 0x7f) {       /* kanji first char */
158                    filter->cache = c;
159                    if (filter->status == 0x90) {
160                        filter->status += 1; /* JIS X 0213 plane 1 */
161                    } else if (filter->status == 0xa0) {
162                        filter->status += 4; /* JIS X 0213 plane 2 */
163                    } else {
164                        filter->status += 5; /* JIS X 0208 */
165                    }
166                } else {
167                    CK((*filter->output_function)(c, filter->data));
168                }
169            }
170        } else {
171            if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
172                if (c > 0xa0 && c < 0xff) { /* X 0213 plane 1 first char */
173                    filter->status = 1;
174                    filter->cache = c;
175                } else if (c == 0x8e) { /* kana first char */
176                    filter->status = 2;
177                } else if (c == 0x8f) { /* X 0213 plane 2 first char */
178                    filter->status = 3;
179                } else {
180                    w = c & MBFL_WCSGROUP_MASK;
181                    w |= MBFL_WCSGROUP_THROUGH;
182                    CK((*filter->output_function)(w, filter->data));
183                }
184            } else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
185                if (c > 0xa0 && c < 0xe0) { /* kana */
186                    CK((*filter->output_function)(0xfec0 + c, filter->data));
187                } else if (c > 0x80 && c < 0xfd && c != 0xa0) { /* kanji first char */
188                    filter->status = 1;
189                    filter->cache = c;
190                } else {
191                    w = c & MBFL_WCSGROUP_MASK;
192                    w |= MBFL_WCSGROUP_THROUGH;
193                    CK((*filter->output_function)(w, filter->data));
194                }
195            } else {
196                w = c & MBFL_WCSGROUP_MASK;
197                w |= MBFL_WCSGROUP_THROUGH;
198                CK((*filter->output_function)(w, filter->data));
199            }
200        }
201        break;
202
203    case 1:     /* kanji second char */
204        filter->status &= ~0xf;
205        c1 = filter->cache;
206
207        if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
208            if (c > 0xa0 && c < 0xff) {
209                s1 = c1 - 0x80;
210                s2 = c - 0x80;
211            }
212        } else if (filter->from->no_encoding == mbfl_no_encoding_sjis2004) {
213            if (c >= 0x40 && c <= 0xfc && c != 0x7f) {
214                SJIS_DECODE(c1, c, s1, s2);
215            }
216        } else {
217            s1 = c1;
218            s2 = c;
219        }
220        w1 = (s1 << 8) | s2;
221
222        if (w1 >= 0x2121) {
223            /* conversion for combining characters */
224            if ((w1 >= 0x2477 && w1 <= 0x2479) || (w1 >= 0x2479 && w1 <= 0x247B) ||
225                (w1 >= 0x2577 && w1 <= 0x257E) || w1 == 0x2678 || w1 == 0x2B44 ||
226                (w1 >= 0x2B48 && w1 <= 0x2B4F) || (w1 >= 0x2B65 && w1 <= 0x2B66)) {
227                k = mbfl_bisec_srch2(w1, jisx0213_u2_key, jisx0213_u2_tbl_len);
228                if (k >= 0) {
229                    w = jisx0213_u2_tbl[2*k];
230                    CK((*filter->output_function)(w, filter->data));
231                    w = jisx0213_u2_tbl[2*k+1];
232                }
233            }
234
235            /* conversion for BMP  */
236            if (w <= 0) {
237                w1 = (s1 - 0x21)*94 + s2 - 0x21;
238                if (w1 >= 0 && w1 < jisx0213_ucs_table_size) {
239                    w = jisx0213_ucs_table[w1];
240                }
241            }
242
243            /* conversion for CJK Unified Ideographs ext.B (U+2XXXX) */
244            if (w <= 0) {
245                w1 = (s1 << 8) | s2;
246                k = mbfl_bisec_srch2(w1, jisx0213_jis_u5_key, jisx0213_u5_tbl_len);
247                if (k >= 0) {
248                    w = jisx0213_jis_u5_tbl[k] + 0x20000;
249                }
250            }
251
252            if (w <= 0) {
253                if (s1 < 0x7f && s2 < 0x7f) {
254                    w = (s1 << 8) | s2;
255                    w &= MBFL_WCSPLANE_MASK;
256                    w |= MBFL_WCSPLANE_JIS0213;
257                } else {
258                    w = (c1 << 8) | c;
259                    w &= MBFL_WCSGROUP_MASK;
260                    w |= MBFL_WCSGROUP_THROUGH;
261                }
262            }
263            CK((*filter->output_function)(w, filter->data));
264        } else if ((c >= 0 && c < 0x21) || c == 0x7f) {     /* CTLs */
265            CK((*filter->output_function)(c, filter->data));
266        } else {
267            w = (c1 << 8) | c;
268            w &= MBFL_WCSGROUP_MASK;
269            w |= MBFL_WCSGROUP_THROUGH;
270            CK((*filter->output_function)(w, filter->data));
271        }
272        break;
273
274    case 2: /* got 0x8e : EUC-JP-2004 kana */
275        filter->status = 0;
276        if (c > 0xa0 && c < 0xe0) {
277            w = 0xfec0 + c;
278            CK((*filter->output_function)(w, filter->data));
279        } else if ((c >= 0 && c < 0x21) || c == 0x7f) {     /* CTLs */
280            CK((*filter->output_function)(c, filter->data));
281        } else {
282            w = 0x8e00 | c;
283            w &= MBFL_WCSGROUP_MASK;
284            w |= MBFL_WCSGROUP_THROUGH;
285            CK((*filter->output_function)(w, filter->data));
286        }
287        break;
288
289    case 3: /* X 0213 plane 2 first char : EUC-JP-2004 (0x8f), ISO-2022-JP-2004 */
290        if ((c >= 0 && c < 0x21) || c == 0x7f) {        /* CTLs */
291            CK((*filter->output_function)(c, filter->data));
292            filter->status = 0;
293        } else {
294            if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
295                s1 = c - 0x80;
296            } else {
297                s1 = c;
298            }
299            if (s1 > 0x20 && s1 < 0x80) {
300                filter->cache = s1;
301                filter->status++;
302            } else {
303                if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
304                    w = c | 0x8f00;
305                    w &= MBFL_WCSGROUP_MASK;
306                    w |= MBFL_WCSGROUP_THROUGH;
307                } else {
308                    w = c & 0x7f;
309                    w &= MBFL_WCSPLANE_MASK;
310                    w |= MBFL_WCSPLANE_JIS0213;
311                }
312                CK((*filter->output_function)(w, filter->data));
313            }
314        }
315        break;
316
317    case 4: /* X 0213 plane 2 second char : EUC-JP-2004, ISO-2022-JP-2004 */
318
319        filter->status &= ~0xf;
320        c1 = filter->cache;
321        if (filter->from->no_encoding == mbfl_no_encoding_eucjp2004) {
322            c2 = c - 0x80;
323        } else {
324            c2 = c;
325        }
326        s1 = c1 - 0x21;
327        s2 = c2 - 0x21;
328
329        if (((s1 >= 0 && s1 <= 4 && s1 != 1) || s1 == 7 || (s1 >= 11 && s1 <= 14) ||
330            (s1 >= 77 && s1 < 94)) && s2 >= 0 && s2 < 94) {
331            /* calc offset from ku */
332            for (k = 0; k < jisx0213_p2_ofst_len; k++) {
333                if (s1 == jisx0213_p2_ofst[k]-1) {
334                    break;
335                }
336            }
337            k = k - (jisx0213_p2_ofst[k]-1);
338
339            /* check for japanese chars in BMP */
340            s = (s1 + 94 + k)*94 + s2;
341            if (s >= 0 && s < jisx0213_ucs_table_size) {
342                w = jisx0213_ucs_table[s];
343            } else {
344                w = 0;
345            }
346
347            /* check for japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */
348            if (w <= 0) {
349                w1 = ((c1 + k + 94) << 8) | c2;
350                k = mbfl_bisec_srch2(w1, jisx0213_jis_u5_key, jisx0213_u5_tbl_len);
351                if (k >= 0) {
352                    w = jisx0213_jis_u5_tbl[k] + 0x20000;
353                }
354            }
355
356            if (w <= 0) {
357                w = ((c1 & 0x7f) << 8) | (c2 & 0x7f);
358                w &= MBFL_WCSPLANE_MASK;
359                w |= MBFL_WCSPLANE_JIS0213;
360            }
361
362            CK((*filter->output_function)(w, filter->data));
363        } else if ((c >= 0 && c < 0x21) || c == 0x7f) {     /* CTLs */
364            CK((*filter->output_function)(c, filter->data));
365        } else {
366            if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
367                w = (c1 << 8) | c | 0x8f0000;
368                w &= MBFL_WCSGROUP_MASK;
369                w |= MBFL_WCSGROUP_THROUGH;
370            } else {
371                w = ((c1 & 0x7f) << 8) | (c2 & 0x7f);
372                w &= MBFL_WCSPLANE_MASK;
373                w |= MBFL_WCSPLANE_JIS0213;
374            }
375            CK((*filter->output_function)(w, filter->data));
376        }
377
378        break;
379
380    case 5: /* X 0208 : ISO-2022-JP-2004 */
381        filter->status &= ~0xf;
382        c1 = filter->cache;
383        if (c > 0x20 && c < 0x7f) {
384            s = (c1 - 0x21)*94 + c - 0x21;
385            if (s >= 0 && s < jisx0208_ucs_table_size) {
386                w = jisx0208_ucs_table[s];
387            }
388        }
389        if (w <= 0) {
390            w = (c1 << 8) | c;
391            w &= MBFL_WCSPLANE_MASK;
392            w |= MBFL_WCSPLANE_JIS0208;
393        }
394        CK((*filter->output_function)(w, filter->data));
395        break;
396
397    /* ESC : ISO-2022-JP-2004 */
398/*  case 0x06:  */
399/*  case 0x16:  */
400/*  case 0x26:  */
401/*  case 0x86:  */
402/*  case 0x96:  */
403/*  case 0xa6:  */
404    case 6:
405        if (c == 0x24) {        /* '$' */
406            filter->status++;
407        } else if (c == 0x28) {     /* '(' */
408            filter->status += 3;
409        } else {
410            filter->status &= ~0xf;
411            CK((*filter->output_function)(0x1b, filter->data));
412            goto retry;
413        }
414        break;
415
416    /* ESC $ : ISO-2022-JP-2004 */
417/*  case 0x07:  */
418/*  case 0x17:  */
419/*  case 0x27:  */
420/*  case 0x87:  */
421/*  case 0x97:  */
422/*  case 0xa7:  */
423    case 7:
424        if (c == 0x42) {    /* 'B' -> JIS X 0208-1983 */
425            filter->status = 0x80;
426        } else if (c == 0x28) {         /* '(' */
427            filter->status++;
428        } else {
429            filter->status &= ~0xf;
430            CK((*filter->output_function)(0x1b, filter->data));
431            CK((*filter->output_function)(0x24, filter->data));
432            goto retry;
433        }
434        break;
435
436        break;
437
438    /* ESC $ ( : ISO-2022-JP-2004 */
439/*  case 0x08:  */
440/*  case 0x18:  */
441/*  case 0x28:  */
442/*  case 0x88:  */
443/*  case 0x98:  */
444/*  case 0xa8:  */
445    case 8:
446        if (c == 0x51) {    /* JIS X 0213 plane 1 */
447            filter->status = 0x90;
448        } else if (c == 0x50) {         /* JIS X 0213 plane 2 */
449            filter->status = 0xa0;
450        } else {
451            filter->status &= ~0xf;
452            CK((*filter->output_function)(0x1b, filter->data));
453            CK((*filter->output_function)(0x24, filter->data));
454            CK((*filter->output_function)(0x28, filter->data));
455            goto retry;
456        }
457        break;
458
459    /* ESC ( : ISO-2022-JP-2004 */
460/*  case 0x09:  */
461/*  case 0x19:  */
462/*  case 0x29:  */
463/*  case 0x89:  */
464/*  case 0x99:  */
465    case 9:
466        if (c == 0x42) {        /* 'B' : ASCII */
467            filter->status = 0;
468        } else {
469            filter->status &= ~0xf;
470            CK((*filter->output_function)(0x1b, filter->data));
471            CK((*filter->output_function)(0x28, filter->data));
472            goto retry;
473        }
474        break;
475
476    default:
477        filter->status = 0;
478        break;
479    }
480
481    return c;
482}
483
484int
485mbfl_filt_conv_wchar_jis2004(int c, mbfl_convert_filter *filter) {
486    int k;
487    int c1, c2, s1 = 0, s2;
488
489retry:
490
491    /* check for 1st char of combining characters */
492    if ((filter->status & 0xf)== 0 && (
493            c == 0x00E6 ||
494            (c >= 0x0254 && c <= 0x02E9) ||
495            (c >= 0x304B && c <= 0x3053) ||
496            (c >= 0x30AB && c <= 0x30C8) ||
497            c == 0x31F7)) {
498        for (k=0;k<jisx0213_u2_tbl_len;k++) {
499            if (c == jisx0213_u2_tbl[2*k]) {
500                filter->status++;
501                filter->cache = k;
502                return c;
503            }
504        }
505    }
506
507    /* check for 2nd char of combining characters */
508    if ((filter->status & 0xf) == 1 &&
509        filter->cache >= 0 && filter->cache <= jisx0213_u2_tbl_len) {
510        k = filter->cache;
511        filter->status &= ~0xf;
512        filter->cache = 0;
513
514        c1 = jisx0213_u2_tbl[2*k];
515        if ((c1 == 0x0254 || c1 == 0x028C || c1 == 0x0259 || c1 == 0x025A)
516            && c == 0x0301) {
517            k++;
518        }
519        if (c == jisx0213_u2_tbl[2*k+1]) {
520            s1 = jisx0213_u2_key[k];
521        } else { /* fallback */
522            s1 = jisx0213_u2_fb_tbl[k];
523
524            if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
525                c1 = (s1 >> 8) & 0xff;
526                c2 = s1 & 0xff;
527                SJIS_ENCODE(c1, c2, s1, s2);
528            } else if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
529                s2 = (s1 & 0xff) + 0x80;
530                s1 = ((s1 >> 8) & 0xff) + 0x80;
531            } else {
532                if (filter->status != 0x200) {
533                    CK((*filter->output_function)(0x1b, filter->data));
534                    CK((*filter->output_function)(0x24, filter->data));
535                    CK((*filter->output_function)(0x28, filter->data));
536                    CK((*filter->output_function)(0x51, filter->data));
537                }
538                filter->status = 0x200;
539
540                s2 = s1 & 0x7f;
541                s1 = (s1 >> 8) & 0x7f;
542            }
543
544            CK((*filter->output_function)(s1, filter->data));
545            CK((*filter->output_function)(s2, filter->data));
546            goto retry;
547        }
548    }
549
550    /* check for major japanese chars: U+4E00 - U+9FFF */
551    if (s1 <= 0) {
552        for (k=0; k < uni2jis_tbl_len ;k++) {
553            if (c >= uni2jis_tbl_range[k][0] && c <= uni2jis_tbl_range[k][1]) {
554                s1 = uni2jis_tbl[k][c-uni2jis_tbl_range[k][0]];
555                break;
556            }
557        }
558    }
559
560    /* check for japanese chars in compressed mapping area: U+1E00 - U+4DBF */
561    if (s1 <= 0 && c >= ucs_c1_jisx0213_min && c <= ucs_c1_jisx0213_max) {
562        k = mbfl_bisec_srch(c, ucs_c1_jisx0213_tbl, ucs_c1_jisx0213_tbl_len);
563        if (k >= 0) {
564            s1 = ucs_c1_jisx0213_ofst[k] + c - ucs_c1_jisx0213_tbl[2*k];
565        }
566    }
567
568    /* check for japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */
569    if (s1 <= 0 && c >= jisx0213_u5_tbl_min && c <= jisx0213_u5_tbl_max) {
570        k = mbfl_bisec_srch2(c - 0x20000, jisx0213_u5_jis_key, jisx0213_u5_tbl_len);
571        if (k >= 0) {
572            s1 = jisx0213_u5_jis_tbl[k];
573        }
574    }
575
576    if (s1 <= 0) {
577        /* CJK Compatibility Forms: U+FE30 - U+FE4F */
578        if (c == 0xfe45) {
579            s1 = 0x233e;
580        } else if (c == 0xfe46) {
581            s1 = 0x233d;
582        } else if (c >= 0xf91d && c <= 0xf9dc) {
583            /* CJK Compatibility Ideographs: U+F900 - U+F92A */
584            k = mbfl_bisec_srch2(c, ucs_r2b_jisx0213_cmap_key, ucs_r2b_jisx0213_cmap_len);
585            if (k >= 0) {
586                s1 = ucs_r2b_jisx0213_cmap_val[k];
587            }
588        }
589    }
590
591    if (s1 <= 0) {
592        c1 = c & ~MBFL_WCSPLANE_MASK;
593        if (c1 == MBFL_WCSPLANE_JIS0213) {
594            s1 = c & MBFL_WCSPLANE_MASK;
595        }
596        if (c == 0) {
597            s1 = 0;
598        } else if (s1 <= 0) {
599            s1 = -1;
600        }
601    } else if (s1 >= 0x9980) {
602        s1 = -1;
603    }
604
605    if (s1 >= 0) {
606        if (s1 < 0x80) { /* ASCII */
607            if (filter->to->no_encoding == mbfl_no_encoding_2022jp_2004 &&
608                (filter->status & 0xff00) != 0) {
609                CK((*filter->output_function)(0x1b, filter->data));     /* ESC */
610                CK((*filter->output_function)(0x28, filter->data));     /* '(' */
611                CK((*filter->output_function)(0x42, filter->data));     /* 'B' */
612            }
613            filter->status = 0;
614            CK((*filter->output_function)(s1, filter->data));
615        } else if (s1 < 0x100) { /* latin or kana */
616            if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
617                CK((*filter->output_function)(0x8e, filter->data));
618            }
619            CK((*filter->output_function)(s1, filter->data));
620        } else if (s1 < 0x7f00) { /* X 0213 plane 1 */
621            if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
622                c1 = (s1 >> 8) & 0xff;
623                c2 = s1 & 0xff;
624                SJIS_ENCODE(c1, c2, s1, s2);
625            } else if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
626                s2 = (s1 & 0xff) + 0x80;
627                s1 = ((s1 >> 8) & 0xff) + 0x80;
628            } else {
629                if ((filter->status & 0xff00) != 0x200) {
630                    CK((*filter->output_function)(0x1b, filter->data));     /* ESC */
631                    CK((*filter->output_function)(0x24, filter->data));     /* '$' */
632                    CK((*filter->output_function)(0x28, filter->data));     /* '(' */
633                    CK((*filter->output_function)(0x51, filter->data));     /* 'Q' */
634                }
635                filter->status = 0x200;
636                s2 = s1 & 0xff;
637                s1 = (s1 >> 8) & 0xff;
638            }
639            CK((*filter->output_function)(s1, filter->data));
640            CK((*filter->output_function)(s2, filter->data));
641        } else { /* X 0213 plane 2 */
642            if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
643                c1 = (s1 >> 8) & 0xff;
644                c2 = s1 & 0xff;
645                SJIS_ENCODE(c1, c2, s1, s2);
646            } else {
647                s2 = s1 & 0xff;
648                k = ((s1 >> 8) & 0xff) - 0x7f;
649                if (k >= 0 && k < jisx0213_p2_ofst_len) {
650                    s1  = jisx0213_p2_ofst[k] - 1 + 0x21;
651                }
652                if  (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
653                    s2 |= 0x80;
654                    s1 |= 0x80;
655                    CK((*filter->output_function)(0x8f, filter->data));
656                } else {
657                    if ((filter->status & 0xff00) != 0x200) {
658                        CK((*filter->output_function)(0x1b, filter->data));     /* ESC */
659                        CK((*filter->output_function)(0x24, filter->data));     /* '$' */
660                        CK((*filter->output_function)(0x28, filter->data));     /* '(' */
661                        CK((*filter->output_function)(0x50, filter->data));     /* 'P' */
662                    }
663                    filter->status = 0x200;
664                }
665            }
666
667            CK((*filter->output_function)(s1, filter->data));
668            CK((*filter->output_function)(s2, filter->data));
669        }
670    } else {
671        if (filter->illegal_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
672            CK(mbfl_filt_conv_illegal_output(c, filter));
673        }
674    }
675}
676
677int
678mbfl_filt_conv_jis2004_flush(mbfl_convert_filter *filter)
679{
680    int k, c1, c2, s1, s2;
681
682    k = filter->cache;
683    filter->cache = 0;
684
685    if (filter->status == 1 && k >= 0 && k <= jisx0213_u2_tbl_len) {
686        s1 = jisx0213_u2_fb_tbl[k];
687
688        if (filter->to->no_encoding == mbfl_no_encoding_sjis2004) {
689            c1 = (s1 >> 8) & 0xff;
690            c2 = s1 & 0xff;
691            SJIS_ENCODE(c1, c2, s1, s2);
692        } else if (filter->to->no_encoding == mbfl_no_encoding_eucjp2004) {
693            s2 = (s1 & 0xff) | 0x80;
694            s1 = ((s1 >> 8) & 0xff) | 0x80;
695        } else {
696            s2 = s1 & 0x7f;
697            s1 = (s1 >> 8) & 0x7f;
698            if ((filter->status & 0xff00) != 0x200) {
699                CK((*filter->output_function)(0x1b, filter->data));     /* ESC */
700                CK((*filter->output_function)(0x24, filter->data));     /* '$' */
701                CK((*filter->output_function)(0x28, filter->data));     /* '(' */
702                CK((*filter->output_function)(0x51, filter->data));     /* 'Q' */
703            }
704            filter->status = 0x200;
705        }
706
707        CK((*filter->output_function)(s1, filter->data));
708        CK((*filter->output_function)(s2, filter->data));
709    }
710
711    /* back to latin */
712    if ((filter->status & 0xff00) != 0) {
713        CK((*filter->output_function)(0x1b, filter->data));     /* ESC */
714        CK((*filter->output_function)(0x28, filter->data));     /* '(' */
715        CK((*filter->output_function)(0x42, filter->data));     /* 'B' */
716    }
717
718    filter->status = 0;
719
720    if (filter->flush_function != NULL) {
721        return (*filter->flush_function)(filter->data);
722    }
723
724    return 0;
725}
726