    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
    021import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    022
    023/**
    024 * 文字関係のコンバータです。
    025 * 一部コードのオリジナルは <a href="http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/CCGI/kanjicod.html">Japanese Kanji Code</a>にて公開されているものです。
    026 * また、http://www.sk-jp.com/cgi-bin/treebbs.cgi?kako=1&amp;all=644&amp;s=681
    027 * にて YOSI さんが公開されたコードも参考にしています(というか実質同じです)。
    028 *
    029 * @version  4.0
    030 * @author   Kazuhiko Hasegawa
    031 * @since    JDK5.0,
    032 */
    033final class CharCodeConverter {
    034        private static final byte[] SJIS_KANA;  // 5.1.9.0 (2010/09/01) public ⇒ private へ変更
    035
    036        /**
    037         * インスタンスの生成を抑止します。
    038         */
    039        private CharCodeConverter() {
    040                // 何もありません。(PMD エラー回避)
    041        }
    042
    043        static {
    044                try {
    045                        // 全角への変換テーブル
    046                        SJIS_KANA = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜".getBytes("Shift_JIS");
    047                } catch( final UnsupportedEncodingException ex ) {
    048                        throw new OgRuntimeException( "CANT HAPPEN",ex );
    049                }
    050        }
    051
    052        /**
    053         * Shift_JIS エンコーディングスキームに基づくバイト列を
    054         * ISO-2022-JP エンコーディングスキームに変換します。
    055         * 「半角カナ」は対応する全角文字に変換します。
    056         *
    057         * @param sjisBytes エンコードするShift_JISバイト配列
    058         *
    059         * @return 変換後のISO-2022-JP(JIS)バイト配列(not null)
    060         * @og.rtnNotNull
    061         */
    062        public static byte[] sjisToJis( final byte[] sjisBytes ) {
    063                final ByteArrayOutputStream out = new ByteArrayOutputStream();
    064                boolean nonAscii = false;
    065                final int len = sjisBytes.length;
    066                for( int i=0; i<len; i++ ) {
    067                        if( sjisBytes[i] >= 0 ) {
    068                                if( nonAscii ) {
    069                                        nonAscii = false;
    070                                        out.write(0x1b);
    071                                        out.write('(');
    072                                        out.write('B');
    073                                }
    074                                out.write(sjisBytes[i]);
    075                        } else {
    076                                if( !nonAscii ) {
    077                                        nonAscii = true;
    078                                        out.write(0x1b);
    079                                        out.write('$');
    080                                        out.write('B');
    081                                }
    082                                final int bt = sjisBytes[i] & 0xff;
    083                                if( bt>=0xa1 && bt<=0xdf ) {
    084                                        // 半角カナは全角に変換
    085                                        final int kanaIndex = (bt - 0xA1) * 2;
    086                                        sjisToJis( out, SJIS_KANA[kanaIndex], SJIS_KANA[kanaIndex+1] );
    087                                } else {
    088                                        i++;
    089                                        if( i==len ) { break; }
    090                                        sjisToJis( out, sjisBytes[i-1], sjisBytes[i] );
    091                                }
    092                        }
    093                }
    094                if( nonAscii ) {
    095                        out.write(0x1b);
    096                        out.write('(');
    097                        out.write('B');
    098                }
    099                return out.toByteArray();
    100        }
    101
    102        /**
    103         * １文字の２バイト Shift_JIS コードを JIS コードに変換して書き出します。
    104         *
    105         * @param outStrm 出力するByteArrayOutputStream
    106         * @param bhi 変換する上位バイト
    107         * @param blo 変換する下位バイト
    108         */
    109        private static void sjisToJis( final ByteArrayOutputStream outStrm, final byte bhi, final byte blo ) {
    110                int hi = (bhi << 1) & 0xFF;
    111                int lo = blo & 0xFF;
    112                if( lo < 0x9F ) {
    113                        if( hi<0x3F) { hi += 0x1F; } else { hi -= 0x61; }
    114                        if( lo>0x7E) { lo -= 0x20; } else { lo -= 0x1F; }
    115                } else {
    116                        if( hi<0x3F) { hi += 0x20; } else { hi -= 0x60; }
    117                        lo -= 0x7E;
    118                }
    119                outStrm.write(hi);
    120                outStrm.write(lo);
    121        }
    122}