/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//    データ変換クラス：バイト配列を16進法または
//                  BASE64形式でバイト表示するStringオブジェクトに変換する
//
//        変更履歴
//           2004.01.08 新規作成（移植）        中山雅文
//

package jp.co.ntt.lms.xmo.util;


/**
 * バイト配列を16進法かBASE64形式でバイト表示するStringオブジェクトに変換する<BR>
 *
 */

public class DataConverter {

    //==========================================================================
    //	 内部フィールド
    //==========================================================================
    private static String[] hexDigits = {"0","1","2","3","4","5","6","7",
    "8","9","a","b","c","d","e","f"};

    //==========================================================================
    //	コンストラクタ
    //==========================================================================
    public DataConverter() {}

    //==========================================================================
    //  外部メソッド
    //==========================================================================
    //--------------------------------------------------------------------------
    /**
    * 1バイトを16進法の文字列に変換する<BR>
    * @param	byte    b
    * @return	String  byteToHexString
    */
    //--------------------------------------------------------------------------
    public static String byteToHexString(byte b)
                                        throws Exception {
        try{

            int n = b;
            if(n < 0) n = 256 + n;
            int d1 = n / 16;
            int d2 = n % 16;
            return hexDigits[d1]+hexDigits[d2];

        }catch(Exception e){
            throw new Exception("DataConvert error.");
        }
    }
    //--------------------------------------------------------------------------
    /**
    * 1バイト配列を16進法の文字列に変換する<BR>
    * @param	byte[]  b
    * @return	String  byteArrayToHexString
    */
    //--------------------------------------------------------------------------
    public static String byteArrayToHexString(byte[] b)
                                                throws Exception {
        String result = "";
        try{

            for(int i=0;i<b.length;++i)
            result += byteToHexString(b[i]);
            return result;

        }catch(Exception ex){
            throw ex;
        }
    }

    //--------------------------------------------------------------------------
    /**
    * バイト配列を16進法の文字列に変換する(RFC 1421)<BR>
    * @param	byte[]  b
    * @param	int     len
    * @return	String  byteArrayToBase64String
    */
    //--------------------------------------------------------------------------
    public static String byteArrayToBase64String(byte[] b, int len)
                                                throws Exception {
        String s = "";
        String result = "";
        try{
            int n = len / 3;
            int m = len % 3;

            for(int i=0; i<n; ++i) {
                int j = i*3;
                s += toBase64(b[j],b[j+1],b[j+2]);
            }

            if(m == 1) {
                s += toBase64(b[len-1]);
            }else if(m==2){
                s += toBase64(b[len-2],b[len-1]);
            }

            // 64 charごとに挿入する
            len = s.length();
            n = len / 64;
            m = len % 64;

            for(int i=0; i<n; ++i) {
                result += s.substring(i*64,(i+1)*64) + "\n";
            }

            if(m > 0) {
                result += s.substring(n*64,len) + "\n";
            }
            return result;

        }catch(Exception ex){
            throw ex;
        }
    }

    //--------------------------------------------------------------------------
    /**
    * バイト配列をBASE64形式の文字列に変換する(RFC 1421))<BR>
    * @param	byte[]  b
    * @return	String  byteArrayToBase64String
    */
    //--------------------------------------------------------------------------
    public static String byteArrayToBase64String(byte[] b)
                                            throws Exception {
        try{

            return byteArrayToBase64String(b,b.length);

         }catch(Exception ex){
            throw ex;
        }
    }

    //--------------------------------------------------------------------------
    /**
    * BASE64形式の文字列をバイト配列に変換する(RFC 1421))<BR>
    * @param	byte[]  b
    * @return	String  byteArrayToBase64String
    */
    //--------------------------------------------------------------------------
    public static byte[] base64StringToByteArray(String s)
                                                   throws Exception {
        String t = "";

        s = s.trim();
        try{
            for(int i=0;i<s.length();++i) {
                char c = s.charAt(i);
                if(c == '\n') {
                    continue;
                } else if((c>='A' && c<='Z') || (c>='a' && c<='z') ||
                    (c>='0' && c<='9') || c=='+' || c=='/') {
                    t += c;
                } else if(c=='=') {
                    break;
                }  else {
                    throw new NumberFormatException();
                }
            }

            int len = t.length();
            int n = 3*(len/4);
            switch(len % 4) {
            case 1:
                throw new NumberFormatException();
            case 2:
                len += 2;
                n += 1;
                t += "==";
                break;
            case 3:
                ++len;
                n += 2;
                t += "=";
                break;
            }

            byte[] b = new byte[n];
            for(int i=0; i < len/4; ++i) {
                byte[] temp = base64ToBytes(t.substring(4*i,4*(i+1)));
                for(int j=0;j<temp.length;++j) {
                    b[3*i+j] = temp[j];
                }
            }
            return b;

        }catch(Exception ex){
            throw ex;
        }
    }

    //==========================================================================
    //  内部メソッド
    //==========================================================================
    //--------------------------------------------------------------------------
    /**
    * BASE64形式への変換を実行する<BR>
    * @param	byte      b1
    * @param	byte      b2
    * @param	byte      b3
    * @return	String  toBase64
    */
    //--------------------------------------------------------------------------
    private static String toBase64(byte b1, byte b2, byte b3)
                                            throws Exception {
        String result = "";
        try{
            int[] digit = new int[4];
            digit[0] = (b1 & 0xFC) >>> 2;
            digit[1] = (b1 & 0x03) << 4;
            digit[1] |= (b2 & 0xF0) >> 4;
            digit[2] = (b2 & 0x0F) << 2;
            digit[2] |= (b3 & 0xC0) >> 6;
            digit[3] = (b3 & 0x3F);

            for(int i=0;i<digit.length;++i)
            result += base64Digit(digit[i]);
            return result;

        }catch(Exception ex){
            throw ex;
        }

    }
    //--------------------------------------------------------------------------
    /**
    * BASE64への変換にパディングを行う。<BR>
    * @param	byte[]  b1
    * @param	byte[]  b2
    * @return	String  toBase64
    */
    //--------------------------------------------------------------------------
    private static String toBase64(byte b1, byte b2)
                                            throws Exception {
        String result = "";
        try{
            int[] digit = new int[3];
            digit[0] = (b1 & 0xFC) >>> 2;
            digit[1] = (b1 & 0x03) << 4;
            digit[1] |= (b2 & 0xF0) >> 4;
            digit[2] = (b2 & 0x0F) << 2;

            for(int i=0;i<digit.length;++i)
            result += base64Digit(digit[i]);
            result += "=";
            return result;

        }catch(Exception ex){
            throw ex;
        }
    }
    //--------------------------------------------------------------------------
    /**
    * BASE64への変換にパディングを行う。<BR>
    * @param	byte[]  b1
    * @return	String  toBase64
    */
    //--------------------------------------------------------------------------
    private static String toBase64(byte b1)
                                    throws Exception {
        String result = "";
        try{
            int[] digit = new int[2];
            digit[0] = (b1 & 0xFC) >>> 2;
            digit[1] = (b1 & 0x03) << 4;

            for(int i=0;i<digit.length;++i)
            result += base64Digit(digit[i]);
            result += "==";
            return result;

        }catch(Exception ex){
            throw ex;
        }
    }
    //--------------------------------------------------------------------------
    /**
    * BASE64への変換にパディングを行う。<BR>
    * @param	int     i
    * @return	char  base64Digit
    */
    //--------------------------------------------------------------------------
    private static char base64Digit(int i) throws Exception {
        try{
            if(i<26) return (char) ('A' + i);
            if(i<52) return (char) ('a' + (i - 26));
            if(i<62) return (char) ('0' + (i - 52));

            if(i == 62) {
                return '+';
            } else {
                return '/';
            }

        } catch(Exception e){
            throw e;
        }
    }

    //--------------------------------------------------------------------------
    /**
    * BASE64への変換にパディングを行う。<BR>
    * @param	String  s
    * @return	byte[]  base64ToBytes
    */
    //--------------------------------------------------------------------------
    private static byte[] base64ToBytes(String s) throws Exception {
        try{
            int len = 0;
            for(int i=0;i<s.length();++i)
            if(s.charAt(i) != '=') ++len;
            int[] digit = new int[len];

            for(int i=0;i<len;++i) {
                char c = s.charAt(i);
                if(c>='A' && c<='Z') digit[i] = c - 'A';
                else if(c>='a' && c<='z') digit[i] = c - 'a' + 26;
                else if(c>='0' && c<='9') digit[i] = c - '0' + 52;
                else if(c=='+') digit[i] = 62;
                else if(c=='/') digit[i] = 63;
            }

            byte[] b = new byte[len-1];
            switch(len) {
            case 4:
                b[2] = (byte) ((((digit[2]) & 0x03) << 6) | digit[3]);
            case 3:
                b[1] = (byte) ((((digit[1]) & 0x0F) << 4) | ((digit[2] & 0x3C) >>> 2));
            case 2:
                b[0] = (byte) ((digit[0] << 2) | ((digit[1] & 0x30) >>> 4));
            }
            return b;

        } catch(Exception e){
            throw e;
        }
    }
}