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&all=644&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 * 1文字の2バイト 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}