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     */
016    package org.opengion.fukurou.mail;
017    
018    import java.io.InputStream;
019    import java.io.OutputStream;
020    import java.io.ByteArrayOutputStream;
021    import java.io.ByteArrayInputStream;
022    import java.io.UnsupportedEncodingException;
023    import java.io.IOException;
024    
025    import javax.activation.DataHandler;
026    import javax.activation.DataSource;
027    import javax.mail.internet.InternetAddress;
028    import javax.mail.internet.MimeMessage;
029    import javax.mail.internet.MimeUtility;
030    import javax.mail.MessagingException;
031    import com.sun.mail.util.BASE64EncoderStream;
032    
033    import java.nio.charset.Charset;                // 5.5.2.6 (2012/05/25)
034    
035    /**
036     * MailCharset は、E-Mail 送信時ã?エンコードに応じたå?ç�?‚’行う為のã€?
037     * インターフェースですã?
038     *
039     * E-Mail で日本語を送信する場合ã?ISO-2022-JP(JISコーãƒ?化してã€?bit で
040     * エンコードして送信するå¿?¦�がありますが、Windows系の特殊文字や、unicodeと
041     * æ–?­—ã?マッピングが異なる文字などがã?æ–?­—化けしますã?
042     * 対応方法としてはã€?
043     * 『1.Windows-31J + 8bit 送信ã€?
044     * 『2.ISO-2022-JP に独自変換 + 7bit 送信ã€?
045     * の方法がありますã?
046     * 今回、この?’つの方法につã�?�¦、それぞれサブクラス化を行い、å?ç�?�§きるように
047     * したのがã?こã?インターフェース、およã?、サブクラスですã?
048     *
049     * 『1.Windows-31J + 8bit 送信』ã?方法ã?ã€??常の JavaMail API に準拠して
050     * 処ç�?‚’行う、Mail_Windows31J_Charset サブクラスで実è£?�—てã�?�¾すã?
051     * 古ã�?ƒ¡イラーおよび、古ã�?ƒ¡ールサーバã?ではメール転送できなã�?‚ºã€?
052     * こã?方式ã?、社å†?�§使用する場合ã?みに、利用できますが、主としてWindows系の
053     * 社å†?‚·スãƒ?ƒ においては、こちらã?方がã?なにかとトラブルは少なã�?�¨思いますã?
054     *
055     * 『2.ISO-2022-JP に独自変換 + 7bit 送信』ã?実è£??ã€?
056     * JAVA PRESS Vol.37 (http://www.gihyo.co.jp/magazines/javapress)の
057     * 【特é›?ã€?決定版??サーバサイドJavaの日本語å?ç�?
058     *  第3ç«?¼šJavaMailの日本語å?ç�??ログラミング……木下信
059     *“ã?ルチã?ラãƒ?ƒˆフォーãƒ??な日本語メール送信è¡?完å?解説
060     * でのサンプルアプリケーション
061     * http://www.gihyo.co.jp/book/2004/225371/download/toku1_3.zip
062     * をã?使用して、Mail_ISO2022JP_Charset サブクラスで実è£?�—てã�?�¾すã?
063     *
064     * これらã?サブクラスは、MailCharsetFactory ファクトリクラスより、作æ?されますã?
065     * そã?場合ã?引数のキャラクタセãƒ?ƒˆ名ã?、Windows-31J 、MS932 かã?それ以外となってã�?�¾すã?
066     * それ以外がæŒ?®šされた場合ã?、ISO-2022-JP を使用しますã?
067     *
068     * @version  4.0
069     * @author   Kazuhiko Hasegawa
070     * @since    JDK5.0,
071     */
072    public interface MailCharset {
073    
074            /**
075             * ãƒ?‚­ストをセãƒ?ƒˆしますã?
076             * Part#setText() の代わりにこちらを使ã�?‚ˆã�?�«しますã?
077             *
078             * @param mimeMsg MimeMessageæœ?¤§取り込み件数
079             * @param text    設定するテキスãƒ?
080             * @throws RuntimeException(MessagingException)
081             */
082            void setTextContent( MimeMessage mimeMsg, String text ) ;
083    
084            /**
085             * 日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­ストを生æ?しますã?
086             * 変換結果は ASCII なので、これをそã?まま setSubject ã‚?InternetAddress
087             * のパラメタとして使用してくださいã€?
088             *
089             * @param text    設定するテキスãƒ?
090             *
091             * @return      日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­スãƒ?
092             * @throws RuntimeException(UnsupportedEncodingException)
093             */
094            String encodeWord( String text ) ;
095    
096            /**
097             * 日本語を含ã‚?‚¢ドレスを生成しますã?
098             * personal に、日本語が含まれると想定してã�?�¾すã?
099             * サブクラスで、日本語å?ç�?‚’行う場合ã?方法ã?、それぞれ異なりますã?
100             *
101             * @param address    アドレス部åˆ?
102             * @param personal   日本語ã?説明部åˆ?
103             *
104             * @return      日本語を含ã‚?‚¢ドレス
105             * @throws RuntimeException(UnsupportedEncodingException)
106             */
107            InternetAddress getAddress( String address,String personal ) ;
108    
109            /**
110             * Content-Transfer-Encoding を指定するå?合ã? ビット数を返しますã?
111             *
112             * Windows系はã€?bit / ISO-2022-JP 系はã€?bit になりますã?
113             *
114             * @return      ビット数
115             */
116            String getBit() ;
117    }
118    
119    /**
120     * MailCharsetFactory は、MailCharset インターフェースを実è£?�—たサブクラスã‚?
121     * 作æ?する ファクトリクラスですã?
122     *
123     * 引数のキャラクタセãƒ?ƒˆ名が、Windows-31J 、MS932 の場合ã?ã€?
124     * 『1.Windows-31J + 8bit 送信ã€?の実è£?�§ある、Mail_Windows31J_Charset
125     * サブクラスを返しますã?
126     * それ以外がæŒ?®šされた場合ã?、ISO-2022-JP を使用して、ã??’.ISO-2022-JP に独自変換 + 7bit 送信ã€?
127     * の実è£?�§ある、Mail_ISO2022JP_Charset サブクラスを返しますã?
128     *
129     * @version  4.0
130     * @author   Kazuhiko Hasegawa
131     * @since    JDK5.0,
132     */
133    class MailCharsetFactory {
134    
135            /**
136             * インスタンスの生æ?を抑止しますã?
137             */
138            private MailCharsetFactory() {
139                    // 何もありませんã€?PMD エラー回避)
140            }
141    
142            /**
143             * キャラクタセãƒ?ƒˆに応じたã?MailCharset オブジェクトを返しますã?
144             *
145             * Windows-31J 、MS932 、Shift_JIS の場合ã?、Mail_Windows31J_Charset
146             * そã?他ã?、ISO-2022-JP として、Mail_ISO2022JP_Charset を返しますã?
147             *
148             * 注意:null の場合ã?、デフォルトではなくã?Mail_ISO2022JP_Charset を返しますã?
149             *
150             * @param  charset キャラクタセãƒ?ƒˆ[Windows-31J/MS932/Shift_JIS/そã?他]
151             *
152             * @return MailCharset
153             */
154            static MailCharset newInstance( final String charset ) {
155                    final MailCharset mcset;
156    
157                    if( "MS932".equalsIgnoreCase( charset ) ||
158                            "Shift_JIS".equalsIgnoreCase( charset ) ||
159                            "Windows-31J".equalsIgnoreCase( charset ) ) {
160                                    mcset = new Mail_Windows31J_Charset( charset );
161                    }
162                    else {
163                            mcset = new Mail_ISO2022JP_Charset();
164                    }
165                    return mcset ;
166            }
167    }
168    
169    /**
170     * MailCharset インターフェースを実è£?�—ã�?Windwos-31J エンコード時のサブクラスですã?
171     *
172     * 『1.Windows-31J + 8bit 送信ã€?の実è£?�§すã?
173     *
174     * @version  4.0
175     * @author   Kazuhiko Hasegawa
176     * @since    JDK5.0,
177     */
178    class Mail_Windows31J_Charset implements MailCharset {
179            private final String charset ;                  // "Windows-31J" or "MS932"
180    
181            /**
182             * 引数に、エンコード方式をæŒ?®šして、作æ?するコンストラクタですã?
183             *
184             * @param charset String
185             */
186            public Mail_Windows31J_Charset( final String charset ) {
187                    this.charset = charset;
188            }
189    
190            /**
191             * ãƒ?‚­ストをセãƒ?ƒˆしますã?
192             * Part#setText() の代わりにこちらを使ã�?‚ˆã�?�«しますã?
193             *
194             * @param mimeMsg MimeMessage
195             * @param text    String
196             * @throws RuntimeException(MessagingException)
197             */
198            public void setTextContent( final MimeMessage mimeMsg, final String text ) {
199                    try {
200                            mimeMsg.setText( text,charset );                // "text/plain" Content
201                    }
202                    catch( MessagingException ex ) {
203                            String errMsg = "æŒ?®šã?ãƒ?‚­ストをセãƒ?ƒˆできませんã€?
204                                                                    + "text=" + text + " , charset=" + charset ;
205                            throw new RuntimeException( errMsg,ex );
206                    }
207            }
208    
209            /**
210             * 日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­ストを生æ?しますã?
211             * 変換結果は ASCII なので、これをそã?まま setSubject ã‚?InternetAddress
212             * のパラメタとして使用してくださいã€?
213             *
214             * @param text    String
215             *
216             * @return      日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­スãƒ?
217             * @throws RuntimeException(UnsupportedEncodingException)
218             */
219            public String encodeWord( final String text ) {
220                    try {
221                            return MimeUtility.encodeText( text, charset, "B" );
222                    }
223                    catch( UnsupportedEncodingException ex ) {
224                            String errMsg = "æŒ?®šã?エンコードが出来ませんã€?
225                                                                    + "text=" + text + " , charset=" + charset ;
226                            throw new RuntimeException( errMsg,ex );
227                    }
228            }
229    
230            /**
231             * 日本語を含ã‚?‚¢ドレスを生成しますã?
232             * personal に、日本語が含まれると想定してã�?�¾すã?
233             * サブクラスで、日本語å?ç�?‚’行う場合ã?方法ã?、それぞれ異なりますã?
234             *
235             * @param address    String
236             * @param personal   String
237             *
238             * @return InternetAddress
239             * @throws RuntimeException(UnsupportedEncodingException)
240             */
241            public InternetAddress getAddress( final String address,final String personal ) {
242                    try {
243                            return new InternetAddress( address,personal,charset );
244                    }
245                    catch( UnsupportedEncodingException ex ) {
246                            String errMsg = "æŒ?®šã?エンコードが出来ませんã€?
247                                                                    + "address=" + address + " , charset=" + charset ;
248                            throw new RuntimeException( errMsg,ex );
249                    }
250            }
251    
252            /**
253             * Content-Transfer-Encoding を指定するå?合ã? ビット数を返しますã?
254             *
255             * Windows系はã€?bit / ISO-2022-JP 系はã€?bit になりますã?
256             *
257             * @return      ビット数("8bit" 固å®?
258             */
259            public String getBit() {
260                    return "8bit" ;
261            }
262    }
263    
264    /**
265     * MailCharset インターフェースを実è£?�—ã�?ISO-2022-JP エンコード時のサブクラスですã?
266     *
267     * 『2.ISO-2022-JP に独自変換 + 7bit 送信ã€?の実è£?�§すã?
268     *
269     * @version  4.0
270     * @author   Kazuhiko Hasegawa
271     * @since    JDK5.0,
272     */
273    class Mail_ISO2022JP_Charset implements MailCharset {
274    
275            /**
276             * プラãƒ?ƒˆフォーãƒ?¾�存ã?ãƒ?ƒ•ォルトã? Charset ですã?
277             * プラãƒ?ƒˆフォーãƒ?¾�存æ?をè?慮する場合ã?エンコード指定で作æ?しておく事をお勧めしますã?
278             *
279             * @og.rev 5.5.2.6 (2012/05/25) findbugs対å¿?
280             */
281            private static final Charset DEFAULT_CHARSET = Charset.defaultCharset() ;
282    
283            /**
284             * ãƒ?‚­ストをセãƒ?ƒˆしますã?
285             * Part#setText() の代わりにこちらを使ã�?‚ˆã�?�«しますã?
286             *
287             * @param mimeMsg MimeMessage
288             * @param text    String
289             * @throws RuntimeException(MessagingException)
290             */
291            public void setTextContent( final MimeMessage mimeMsg, final String text ) {
292                    try {
293                            // mimeMsg.setText(text, "ISO-2022-JP");
294                            mimeMsg.setDataHandler(new DataHandler(new JISDataSource(text)));
295                    }
296                    catch( MessagingException ex ) {
297                            String errMsg = "æŒ?®šã?ãƒ?‚­ストをセãƒ?ƒˆできませんã€?
298                                                                    + "text=" + text ;
299                            throw new RuntimeException( errMsg,ex );
300                    }
301            }
302    
303            /**
304             * 日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­ストを生æ?しますã?
305             * 変換結果は ASCII なので、これをそã?まま setSubject ã‚?InternetAddress
306             * のパラメタとして使用してくださいã€?
307             *
308             * @param text    String
309             *
310             * @return      日本語を含ã‚??ãƒ?ƒ€用ãƒ?‚­スãƒ?
311             * @throws RuntimeException(UnsupportedEncodingException)
312             */
313            public String encodeWord( final String text ) {
314                    try {
315                            return "=?ISO-2022-JP?B?" +
316                                    new String(
317                                            BASE64EncoderStream.encode(
318                                                    CharCodeConverter.sjisToJis(
319                                                            UnicodeCorrecter.correctToCP932(text).getBytes("Windows-31J")
320                                                    )
321                                            )
322                                    ,DEFAULT_CHARSET ) + "?=";              // 5.5.2.6 (2012/05/25) findbugs対å¿?
323                    }
324                    catch( UnsupportedEncodingException ex ) {
325                            String errMsg = "æŒ?®šã?エンコードが出来ませんã€?
326                                                                    + "text=" + text + " , charset=Windows-31J" ;
327                            throw new RuntimeException( errMsg,ex );
328                    }
329            }
330    
331            /**
332             * 日本語を含ã‚?‚¢ドレスを生成しますã?
333             * personal に、日本語が含まれると想定してã�?�¾すã?
334             * サブクラスで、日本語å?ç�?‚’行う場合ã?方法ã?、それぞれ異なりますã?
335             *
336             * @param address    String
337             * @param personal   String
338             *
339             * @return InternetAddress
340             * @throws RuntimeException(UnsupportedEncodingException)
341             */
342            public InternetAddress getAddress( final String address,final String personal ) {
343                    try {
344                            return new InternetAddress( address,encodeWord( personal ) );
345                    }
346                    catch( UnsupportedEncodingException ex ) {
347                            String errMsg = "æŒ?®šã?エンコードが出来ませんã€?
348                                                                    + "address=" + address ;
349                            throw new RuntimeException( errMsg,ex );
350                    }
351            }
352    
353            /**
354             * Content-Transfer-Encoding を指定するå?合ã? ビット数を返しますã?
355             *
356             * Windows系はã€?bit / ISO-2022-JP 系はã€?bit になりますã?
357             *
358             * @return      ビット数("7bit" 固å®?
359             */
360            public String getBit() {
361                    return "7bit" ;
362            }
363    }
364    
365    /**
366     * ãƒ?‚­ストã?本æ–?‚’送信するための DataSource ですã?
367     *
368     * Windows-31J でバイトコードに変換した後ã?独自エンコードにてã€?
369     * Shift-JIS â‡?JIS 変換してã�?�¾すã?
370     *
371     * @version  4.0
372     * @author   Kazuhiko Hasegawa
373     * @since    JDK5.0,
374     */
375    class JISDataSource implements DataSource {
376            private final byte[] data;
377    
378            public JISDataSource( final String str ) {
379                    try {
380                            data = CharCodeConverter.sjisToJis(
381                                    UnicodeCorrecter.correctToCP932(str).getBytes("Windows-31J"));
382    
383                    } catch (UnsupportedEncodingException e) {
384                            String errMsg = "Windows-31J でのエンコーãƒ?‚£ングがå?来ませんã€? + str;
385                            throw new RuntimeException( errMsg,e );
386                    }
387            }
388    
389            /**
390             * ãƒ??タの MIME タイプをæ–?­—å?の形で返しますã?
391             * かならず有効なタイプを返すべきですã?
392             * DataSource の実è£?�Œãƒ??タタイプを 決定できなã�??合ã?ã€?
393             * getContentType は "application/octet-stream" を返すことã‚?提案しますã?
394             *
395             * @return      MIME タイãƒ?
396             */
397            public String getContentType() {
398                    return "text/plain; charset=ISO-2022-JP";
399            }
400    
401            /**
402             * ãƒ??タを表ã�?InputStream を返しますã?
403             * それができなã�??合ã?適åˆ?�ª例外をスローしますã?
404             *
405             * @return InputStream
406             * @throws IOException
407             */
408            public InputStream getInputStream() throws IOException {
409                    return new ByteArrayInputStream( data );
410            }
411    
412            /**
413             * ãƒ??タが書込可能なã‚?OutputStream を返しますã?
414             * それができなã�??合ã?適åˆ?�ª例外をスローしますã?
415             *
416             * ※ こã?クラスでは実è£?�•れてã�?�¾せんã€?
417             *
418             * @return OutputStream
419             * @throws IOException
420             */
421            public OutputStream getOutputStream() throws IOException {
422                    String errMsg = "こã?クラスでは実è£?�•れてã�?�¾せんã€?;
423            //      throw new UnsupportedOperationException( errMsg );
424                    throw new IOException( errMsg );
425            }
426    
427            /**
428             * こã?オブジェクトã? '名前' を返しますã?
429             * こã?名前は下層のオブジェクトã?性質によりますã?
430             * ファイルをカプセル化すã‚?DataSource なã‚?オブジェクトã?
431             * ファイル名を返すようにするかもしれませんã€?
432             *
433             * @return      オブジェクトã?名前
434             */
435            public String getName() {
436                    return "JISDataSource";
437            }
438    }
439    
440    /**
441     * æ–?­—関係ã?コンバã?タですã?
442     * ä¸?ƒ¨コードã?オリジナルは<a href="http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/CCGI/kanjicod.html">Japanese Kanji Code</a>にて公開されてã�?‚‹もã?ですã?
443     * またã?http://www.sk-jp.com/cgi-bin/treebbs.cgi?kako=1&all=644&s=681
444     * にて YOSI さんがå?開されたコードも参è?にしてã�?�¾ã�?とã�?�†か実質同じでã�?ã€?
445     *
446     * @version  4.0
447     * @author   Kazuhiko Hasegawa
448     * @since    JDK5.0,
449     */
450    class CharCodeConverter {
451            private static final byte[] SJIS_KANA;  // 5.1.9.0 (2010/09/01) public â‡?private へ変更
452    
453            /**
454             * インスタンスの生æ?を抑止しますã?
455             */
456            private CharCodeConverter() {
457                    // 何もありませんã€?PMD エラー回避)
458            }
459    
460            static {
461                    try {
462                            // 全角への変換ãƒ??ブル
463                            SJIS_KANA = "。ã?」ã?・ヲァィゥェォャュョãƒ??アイウエオカキクケコサシスセソタチツãƒ?ƒˆナニヌネノハヒフヘã?マミãƒ?ƒ¡モヤユヨラリルレロワン゛ã?".getBytes("Shift_JIS");
464                    } catch( UnsupportedEncodingException ex ) {
465                            throw new RuntimeException( "CANT HAPPEN",ex );
466                    }
467            }
468    
469            /**
470             * Shift_JIS エンコーãƒ?‚£ングスキーãƒ?�«基づくバイトå?ã‚?
471             * ISO-2022-JP エンコーãƒ?‚£ングスキーãƒ?�«変換しますã?
472             * 「半角カナã?は対応するå?角文字に変換しますã?
473             *
474             * @param sjisBytes byte[] エンコードするShift_JISバイトé?åˆ?
475             *
476             * @return byte[] 変換後ã?ISO-2022-JP(JIS)バイトé?åˆ?not null)
477             */
478            public static byte[] sjisToJis( final byte[] sjisBytes ) {
479                    ByteArrayOutputStream out = new ByteArrayOutputStream();
480                    boolean nonAscii = false;
481                    int len = sjisBytes.length;
482                    for(int i = 0; i < len; i++ ) {
483                            if(sjisBytes[i] >= 0) {
484                                    if(nonAscii) {
485                                            nonAscii = false;
486                                            out.write(0x1b);
487                                            out.write('(');
488                                            out.write('B');
489                                    }
490                                    out.write(sjisBytes[i]);
491                            } else {
492                                    if(!nonAscii) {
493                                            nonAscii = true;
494                                            out.write(0x1b);
495                                            out.write('$');
496                                            out.write('B');
497                                    }
498                                    int bt = sjisBytes[i] & 0xff;
499                                    if(bt >= 0xa1 && bt <= 0xdf) {
500                                            // 半角カナã?全角に変換
501                                            int kanaIndex = (bt - 0xA1) * 2;
502                                            sjisToJis(out, SJIS_KANA[kanaIndex], SJIS_KANA[kanaIndex + 1]);
503                                    } else {
504                                            i++;
505                                            if(i == len) { break; }
506                                            sjisToJis(out, sjisBytes[i - 1], sjisBytes[i]);
507                                    }
508                            }
509                    }
510                    if(nonAscii) {
511                            out.write(0x1b);
512                            out.write('(');
513                            out.write('B');
514                    }
515                    return out.toByteArray();
516            }
517    
518            /**
519             * ?‘文字ã??’バイãƒ?Shift_JIS コードを JIS コードに変換して書きå?しますã?
520             */
521            private static void sjisToJis(
522                                    final ByteArrayOutputStream out, final byte bhi, final byte blo) {
523                    int hi = (bhi << 1) & 0xFF;
524                    int lo = blo & 0xFF;
525                    if(lo < 0x9F) {
526                            if(hi < 0x3F) { hi += 0x1F; } else { hi -= 0x61; }
527                            if(lo > 0x7E) { lo -= 0x20; } else { lo -= 0x1F; }
528                    } else {
529                            if(hi < 0x3F) { hi += 0x20; } else { hi -= 0x60; }
530                            lo -= 0x7E;
531                    }
532                    out.write(hi);
533                    out.write(lo);
534            }
535    }
536    
537    /**
538     * unicode と、JIS とのæ–?­—コードã?関係で、変換してã�?�¾すã?
539     *
540     * 0x301c(&#x301c;) をã?0xff5e(&#xff5e;) へã€?
541     * 0x2016(&#x2016;) をã?0x2225(&#x2225;) へã€?
542     * 0x2212(&#x2212;) をã?0xff0d(&#xff0d;) へã€?
543     * それぞれコード変換しますã?
544     *
545     * @version  4.0
546     * @author   Kazuhiko Hasegawa
547     * @since    JDK5.0,
548     */
549    class UnicodeCorrecter {
550    
551            /**
552             * インスタンスの生æ?を抑止しますã?
553             */
554            private UnicodeCorrecter() {
555                    // 何もありませんã€?PMD エラー回避)
556            }
557    
558            /**
559             * Unicode æ–?­—å?の補正を行いますã?
560             * "MS932" コンバã?タでエンコードしようとした際に
561             * 正常に変換できなã�?ƒ¨åˆ?‚’補正しますã?
562             */
563            public static String correctToCP932( final String str ) {
564                    String rtn = "";
565    
566                    if( str != null ) {
567                            int cnt = str.length();
568                            StringBuilder buf = new StringBuilder( cnt );
569                            for(int i=0; i<cnt; i++) {
570                                    buf.append(correctToCP932(str.charAt(i)));
571                            }
572                            rtn = buf.toString() ;
573                    }
574                    return rtn ;
575            }
576    
577            /**
578             * キャラクタ単位に、Unicode æ–?­—å?の補正を行いますã?
579             *
580             * 風間殿のペã?ジを参è€?�«してã�?�¾すã?
581             * @see <a href="http://www.ingrid.org/java/i18n/encoding/ja-conv.html" target="_blank">
582             * http://www.ingrid.org/java/i18n/encoding/ja-conv.html</a>
583             */
584            public static char correctToCP932( final char ch ) {
585                    char rtn = ch;
586    
587                    switch (ch) {
588            //              case 0x00a2:    return 0xffe0;          // ≪
589            //              case 0x00a3:    return 0xffe1;          // ?£
590            //              case 0x00ac:    return 0xffe2;          // μ
591            //              case 0x03bc:    return 0x00b5;          // ・
592            //              case 0x2014:    return 0x2015;          // ??
593            //              case 0x2016:    return 0x2225;          // ≫
594            //              case 0x2212:    return 0xff0d;          // �
595            //              case 0x226a:    return 0x00ab;          // ∥
596            //              case 0x226b:    return 0x00bb;          // ヴ
597            //              case 0x301c:    return 0xff5e;          // ??
598            //              case 0x30f4:    return 0x3094;          // ??
599            //              case 0x30fb:    return 0x00b7;          // ??
600            //              case 0xff0c:    return 0x00b8;          // ?¡
601            //              case 0xffe3:    return 0x00af;          // ?¢
602    
603                            case 0x00a2:    rtn = 0xffe0; break;            // ??(1-81, CENT SIGN)
604                            case 0x00a3:    rtn = 0xffe1; break;            // ?¡ (1-82, POUND SIGN)
605                            case 0x00a5:    rtn = 0x005c; break;            // \ (D/12, YEN SIGN)
606                            case 0x00ac:    rtn = 0xffe2; break;            // ?¢ (2-44, NOT SIGN)
607                            case 0x2016:    rtn = 0x2225; break;            // ∥ (1-34, DOUBLE VERTICAL LINE)
608                            case 0x203e:    rtn = 0x007e; break;            // ~ (F/14, OVERLINE)
609                            case 0x2212:    rtn = 0xff0d; break;            // ??(1-61, MINUS SIGN)
610                            case 0x301c:    rtn = 0xff5e; break;            // ??(1-33, WAVE DASH)
611    
612            //              case 0x301c:    return 0xff5e;
613            //              case 0x2016:    return 0x2225;
614            //              case 0x2212:    return 0xff0d;
615                            default:                break;                  // 4.0.0 (2005/01/31)
616                    }
617                    return rtn;
618            }
619    }