    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.mail;
    017
    018import java.io.ByteArrayOutputStream;
    019import java.io.UnsupportedEncodingException;
    020
    021/**
    022 * 文字関係のコンバータです。
    023 * 一部コードのオリジナルは <a href="http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/CCGI/kanjicod.html">Japanese Kanji Code</a>にて公開されているものです。
    024 * また、http://www.sk-jp.com/cgi-bin/treebbs.cgi?kako=1&amp;all=644&amp;s=681
    025 * にて YOSI さんが公開されたコードも参考にしています(というか実質同じです)。
    026 *
    027 * @version  4.0
    028 * @author   Kazuhiko Hasegawa
    029 * @since    JDK5.0,
    030 */
    031final class CharCodeConverter {
    032        private static final byte[] SJIS_KANA;  // 5.1.9.0 (2010/09/01) public ⇒ private へ変更
    033
    034        /**
    035         * インスタンスの生成を抑止します。
    036         */
    037        private CharCodeConverter() {
    038                // 何もありません。(PMD エラー回避)
    039        }
    040
    041        static {
    042                try {
    043                        // 全角への変換テーブル
    044                        SJIS_KANA = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜".getBytes("Shift_JIS");
    045                } catch( UnsupportedEncodingException ex ) {
    046                        throw new RuntimeException( "CANT HAPPEN",ex );
    047                }
    048        }
    049
    050        /**
    051         * Shift_JIS エンコーディングスキームに基づくバイト列を
    052         * ISO-2022-JP エンコーディングスキームに変換します。
    053         * 「半角カナ」は対応する全角文字に変換します。
    054         *
    055         * @param sjisBytes byte[] エンコードするShift_JISバイト配列
    056         *
    057         * @return byte[] 変換後のISO-2022-JP(JIS)バイト配列(not null)
    058         */
    059        public static byte[] sjisToJis( final byte[] sjisBytes ) {
    060                ByteArrayOutputStream out = new ByteArrayOutputStream();
    061                boolean nonAscii = false;
    062                int len = sjisBytes.length;
    063                for(int i = 0; i < len; i++ ) {
    064                        if(sjisBytes[i] >= 0) {
    065                                if(nonAscii) {
    066                                        nonAscii = false;
    067                                        out.write(0x1b);
    068                                        out.write('(');
    069                                        out.write('B');
    070                                }
    071                                out.write(sjisBytes[i]);
    072                        } else {
    073                                if(!nonAscii) {
    074                                        nonAscii = true;
    075                                        out.write(0x1b);
    076                                        out.write('$');
    077                                        out.write('B');
    078                                }
    079                                int bt = sjisBytes[i] & 0xff;
    080                                if(bt >= 0xa1 && bt <= 0xdf) {
    081                                        // 半角カナは全角に変換
    082                                        int kanaIndex = (bt - 0xA1) * 2;
    083                                        sjisToJis(out, SJIS_KANA[kanaIndex], SJIS_KANA[kanaIndex + 1]);
    084                                } else {
    085                                        i++;
    086                                        if(i == len) { break; }
    087                                        sjisToJis(out, sjisBytes[i - 1], sjisBytes[i]);
    088                                }
    089                        }
    090                }
    091                if(nonAscii) {
    092                        out.write(0x1b);
    093                        out.write('(');
    094                        out.write('B');
    095                }
    096                return out.toByteArray();
    097        }
    098
    099        /**
    100         * １文字の２バイト Shift_JIS コードを JIS コードに変換して書き出します。
    101         */
    102        private static void sjisToJis(
    103                                final ByteArrayOutputStream out, final byte bhi, final byte blo) {
    104                int hi = (bhi << 1) & 0xFF;
    105                int lo = blo & 0xFF;
    106                if(lo < 0x9F) {
    107                        if(hi < 0x3F) { hi += 0x1F; } else { hi -= 0x61; }
    108                        if(lo > 0x7E) { lo -= 0x20; } else { lo -= 0x1F; }
    109                } else {
    110                        if(hi < 0x3F) { hi += 0x20; } else { hi -= 0x60; }
    111                        lo -= 0x7E;
    112                }
    113                out.write(hi);
    114                out.write(lo);
    115        }
    116}