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 *
026 * @version     4.0
027 * @author      Kazuhiko Hasegawa
028 * @since       JDK5.0,
029 */
030final class CharCodeConverter {
031        private static final byte[] SJIS_KANA;  // 5.1.9.0 (2010/09/01) public ⇒ private へ変更
032
033        /**
034         * デフォルトコンストラクターをprivateにして、
035         * オブジェクトの生成をさせないようにする。
036         */
037        private CharCodeConverter() {
038                // 何もありません。(PMD エラー回避)
039        }
040
041        static {
042                try {
043                        // 全角への変換テーブル
044                        SJIS_KANA = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜".getBytes("Shift_JIS");
045                } catch( final UnsupportedEncodingException ex ) {
046                        throw new OgRuntimeException( "CANT HAPPEN",ex );
047                }
048        }
049
050        /**
051         * Shift_JIS エンコーディングスキームに基づくバイト列を
052         * ISO-2022-JP エンコーディングスキームに変換します。
053         * 「半角カナ」は対応する全角文字に変換します。
054         *
055         * @param sjisBytes エンコードするShift_JISバイト配列
056         *
057         * @return      変換後のISO-2022-JP(JIS)バイト配列(not null)
058         * @og.rtnNotNull
059         */
060        public static byte[] sjisToJis( final byte[] sjisBytes ) {
061                final ByteArrayOutputStream out = new ByteArrayOutputStream();
062                boolean nonAscii = false;
063                final int len = sjisBytes.length;
064                // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
065//              for( int i=0; i<len; i++ ) {
066                int idx = 0;
067                while( idx < len ) {
068                        final byte sbt = sjisBytes[idx];
069//                      if( sjisBytes[i] >= 0 ) {
070                        if( sbt >= 0 ) {                                                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
071                                if( nonAscii ) {
072                                        nonAscii = false;
073                                        out.write(0x1b);
074                                        out.write('(');
075                                        out.write('B');
076                                }
077//                              out.write(sjisBytes[i]);
078                                out.write(sbt);                                                 // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
079                        } else {
080                                if( !nonAscii ) {
081                                        nonAscii = true;
082                                        out.write(0x1b);
083                                        out.write('$');
084                                        out.write('B');
085                                }
086//                              final int bt = sjisBytes[i] & 0xff;
087                                final int bt = sbt & 0xff;                              // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
088                                if( bt>=0xa1 && bt<=0xdf ) {
089                                        // 半角カナは全角に変換
090                                        final int kanaIndex = (bt - 0xA1) * 2;
091                                        sjisToJis( out, SJIS_KANA[kanaIndex], SJIS_KANA[kanaIndex+1] );
092                                } else {
093//                                      i++;
094//                                      if( i==len ) { break; }
095//                                      sjisToJis( out, sjisBytes[i-1], sjisBytes[i] );
096                                        idx++;                                                                  // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
097                                        if( idx == len ) { break; }                             // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
098                                        sjisToJis( out, sbt, sjisBytes[idx] );  // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
099                                }
100                        }
101                        idx++ ;                 // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidReassigningLoopVariables
102                }
103                if( nonAscii ) {
104                        out.write(0x1b);
105                        out.write('(');
106                        out.write('B');
107                }
108                return out.toByteArray();
109        }
110
111        /**
112         * 1文字の2バイト Shift_JIS コードを JIS コードに変換して書き出します。
113         *
114         * @param       outStrm 出力するByteArrayOutputStream
115         * @param       bhi             変換する上位バイト
116         * @param       blo             変換する下位バイト
117         */
118        private static void sjisToJis( final ByteArrayOutputStream outStrm, final byte bhi, final byte blo ) {
119                int hi = (bhi << 1) & 0xFF;
120                int lo = blo & 0xFF;
121                if( lo < 0x9F ) {
122                        if( hi<0x3F) { hi += 0x1F; } else { hi -= 0x61; }
123                        if( lo>0x7E) { lo -= 0x20; } else { lo -= 0x1F; }
124                } else {
125                        if( hi<0x3F) { hi += 0x20; } else { hi -= 0x60; }
126                        lo -= 0x7E;
127                }
128                outStrm.write(hi);
129                outStrm.write(lo);
130        }
131}