package org.maachang.util;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.security.MessageDigest;

/**
 * バイナリ情報をDigestに変換. <BR>
 * <BR>
 * バイナリ情報をDigestに変換します.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
public class Digest {

    /**
     * バッファサイズ.
     */
    private static final int BUFFER = 1024;

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @param offset
     *            変換対象バイナリの変換オフセット値を設定します.
     * @param length
     *            変換対象バイナリの変換長を設定します.
     * @return byte[] 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final byte[] convert(String digest, InputStream stream)
            throws Exception {

        int len;
        BufferedInputStream bi = null;
        MessageDigest md = null;
        byte[] buf = null;
        byte[] ret = null;

        if (stream == null) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {

            md = MessageDigest.getInstance(digest);
            bi = new BufferedInputStream(stream);
            buf = new byte[BUFFER];

            for (;;) {
                if ((len = bi.read(buf)) <= 0) {
                    break;
                }
                md.update(buf, 0, len);
            }

            ret = md.digest();

        } catch (Exception e) {
            ret = null;
            throw e;
        } finally {
            try {
                bi.close();
            } catch (Exception ee) {
            }
            bi = null;
            buf = null;
            md = null;
        }

        return ret;
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @return byte[] 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final byte[] convertBinary(String digest, byte[] bin)
            throws Exception {

        int len;
        if (bin == null || (len = bin.length) <= 0) {
            throw new IllegalArgumentException("引数は不正です");
        }

        return Digest.convertBinary(digest, bin, 0, len);
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @param length
     *            変換対象バイナリの変換長を設定します.
     * @return byte[] 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final byte[] convertBinary(String digest, byte[] bin,
            int length) throws Exception {

        return Digest.convertBinary(digest, bin, 0, length);
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @param offset
     *            変換対象バイナリの変換オフセット値を設定します.
     * @param length
     *            変換対象バイナリの変換長を設定します.
     * @return byte[] 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final byte[] convertBinary(String digest, byte[] bin,
            int offset, int length) throws Exception {

        MessageDigest md = null;
        byte[] ret = null;

        if (bin == null || bin.length <= 0 || offset < 0 || length < 0) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {

            md = MessageDigest.getInstance(digest);
            md.update(bin, offset, length);
            ret = md.digest();

        } catch (Exception e) {
            ret = null;
            throw e;
        } finally {
            md = null;
        }

        return ret;
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @return String 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final String convert(String digest, byte[] bin)
            throws Exception {

        int len;
        if (bin == null || (len = bin.length) <= 0) {
            throw new IllegalArgumentException("引数は不正です");
        }

        return Digest.convert(digest, bin, 0, len);
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @param length
     *            変換対象バイナリの変換長を設定します.
     * @return String 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final String convert(String digest, byte[] bin, int length)
            throws Exception {

        return Digest.convert(digest, bin, 0, length);
    }

    /**
     * バイナリ情報をDigestに変換します. <BR>
     * <BR>
     * バイナリ情報をDigestに変換します. <BR>
     * 
     * @param digest
     *            対象のダイジェスト条件を設定します.
     * @param bin
     *            変換対象のバイナリ情報を設定します.
     * @param offset
     *            変換対象バイナリの変換オフセット値を設定します.
     * @param length
     *            変換対象バイナリの変換長を設定します.
     * @return String 変換されたDigest情報が返されます.
     * @throws Exception
     *             例外.
     */
    public static final String convert(String digest, byte[] bin, int offset,
            int length) throws Exception {

        int i;
        int len;

        byte[] tmp = null;
        StringBuffer buf = null;
        MessageDigest md = null;
        String ret = null;

        if (bin == null || bin.length <= 0 || offset < 0 || length < 0) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {

            md = MessageDigest.getInstance(digest);
            md.update(bin, offset, length);
            tmp = md.digest();

            len = tmp.length;
            buf = new StringBuffer(len);

            for (i = 0; i < len; i++) {
                buf.append(Integer.toString((tmp[i] & 0x000000f0) >> 4, 16));
                buf.append(Integer.toString(tmp[i] & 0x0000000f, 16));
            }

            ret = buf.toString();

        } catch (Exception e) {
            ret = null;
            throw e;
        } finally {
            md = null;
            tmp = null;
            buf = null;
        }

        return ret;
    }

    private Digest() {
    }
}
