using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Security.Cryptography;
using Externals.Compression.Zip;
using Externals.Compression.Checksums;
using Apewer.Internals;
using System.Diagnostics;
// using System.Runtime.Remoting.Messaging;

namespace Apewer
{

    /// <summary>二进制。</summary>
    public class BinaryUtility
    {

        /// <summary>空字节数组,每次获取都将创建新的引用。</summary>
        public static byte[] EmptyBytes { get { return Constant.EmptyBytes; } }

        #region Bytes Array

        /// <summary>创建数组,元素值为零。</summary>
        public static byte[] ZeroArray(int length = 0)
        {
            if (length < 1) return new byte[0];
            var array = new byte[length];
            for (int i = 0; i < length; i++) array[i] = 0;
            return array;
        }

        /// <summary>所有字节取反。</summary>
        public static byte[] Adverse(byte[] bytes)
        {
            if (bytes == null || bytes.Length < 1) return Constant.EmptyBytes;
            byte[] adverse = new byte[bytes.Length];
            for (int i = 0; i < bytes.Length; i++) adverse[i] = Convert.ToByte(byte.MaxValue - bytes[i]);
            return adverse;
        }

        /// <summary>克隆字节数组。当源为 NULL 时,将获取零元素字节数组。</summary>
        public static byte[] Clone(byte[] bytes)
        {
            if (bytes == null || bytes.LongLength < 0L) return Constant.EmptyBytes;
            var result = new byte[bytes.LongLength];
            bytes.CopyTo(result, 0L);
            return result;
        }

        /// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
        public static byte[] AddTextBom(params byte[] text)
        {
            var bom = new byte[] { 0xEF, 0xBB, 0xBF };
            if (text == null || text.LongLength < 1L) return bom;

            if (text.LongLength >= 3L && text[0] == 0xEF && text[1] == 0xBB && text[2] == 0xBF)
            {
                // contains bom
                var array = new byte[text.LongLength];
                Array.Copy(text, 0L, array, 0L, text.LongLength);
                return array;
            }
            else
            {
                // add bom
                var array = new byte[text.LongLength + 3L];
                Array.Copy(bom, 0L, array, 0L, 3L);
                Array.Copy(text, 0L, array, 3L, text.LongLength);
                return array;
            }
        }

        /// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
        public static byte[] WipeTextBom(byte[] bytes)
        {
            if (bytes == null) return Constant.EmptyBytes;
            var length = bytes.Length;
            if (length >= 3)
            {
                if ((bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
                {
                    var memory = new MemoryStream();
                    memory.Write(bytes, 3, length - 3);
                    var result = memory.ToArray();
                    memory.Dispose();
                    return result;
                }
            }
            return bytes;
        }

        /// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
        public static bool StartsWith(byte[] bytes, params byte[] head)
        {
            var data = bytes;

            if (data == null) return false;
            if (head == null) return false;

            var datalength = data.LongLength;
            var headlength = head.LongLength;
            if (datalength < headlength) return false;
            if (headlength < 1L) return true;

            for (long i = 0; i < head.LongLength; i++)
            {
                if (data[i] != head[i]) return false;
            }
            return true;
        }

        /// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
        public static bool EndsWith(byte[] bytes, params byte[] head)
        {
            var data = bytes;

            if (data == null) return false;
            if (head == null) return false;

            var datalength = data.LongLength;
            var headlength = head.LongLength;
            if (datalength < headlength) return false;
            if (headlength < 1L) return true;

            for (long i = 0; i < headlength; i++)
            {
                var dataindex = datalength - i - 1;
                var headindex = headlength - i - 1;
                if (data[dataindex] != head[headindex]) return false;
            }
            return true;
        }

        #endregion

        #region Text

        /// <summary>将字节数组转换为十六进制文本。</summary>
        public static string ToHex(params byte[] bytes)
        {
            int length = bytes.Length;
            if (length > 0)
            {
                var sb = new StringBuilder();
                for (int i = 0; i < length; i++)
                {
                    sb.Append(Constant.HexCollection[bytes[i] / 16]);
                    sb.Append(Constant.HexCollection[bytes[i] % 16]);
                }
                return sb.ToString();
            }
            return "";
        }

        /// <summary>将十六进制文本转换为字节数组。</summary>
        public static byte[] FromHex(string hex)
        {
            if (string.IsNullOrEmpty(hex) || hex.Length < 2) return Constant.EmptyBytes;
            if (hex.Length % 2 != 0) return Constant.EmptyBytes;

            var lower = hex.ToLower().ToCharArray();
            var half = lower.Length / 2;
            var bytes = new byte[half];
            for (var i = 0; i < half; i++)
            {
                var offset = i * 2;
                var h = Constant.HexCollection.IndexOf(lower[offset]);
                var l = Constant.HexCollection.IndexOf(lower[offset + 1]);
                if (h < 0 || l < 0) return Constant.EmptyBytes;
                bytes[i] = Convert.ToByte((h * 16) + l);
            }

            return bytes;
        }

        /// <summary>将字节数组格式化为大写十六进制字符串。</summary>
        public static string ToX2(params byte[] bytes)
        {
            if (bytes == null) return "";
            var sb = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                sb.Append(bytes[i].ToString("X2"));
            }
            return sb.ToString();
        }

        /// <summary>Byte[] -> Base64</summary>
        public static string ToBase64(params byte[] bytes)
        {
            if (bytes.Length < 1) return Constant.EmptyString;
            try { return Convert.ToBase64String(bytes); }
            catch { return Constant.EmptyString; }
        }

        /// <summary>Base64 -> Byte[]</summary>
        public static byte[] FromBase64(string base64)
        {
            if (string.IsNullOrEmpty(base64)) return Constant.EmptyBytes;
            try { return Convert.FromBase64String(base64); }
            catch { return Constant.EmptyBytes; }
        }

        /// <summary>转换字节数组为文本,默认使用 UTF-8 代码页。</summary>
        public static string ToText(byte[] bytes, Encoding encoding = null)
        {
            if (bytes.Length < 1) return Constant.EmptyString;
            try { return (encoding ?? Encoding.UTF8).GetString(bytes); }
            catch { return Constant.EmptyString; }
        }

        /// <summary>转换文本为字节数组,默认使用 UTF-8 代码页。</summary>
        public static byte[] FromText(string text, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(text)) return Constant.EmptyBytes;
            try { return (encoding ?? Encoding.UTF8).GetBytes(text); }
            catch { return Constant.EmptyBytes; }
        }

        /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
        public static bool ContainsBOM(byte[] bytes)
        {
            if (bytes == null) return false;
            if (bytes.LongLength < 3L) return false;
            return bytes[0L] == 0xEF && bytes[1L] == 0xBB && bytes[2L] == 0xBF;
        }

        /// <summary>检查字节数组是 UTF-8 文本。可指定检查的最大字节长度。</summary>
        /// <param name="bytes">要检查的字节数组。</param>
        /// <param name="offset">已检查的偏移量。</param>
        /// <param name="checkLength">检查的最大字节长度。</param>
        public static bool IsUTF8(byte[] bytes, Class<int> offset, int checkLength = 1048576)
        {
            return IsUTF8(bytes, offset, checkLength);
        }

        /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
        /// <param name="bytes">要检查的字节数组。</param>
        /// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
        /// <param name="offset">已检查的偏移量,用于调试。</param>
        public static bool IsUTF8(byte[] bytes, int checkLength = 1048576, Class<int> offset = null)
        {
            // UTF8在Unicode的基础上制定了这样一套规则:
            // 1.对于单字节字符,比特位的最高位为0;
            // 2.对于多字节字符,第一个字节的比特位中,最高位有n个1,剩下的n - 1个字节的比特位中,最高位都是10。
            // 好了,我知道你一定看不懂,那就先来看看下面例子后,再去看上面定义吧。
            // 比如一个字符(“A”),它在UTF8中的编码为(用二进制表示):01000001。由于比特位的最高位是0,表示它是单字节,它只需要1个字节就可以表示。
            // 再比如一个字符(“判”),它在UTF8中的编码为(用二进制表示):11100101 10001000 10100100。由于在第一个字节中,比特位最高位有3个1,说明这个字符总共需要3个字节来表示,且后3 - 1 = 2位字节中,比特位的最高位为10。

            if (bytes == null) return false;
            var length = bytes.LongLength;

            // 检查 BOM 头。
            if (ContainsBOM(bytes)) return true;

            var hasOffset = offset != null;

            var append = 0;
            if (hasOffset) offset.Value = 0;
            for (int i = 0; i < length; i++)
            {
                if (checkLength > 0 && i >= checkLength) break;

                var b = bytes[i];
                if (hasOffset) offset.Value = i;

                // 追加字节最高位为 0。
                if (append > 0)
                {
                    if (b >> 6 != 2) return false;
                    append -= 1;
                    continue;
                }

                // ASCII 字符。
                if (b < 128) continue;

                // 2 字节 UTF-8。
                if (b >= 0xC0 && b <= 0xDF)
                {
                    append = 1;
                    continue;
                }

                // 3 字节 UTF-8 字符。
                if (b >= 0xE0 && b <= 0xEF)
                {
                    append = 2;
                    continue;
                }

                // 4 字节 UTF-8 字符。
                if (b >= 0xF0 && b <= 0xF7)
                {
                    append = 3;
                    continue;
                }

                // 5 字节 UTF-8 字符。
                if (b >= 0xF8 && b <= 0xFB)
                {
                    append = 4;
                    continue;
                }

                // 6 字节 UTF-8 字符。
                if (b >= 0xFC && b <= 0xFD)
                {
                    append = 5;
                    continue;
                }

                // 未知字节,非 UTF-8 定义。
                return false;
            }

            return true;
        }

        #endregion

        /// <summary>为字节数组增加字节。</summary>
        public static byte[] Append(byte[] head, params byte[] bytes)
        {
            var memory = new MemoryStream();
            if (head != null && head.Length > 0) Write(memory, head);
            if (bytes != null && bytes.Length > 0) Write(memory, bytes);
            var whole = memory.ToArray();
            return whole;
        }

        /// <summary>合并字节数组。</summary>
        public static byte[] Merge(params byte[][] array)
        {
            var memory = new MemoryStream();
            foreach (var bytes in array)
            {
                if (bytes == null || bytes.LongLength < 1L) continue;
                Write(memory, bytes);
            }
            var whole = memory.ToArray();
            return whole;
        }

        #region 压缩、解压。

        /// <summary>对数据进行 GZip 压缩。</summary>
        public static byte[] ToGzip(byte[] plain)
        {
            if (plain == null) return Constant.EmptyBytes;
            if (plain.Length == 0) return Constant.EmptyBytes;

            byte[] result;
            var output = new MemoryStream();
            var zip = new GZipStream(output, CompressionMode.Compress, true);
            zip.Write(plain, 0, plain.Length);
            zip.Close();
            zip.Dispose();
            result = output.ToArray();
            output.Close();
            output.Dispose();
            return result;
        }

        /// <summary>对数据进行 GZip 解压。</summary>
        public static byte[] FromGzip(byte[] gzip)
        {
            if (gzip == null) return Constant.EmptyBytes;
            if (gzip.Length == 0) return Constant.EmptyBytes;

            byte[] result;
            var input = new MemoryStream(gzip);
            var output = new MemoryStream();
            input.Position = 0;
            var zip = new GZipStream(input, CompressionMode.Decompress, true);
            Read(zip, output, 64, null);
            result = output.ToArray();
            zip.Close();
            zip.Dispose();
            input.Close();
            input.Dispose();
            output.Close();
            output.Dispose();
            return result;
        }

        /// <summary>压缩字典为 ZIP 文件。</summary>
        /// <param name="files">由文件名和文件内容组成的字典。</param>
        /// <param name="target">要输出的 ZIP 流。</param>
        public static Exception ToZip(Dictionary<string, byte[]> files, Stream target)
        {
            var zip = null as ZipOutputStream;
            try
            {
                if (files == null) return new ArgumentNullException();
                if (target == null) return new ArgumentNullException();
                if (!target.CanWrite) return new NotSupportedException();

                zip = new ZipOutputStream(target);
                zip.SetLevel(1);

                foreach (var file in files)
                {
                    var crc = new Crc32();
                    crc.Reset();
                    crc.Update(file.Value);

                    var zipentry = new ZipEntry(file.Key);
                    zipentry.CompressionMethod = CompressionMethod.Deflated;
                    //vzipentry.Size = vfile.Value.LongLength;
                    zipentry.Crc = crc.Value;
                    zipentry.IsUnicodeText = true;

                    zip.PutNextEntry(zipentry);
                    zip.Write(file.Value, 0, file.Value.Length);
                    zip.CloseEntry();
                }

                zip.IsStreamOwner = false;
                zip.Finish();
                zip.Flush();
                zip.Close();

                return null;
            }
            catch (Exception ex)
            {
                KernelUtility.Dispose(zip);
                return ex;
            }
        }

        /// <summary>压缩到 ZIP 流。</summary>
        /// <param name="names">ZIP 内的文件名。</param>
        /// <param name="target">要输出的 ZIP 流。</param>
        /// <param name="modifildGetter">获取文件的修改时间。</param>
        /// <param name="disposeFiles">释放已写入 ZIP 的输入流。</param>
        public static Exception ToZip(IEnumerable<string> names, Stream target, Func<string, Stream> inputGetter, Func<string, DateTime> modifildGetter = null, bool disposeFiles = false)
        {
            var zip = null as ZipOutputStream;
            try
            {
                if (names == null) return new ArgumentNullException("names");
                if (target == null) return new ArgumentNullException("target");
                if (!target.CanWrite) return new ArgumentNullException("target");

                zip = new ZipOutputStream(target);
                zip.SetLevel(1);

                foreach (var name in names)
                {
                    if (string.IsNullOrEmpty(name)) continue;

                    // stream
                    var capacity = 1024;
                    var input = inputGetter == null ? null : inputGetter(name);
                    if (input != null)
                    {
                        if (!input.CanSeek || !input.CanRead)
                        {
                            if (disposeFiles) KernelUtility.Dispose(input);
                            return new NotSupportedException("获取到的输入流不支持 Seek 或 Read。");
                        }
                    }

                    var crc = new Crc32();
                    crc.Reset();
                    if (input != null)
                    {
                        input.ResetPosition();
                        while (true)
                        {
                            var count = 0;
                            var buffer = new byte[capacity];
                            count = input.Read(buffer, 0, buffer.Length);
                            if (count == 0) break;
                            crc.Update(buffer, 0, count);
                        }
                    }

                    var entry = new ZipEntry(name);
                    entry.CompressionMethod = CompressionMethod.Deflated;
                    //vzipentry.Size = vfile.Value.LongLength;
                    entry.Crc = crc.Value;
                    entry.IsUnicodeText = true;
                    if (modifildGetter != null) entry.DateTime = modifildGetter(name);

                    zip.PutNextEntry(entry);
                    if (input != null)
                    {
                        input.ResetPosition();
                        while (true)
                        {
                            var count = 0;
                            var buffer = new byte[capacity];
                            count = input.Read(buffer, 0, buffer.Length);
                            if (count == 0) break;
                            zip.Write(buffer, 0, count);
                        }
                    }
                    zip.CloseEntry();

                    if (disposeFiles) KernelUtility.Dispose(input);
                }

                zip.IsStreamOwner = false;
                zip.Finish();
                zip.Flush();
                zip.Close();

                return null;
            }
            catch (Exception ex)
            {
                KernelUtility.Dispose(zip);
                return ex;
            }
        }

        /// <summary>压缩字典为 ZIP 包。</summary>
        /// <param name="files">由文件名和文件内容组成的字典。</param>
        public static byte[] ToZip(Dictionary<string, byte[]> files)
        {
            if (files == null) return null;

            var output = new MemoryStream();

            var input = null as Stream;
            var ex = ToZip(files.Keys, output, (name) =>
            {
                KernelUtility.Dispose(input);
                if (name.IsEmpty()) return null;

                var bytes = files[name];
                if (bytes == null || bytes.LongLength < 1L) return null;

                input = new MemoryStream();
                Write(input, bytes);
                return input;
            }, null, true);
            KernelUtility.Dispose(input);

            var result = output.ToArray();
            KernelUtility.Dispose(result);
            return result;
        }

        /// <summary>解压 ZIP 文件。</summary>
        public static Exception FromZip(Stream input, ZipOnFile onFile, ZipOnDirectory onDirectory = null, bool disposeOutput = false)
        {
            const int BufferCapacity = 1024;

            var zip = null as ZipInputStream;
            try
            {
                if (input == null) return new ArgumentNullException("input");
                if (!input.CanRead) return new NotSupportedException();
                if (onFile == null) return new ArgumentNullException("extraction");

                zip = new ZipInputStream(input);
                while (true)
                {
                    var entry = zip.GetNextEntry();
                    if (entry == null) break;

                    var name = entry.Name;
                    var size = entry.Size;
                    var modified = entry.DateTime;

                    if (entry.IsFile)
                    {
                        var output = null as Stream;
                        try
                        {
                            output = onFile(name, size, modified);
                            if (output == null) continue;
                            if (!output.CanWrite)
                            {
                                KernelUtility.Dispose(output);
                                continue;
                            }

                            var writed = 0L;
                            while (true)
                            {
                                var buffer = new byte[BufferCapacity];
                                var count = zip.Read(buffer, 0, BufferCapacity);
                                writed += count;
                                if (count < 1) break;
                                output.Write(buffer, 0, count);
                            }

                            if (disposeOutput) KernelUtility.Dispose(output, true);
                        }
                        catch (Exception ex)
                        {
                            if (disposeOutput) KernelUtility.Dispose(output, true);
                            KernelUtility.Dispose(zip);
                            return ex;
                        }
                    }

                    if (onDirectory != null && entry.IsDirectory)
                    {
                        try
                        {
                            onDirectory(name, modified);
                        }
                        catch (Exception ex)
                        {
                            KernelUtility.Dispose(zip);
                            return ex;
                        }
                    }
                }
                zip.Dispose();

                return null;
            }
            catch (Exception ex)
            {
                KernelUtility.Dispose(zip);
                return ex;
            }
        }

        /// <summary>解压 .ZIP 文件为字典。</summary>
        public static Dictionary<string, byte[]> FromZip(byte[] zip)
        {
            var result = new Dictionary<string, byte[]>();
            if (zip == null) return result;
            if (zip.LongLength < 1) return result;

            var packagememory = new System.IO.MemoryStream(zip);
            try
            {
                var zipstream = new ZipInputStream(packagememory);
                while (true)
                {
                    var entry = zipstream.GetNextEntry();
                    if (entry == null) break;

                    if (entry.IsFile)
                    {
                        var cellname = entry.Name;
                        var celldata = new byte[0];
                        {
                            var cellstream = new System.IO.MemoryStream();
                            while (true)
                            {
                                var blockdata = new byte[1024];
                                var blockread = zipstream.Read(blockdata, 0, 1024);
                                if (blockread < 1) break;
                                cellstream.Write(blockdata, 0, blockread);
                            }
                            celldata = cellstream.ToArray();
                            cellstream.Dispose();
                        }
                        if (result.ContainsKey(cellname)) result[cellname] = celldata;
                        else result.Add(cellname, celldata);
                    }
                }
                zipstream.Dispose();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            packagememory.Dispose();
            return result;
        }

        #endregion

        #region Stream

        /// <summary>关闭,并释放流。</summary>
        public static void Dispose(Stream stream, bool flush = false, bool close = true)
        {
            if (stream != null)
            {
                try { if (flush) stream.Flush(); } catch { }
                try { if (close) stream.Close(); } catch { }
                try { stream.Dispose(); } catch { }
            }
        }

        /// <summary>关闭,并释放流。</summary>
        public static void Dispose(IEnumerable<Stream> streams, bool flush = false, bool close = true)
        {
            if (streams != null)
            {
                foreach (var stream in streams) Dispose(stream, flush, close);
            }
        }

        /// <summary>重置流的位置到开始位置。</summary>
        public static bool ResetPosition(Stream stream)
        {
            if (stream == null) return false;
            try
            {
                stream.Position = 0;
                if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary></summary>
        private static long Read(Stream source, Stream destination, int capacit, Action<Int64> progress)
        {
            if (source == null) return 0;
            if (destination == null) return 0;
            if (!source.CanRead) return 0;
            if (!destination.CanWrite) return 0;

            long result = 0;
            var failed = false;
            var callback = progress != null;
            while (true)
            {
                var count = 0;
                var buffer = new byte[capacit];
                try { count = source.Read(buffer, 0, buffer.Length); } catch { failed = true; }
                if (failed) break;
                if (callback) progress(result);
                if (count == 0) break;
                try { destination.Write(buffer, 0, count); } catch { failed = true; }
                if (failed) break;
                result += count;
            }
            return result;
        }

        /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的字节数。</summary>
        /// <param name="source">源流。</param>
        /// <param name="destination">目标流。</param>
        /// <param name="progress">进度回调。</param>
        public static long Read(Stream source, Stream destination, Action<Int64> progress = null)
        {
            return Read(source, destination, Constant.DefaultBufferCapacity, progress);
        }

        /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
        /// <param name="sources">源流。</param>
        /// <param name="destination">目标流。</param>
        public static long Read(IEnumerable<Stream> sources, Stream destination)
        {
            var count = 0L;
            if (sources != null)
            {
                foreach (var source in sources)
                {
                    count += Read(source, destination, Constant.DefaultBufferCapacity, null);
                }
            }
            return count;
        }

        /// <summary>读取源流中的数据。</summary>
        /// <param name="source">源流。</param>
        /// <param name="dispose">读取结束后释放源流。</param>
        public static byte[] Read(Stream source, bool dispose = false)
        {
            var memory = new MemoryStream();
            Read(source, memory, Constant.DefaultBufferCapacity, null);
            var result = memory.ToArray();
            Dispose(memory);
            if (dispose) Dispose(source);
            return result;
        }

        /// <summary>向目标流写入数据。</summary>
        ///  <param name="destination">目标流。</param>
        ///  <param name="bytes">要写入的数据。</param>
        public static long Write(Stream destination, params byte[] bytes)
        {
            if (bytes == null) return 0L;
            if (bytes.LongLength < 1L) return 0L;
            if (destination == null) return 0L;

            var count = 0L;
            try
            {
                if (!destination.CanWrite) return 0L;
                for (var i = 0L; i < bytes.LongLength; i++)
                {
                    destination.WriteByte(bytes[i]);
                    count += 1L;
                }
            }
            catch { }

            return count;
        }

        #endregion

        #region AES

        private static RijndaelManaged Aes256Provider(byte[] argKey)
        {
            var key = argKey ?? Constant.EmptyBytes; // AesFill(argKey);
            var p = new RijndaelManaged();
            p.Key = key;
            p.Mode = CipherMode.ECB;
            p.Padding = PaddingMode.PKCS7;
            return p;
        }

        /// <summary>对数据进行 AES 加密。</summary>
        public static byte[] Aes256Encrypt(byte[] bytes, byte[] key = null)
        {
            if (bytes == null) return Constant.EmptyBytes;
            if (bytes.Length == 0) return Constant.EmptyBytes;
            var rm = Aes256Provider(key);
            var result = new byte[0];
            var ct = rm.CreateEncryptor();
            try
            {
                result = ct.TransformFinalBlock(bytes, 0, bytes.Length);
            }
            catch { }
            return result;
        }

        /// <summary>对数据进行 AES 解密。</summary>
        public static byte[] Aes256Decrypt(byte[] cipher, byte[] key = null)
        {
            if (cipher == null) return Constant.EmptyBytes;
            if (cipher.Length == 0) return Constant.EmptyBytes;
            var rm = Aes256Provider(key);
            var result = new byte[0];
            var ct = rm.CreateDecryptor();
            try
            {
                result = ct.TransformFinalBlock(cipher, 0, cipher.Length);
            }
            catch { }
            ct.Dispose();
            return result;
        }

        #endregion

        #region Hash

        private static byte[] ComputeHash(HashAlgorithm csp, byte[] bytes)
        {
            if (bytes != null)
            {
                try
                {
                    var result = csp.ComputeHash(bytes);
                    csp.Clear();
#if !NET20
                    csp.Dispose();
#endif
                    return result;
                }
                catch { }
            }
            return Constant.EmptyBytes;
        }

        private static byte[] ComputeHash(HashAlgorithm csp, Stream stream, bool dispose, Action<Int64> progress)
        {
            if (progress == null)
            {
                if (stream != null)
                {
                    var result = Constant.EmptyBytes;
                    try
                    {
                        result = csp.ComputeHash(stream);
                        csp.Clear();
#if !NET20
                        csp.Dispose();
#endif
                    }
                    catch { }
                    if (dispose) stream.Dispose();
                    return result;
                }
                return Constant.EmptyBytes;
            }
            else
            {
                if (stream == null) return Constant.EmptyBytes;

                // 初始化。
                var validcallback = progress != null;
                var capacity = Constant.DefaultBufferCapacity;
                var buffer = new byte[capacity];
                csp.Initialize();

                // 读取。
                var failed = false;
                while (true)
                {
                    var read = 0;
                    try { read = stream.Read(buffer, 0, capacity); }
                    catch { failed = true; }

                    if (read < capacity)
                    {
                        if (read < 1)
                        {
                            csp.TransformFinalBlock(new byte[0], 0, 0);
                        }
                        else
                        {
                            csp.TransformFinalBlock(buffer, 0, Convert.ToInt32(read));
                        }
                        break;
                    }
                    else
                    {
                        csp.TransformBlock(buffer, 0, Convert.ToInt32(read), buffer, 0);
                    }
                }

                if (failed)
                {
                    csp.Clear();
#if !NET20
                    csp.Dispose();
#endif
                    return Constant.EmptyBytes;
                }
                else
                {
                    var result = csp.Hash;
                    csp.Clear();
#if !NET20
                    csp.Dispose();
#endif
                    return result;
                }
            }
        }

        /// <summary>获取 MD5 值。</summary>
        public static byte[] MD5(params byte[] bytes)
        {
            return ComputeHash(new MD5CryptoServiceProvider(), bytes);
        }

        /// <summary>获取 MD5 值。</summary>
        public static byte[] MD5(Stream stream, Action<Int64> progress = null)
        {
            return ComputeHash(new MD5CryptoServiceProvider(), stream, false, progress);
        }

        /// <summary>获取 SHA1 值。</summary>
        public static byte[] SHA1(params byte[] bytes)
        {
            return ComputeHash(new SHA1CryptoServiceProvider(), bytes);
        }

        /// <summary>获取 SHA1 值。</summary>
        public static byte[] SHA1(Stream stream, Action<Int64> progress = null)
        {
            return ComputeHash(new SHA1CryptoServiceProvider(), stream, false, progress);
        }

#if !NET20

        /// <summary>获取 SHA256 值。</summary>
        public static byte[] SHA256(params byte[] bytes)
        {
            return ComputeHash(new SHA256CryptoServiceProvider(), bytes);
        }

        /// <summary>获取 SHA256 值。</summary>
        public static byte[] SHA256(Stream stream, Action<Int64> progress = null)
        {
            return ComputeHash(new SHA256CryptoServiceProvider(), stream, false, progress);
        }

#endif

        #endregion

    }

}