[C#]將 byte陣列(byte array) 以 Base64 編碼/解碼 並以 byte陣列(byte array) 作為輸出

  • 7322
  • 0
  • C#
  • 2016-10-27

摘要: base64 encode (decode) to byte array, 將 byte陣列(byte array) 以 Base64 編碼/解碼 並以 byte陣列(byte array) 作為輸出

Title: base64 encode (decode) to byte array

使用說明:

下文程式碼為使用範例,將myData 作 Base64 編碼後,再還原成未編碼的資料。

static void Main(string[] args)
{
    byte[] myData = new byte[] { 125, 125};
    byte[] base64 = ByteConvert.Base64Encode(myData);
    byte[] rawMyData = ByteConvert.Base64Decode(base64);
}

 

ByteConvert 類別的原始碼:

下面的程式碼為實作 Base64 編碼/解碼 出 byte 陣列

using System;
using System.Text;

namespace Base64Byte
{
    public class ByteConvert
    {
        private static readonly byte[] _encodeTable = 
                                        Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                                              + "abcdefghijklmnopqrstuvwxyz"
                                                              + "0123456789+/");

        /// <summary>
        /// Base64 encode
        /// </summary>
        /// <param name="data">raw data</param>
        /// <returns>base64 encode data</returns>
        public static byte[] Base64Encode(byte[] data)
        {
            if (data == null) throw new ArgumentNullException();

            var bufferLen = Base64EncodeLen(data.Length);
            byte[] buffer = new byte[bufferLen];
            var bufferPos = 0;

            UInt32 octet_a;
            UInt32 octet_b;
            UInt32 octet_c;
            int dataPos = 0;
            for (int dataLenMax = data.Length - (data.Length % 3); dataPos < dataLenMax;)
            {
                octet_a = data[dataPos++];
                octet_b = data[dataPos++];
                octet_c = data[dataPos++];

                var triple = (octet_a << 0x10) | (octet_b << 0x08) | octet_c;

                buffer[bufferPos++] = _encodeTable[(triple >> 3 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 2 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 1 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 0 * 6) & 0x3F];
            }

            // last bytes
            if (dataPos < data.Length)
            {
                octet_a = data[dataPos++];
                octet_b = dataPos < data.Length ? data[dataPos++] : 0U;
                octet_c = 0U; // last character is definitely padded

                var triple = (octet_a << 0x10) | (octet_b << 0x08) | octet_c;

                buffer[bufferPos++] = _encodeTable[(triple >> 3 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 2 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 1 * 6) & 0x3F];
                buffer[bufferPos++] = _encodeTable[(triple >> 0 * 6) & 0x3F];

                // add padding '='
                var dataLenMod = data.Length % 3;
                // last character is definitely padded
                buffer[bufferPos - 1] = (byte)'=';
                if (dataLenMod == 1) buffer[bufferPos - 2] = (byte)'=';
            }

            return buffer;
        }

        /// <summary>
        /// Get base64 encode length
        /// </summary>
        /// <param name="dataLen">raw data length</param>
        /// <returns>base64 encode data length</returns>
        private static int Base64EncodeLen(int dataLen)
        {
            return ((dataLen + 2) / 3) * 4;
        }

        private static readonly byte[] _decodeTable = new byte[256]
        {
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
            64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
            64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
        };

        /// <summary>
        /// Get base64 decode
        /// </summary>
        /// <param name="encodeData">base64 encode data</param>
        /// <returns>base64 decode data</returns>
        public static byte[] Base64Decode(byte[] encodeData)
        {
            if (encodeData == null) throw new ArgumentNullException();
            if (encodeData.Length % 4 != 0) throw new InvalidOperationException();

            int encodeDataUseLen;
            var bufferLen = Base64DecodeLen(encodeData, out encodeDataUseLen);
            byte[] buffer = new byte[bufferLen];
            var bufferPos = 0;

            UInt32 octet_a;
            UInt32 octet_b;
            UInt32 octet_c;
            UInt32 octet_d;
            int dataPos = 0;
            for (int dataLenMax = encodeDataUseLen - (encodeDataUseLen % 4); dataPos < dataLenMax;)
            {
                octet_a = _decodeTable[encodeData[dataPos++]];
                octet_b = _decodeTable[encodeData[dataPos++]];
                octet_c = _decodeTable[encodeData[dataPos++]];
                octet_d = _decodeTable[encodeData[dataPos++]];

                var triple = (octet_a << 0x12) | (octet_b << 0x0C) | (octet_c << 0x06) | octet_d;

                buffer[bufferPos++] = (byte)((triple >> 2 * 8) & 0xFF);
                buffer[bufferPos++] = (byte)((triple >> 1 * 8) & 0xFF);
                buffer[bufferPos++] = (byte)(triple & 0xFF);
            }

            var dataSurplus = encodeDataUseLen - dataPos;
            if (dataSurplus == 1) throw new Exception();

            // last 2~3 bytes
            if (dataSurplus > 0)
            {
                octet_a = _decodeTable[encodeData[dataPos++]];
                octet_b = _decodeTable[encodeData[dataPos++]];
                octet_c = dataPos < encodeDataUseLen ? _decodeTable[encodeData[dataPos++]] : 0U;
                octet_d = 0U;

                var triple = (octet_a << 0x12) | (octet_b << 0x0C) | (octet_c << 0x06) | octet_d;
                buffer[bufferPos++] = (byte)((triple >> 2 * 8) & 0xFF);
                if (dataSurplus == 3) buffer[bufferPos++] = (byte)((triple >> 1 * 8) & 0xFF);
            }

            return buffer;
        }

        /// <summary>
        /// Get base64 decode length
        /// </summary>
        /// <param name="encodeData">base64 encode data</param>
        /// <param name="encodeDataUseLen">out: base64 encode max use length</param>
        /// <returns>base64 decode data length</returns>
        private static int Base64DecodeLen(byte[] encodeData, out int encodeDataUseLen)
        {
            int useLen = encodeData.Length;
            for (int i = encodeData.Length - 1; i >= 0; --i)
            {
                if (encodeData[i] == '=')
                {
                    useLen = i;
                }
            }

            encodeDataUseLen = useLen;
            return (((useLen + 3) / 4) * 3) - (encodeData.Length - useLen);
        }
    }
}

 

主要參考:

How do I base64 encode (decode) in C?​
http://www.opensource.apple.com/source/QuickTimeStreamingServer/QuickTimeStreamingServer-452/CommonUtilitiesLib/base64.c
Base64 - 維基百科,自由的百科全書

※在此感謝所有的幫助者,感謝~