概要
本記事ではbase64のエンコードの流れを記載。
最後の方にあるC#コードは、何かの参考になればと載せているだけなので、きちんと動くかはまた微妙。
base64のエンコードの流れ
base64のエンコードの流れは以下の通り。
- 元の文字列(abcd)をバイト型に変換
- バイト型から2進数に変換し、8桁になるように前0を埋め、すべて結合
- 2進数を6文字ごとに区切り、6文字になるように後ろに0を埋める
- 専用の変換表から、2進数を文字列に変換する
- 文字列の長さが4の倍数になるように、後ろに=を詰める
図にすると以下の通り。
画像クリックで等倍
次からはC#コードを載せています。流れが分かりやすいように冗長的に書いています。テキトーにコピペしてみてもある程度動くと思います。
1.元の文字列(abcd)をバイト型に変換
/**
* 1.元の文字列(abcd)をバイト型に変換
* (abcd)
* -> (0x61, 0x62, 0x63, 0x64)
*/
// 元の文字列をバイト型に変換
Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(pTxt);
2.バイト型から2進数に変換し、8桁になるように前0を埋め、すべて結合
/**
* 2.バイト型から2進数に変換し、8桁になるように前0を埋め、すべて結合
* (0x61, 0x62, 0x63)
* -> (1100001, 1100010, 1100011, 1100100)
* -> (01100001, 01100010, 01100011, 01100100)
* -> (01100001011000100110001101100100)
*/
String unionBinaryNumTxt = "";
foreach (Byte b in bytes)
{
// バイト型から2進数に変換
String binaryNumTxt = Convert.ToString(b, 2);
// 8桁になるように前0を埋める
String paddingBinaryNumTxt = binaryNumTxt.PadLeft(8, '0');
// 結合
unionBinaryNumTxt += paddingBinaryNumTxt;
}
3.2進数を6文字ごとに区切り、6文字になるように後ろに0を埋める
/**
* 3.2進数を6文字ごとに区切り、6文字になるように後ろに0を埋める
* (01100001011000100110001101100100)
* -> (011000, 010110, 001001, 100011, 011001, 00)
* -> (011000, 010110, 001001, 100011, 011001, 000000)
*/
int splitNumber = 6;
List split6TxtList = new List();
for(int i = 0;true;i++)
{
if (unionBinaryNumTxt.Length <= i * splitNumber) // 最後まで区切ったら終了
{
break;
}
// 2進数を6文字ごとに区切る
String split6Txt = "";
if (unionBinaryNumTxt.Length < (i + 1) * splitNumber)
{
split6Txt = unionBinaryNumTxt.Substring(i * splitNumber, unionBinaryNumTxt.Length % splitNumber);
} else {
split6Txt = unionBinaryNumTxt.Substring(i * splitNumber, splitNumber);
}
// 6文字になるように後ろに0を埋める
String paddingSplit6Txt = split6Txt.PadRight(splitNumber, '0');
split6TxtList.Add(paddingSplit6Txt);
}
4.専用の変換表から、2進数を文字列に変換する
/**
* 4.専用の変換表から、2進数を文字列に変換する
* (011000, 010110, 001001, 100011, 011001, 000000)
* -> (Y, W, J, j, Z, A)
* -> (YWJjZA)
*/
// 専用の変換表を定義
IDictionary cTable = new Dictionary()
{
{"000000", "A"},
{"000001", "B"},
{"000010", "C"},
{"000011", "D"},
{"000100", "E"},
{"000101", "F"},
{"000110", "G"},
{"000111", "H"},
{"001000", "I"},
{"001001", "J"},
{"001010", "K"},
{"001011", "L"},
{"001100", "M"},
{"001101", "N"},
{"001110", "O"},
{"001111", "P"},
{"010000", "Q"},
{"010001", "R"},
{"010010", "S"},
{"010011", "T"},
{"010100", "U"},
{"010101", "V"},
{"010110", "W"},
{"010111", "X"},
{"011000", "Y"},
{"011001", "Z"},
{"011010", "a"},
{"011011", "b"},
{"011100", "c"},
{"011101", "d"},
{"011110", "e"},
{"011111", "f"},
{"100000", "g"},
{"100001", "h"},
{"100010", "i"},
{"100011", "j"},
{"100100", "k"},
{"100101", "l"},
{"100110", "m"},
{"100111", "n"},
{"101000", "o"},
{"101001", "p"},
{"101010", "q"},
{"101011", "r"},
{"101100", "s"},
{"101101", "t"},
{"101110", "u"},
{"101111", "v"},
{"110000", "w"},
{"110001", "x"},
{"110010", "y"},
{"110011", "z"},
{"110100", "0"},
{"110101", "1"},
{"110110", "2"},
{"110111", "3"},
{"111000", "4"},
{"111001", "5"},
{"111010", "6"},
{"111011", "7"},
{"111100", "8"},
{"111101", "9"},
{"111110", "+"},
{"111111", "/"}
};
// 2進数を文字列に変換する
String base64Txt = "";
foreach (String split6Txt in split6TxtList) {
base64Txt += cTable[split6Txt];
}
5.文字列の長さが4の倍数になるように、後ろに=を詰める
/**
* 5.文字列の長さが4の倍数になるように、後ろに=を詰める
* (YWJjZA)
* -> (YWJjZA==)
*/
String paddingBase64Txt = base64Txt;
if (base64Txt.Length % 4 != 0)
{
paddingBase64Txt = base64Txt.PadRight(base64Txt.Length + (4 - base64Txt.Length % 4), '=');
}