View Javadoc

1   /*
2    * Copyright (c) 2003 Shin Kinoshita All Rights Reserved.
3    */
4   package com.ozacc.mail.fetch.impl.sk_jp.io;
5   
6   import java.io.ByteArrayOutputStream;
7   import java.io.UnsupportedEncodingException;
8   
9   /***
10   * 文字関係のコンバータです。
11   * 一部コードのオリジナルは<a href="http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/CCGI/kanjicod.html">Japanese Kanji Code</a>にて公開されているものです。
12   * また、http://www.sk-jp.com/cgi-bin/treebbs.cgi?kako=1&all=644&s=681
13   * にて YOSI さんが公開されたコードも参考にしています(というか実質同じです)。
14   *
15   * @author Shin
16   * @version $Revision: 1.1.2.1 $ $Date: 2005/01/18 07:20:36 $
17   */
18  public class CharCodeConverter {
19      public static final byte[] SJIS_KANA;
20      static {
21          try {
22              // 全角への変換テーブル
23              SJIS_KANA = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜".getBytes("Shift_JIS");
24          } catch (UnsupportedEncodingException e) {
25              throw new RuntimeException("CANT HAPPEN");
26          }
27      }
28  
29      /***
30       * Shift_JIS エンコーディングスキームに基づくバイト列を
31       * ISO-2022-JP エンコーディングスキームに変換します。
32       * 「半角カナ」は対応する全角文字に変換します。
33       */
34      public static byte[] sjisToJis(byte[] sjisBytes) {
35          ByteArrayOutputStream out = new ByteArrayOutputStream();
36          boolean nonAscii = false;
37          int len = sjisBytes.length;
38          for (int i = 0; i < len; i++ ) {
39              if (sjisBytes[i] >= 0) {
40                  if (nonAscii) {
41                      nonAscii = false;
42                      out.write(0x1b);
43                      out.write('(');
44                      out.write('B');
45                  }
46                  out.write(sjisBytes[i]);
47              } else {
48                  if (!nonAscii) {
49                      nonAscii = true;
50                      out.write(0x1b);
51                      out.write('$');
52                      out.write('B');
53                  }
54                  int b = sjisBytes[i] & 0xff;
55                  if (b >= 0xa1 && b <= 0xdf) {
56                      // 半角カナは全角に変換
57                      int kanaIndex = (b - 0xA1) * 2;
58                      sjisToJis(out, SJIS_KANA[kanaIndex], SJIS_KANA[kanaIndex + 1]);
59                  } else {
60                      i++;
61                      if (i == len) break;
62                      sjisToJis(out, sjisBytes[i - 1], sjisBytes[i]);
63                  }
64              }
65          }
66          if (nonAscii) {
67              out.write(0x1b);
68              out.write('(');
69              out.write('B');
70          }
71          return out.toByteArray();
72      }
73      /***
74       * 1文字の2バイト Shift_JIS コードを JIS コードに変換して書き出します。
75       */
76      private static void sjisToJis(
77                  ByteArrayOutputStream out, byte bh, byte bl) {
78          int h = (bh << 1) & 0xFF;
79          int l = bl & 0xFF;
80          if (l < 0x9F) {
81              if (h < 0x3F) h += 0x1F; else h -= 0x61;
82              if (l > 0x7E) l -= 0x20; else l -= 0x1F;
83          } else {
84              if (h < 0x3F) h += 0x20; else h -= 0x60;
85              l -= 0x7E;
86          }
87          out.write(h);
88          out.write(l);
89      }
90  
91      /***
92       * 配列はワイドキャラクタの境界にないことを前提としています。
93       * また、エスケープシーケンスが適切に含まれることも前提です。
94       * エスケープシーケンスが"(B"/"$B"以外の場合は無視します。
95       */
96      public byte[] jisTosjis(byte[] jisBytes) {
97          ByteArrayOutputStream out = new ByteArrayOutputStream();
98          boolean nonAscii = false;
99          boolean kana = false;
100         int len = jisBytes.length;
101         for (int i = 0; i < len; i++) {
102             if (jisBytes[i] == 0x1b) {
103                 if (i + 2 >= len) break;
104                 if (jisBytes[i + 1] == '$' && jisBytes[i + 2] == 'B') {
105                     nonAscii = true;
106                     i += 2;
107                 } else if (jisBytes[i + 1] == '(' && jisBytes[i + 2] == 'I') {
108                     kana = true;
109                     i += 2;
110                 } else if (jisBytes[i + 1] == '(' && jisBytes[i + 2] == 'B') {
111                     nonAscii = false;
112                     kana = false;
113                     i += 2;
114                 } else {
115                     // illegal sequence は当面無視
116                     nonAscii = false;
117                     kana = false;
118                 }
119                 continue;
120             }
121             if (jisBytes[i] == 0x0e) { // SO
122                 kana = true;
123                 continue;
124             }
125             if (jisBytes[i] == 0x0f) { // SI
126                 kana = false;
127                 continue;
128             }
129             if (kana) {
130                 out.write(jisBytes[i] | 0x80);
131             } else if (nonAscii) {
132                 i++;
133                 if (i == jisBytes.length) break;
134                 jisToSjis(out, jisBytes[i - 1], jisBytes[i]);
135             } else {
136                 out.write(jisBytes[i]);
137             }
138         }
139         return out.toByteArray();
140     }
141     /***
142      * 1文字の2バイト JIS コードを Shift_JIS に変換して書き出します。
143      */
144     private static void jisToSjis(
145                 ByteArrayOutputStream out, byte bh, byte bl) {
146         int h = bh & 0xFF;
147         int l = bl & 0xFF;
148         if ((h & 0x01) > 0) {
149             h >>= 1;
150             if (h < 0x2F) h += 0x71; else h -= 0x4F;
151             if (l > 0x5F) l += 0x20; else l += 0x1F;
152         } else {
153             h >>= 1;
154             if (h < 0x2F) h += 0x70; else h -= 0x50;
155             l += 0x7E;
156         }
157         out.write(h);
158         out.write(l);
159     }
160 }