00001
00002
00003 #include <sstream>
00004 #include <cassert>
00005 #include "Base64.h"
00006
00007 using namespace Yosokumo;
00008
00009 char Base64::encode64[] =
00010 {
00011 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00012 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
00013 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00014 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00015 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00016 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00017 'w', 'x', 'y', 'z', '0', '1', '2', '3',
00018 '4', '5', '6', '7', '8', '9', '+', '/'
00019 };
00020
00021
00022 void Base64::map3to4(uint8_t A, uint8_t B, uint8_t C, std::string &abcd)
00023 {
00024 unsigned AA = ((unsigned)A) & 0xff;
00025 unsigned BB = ((unsigned)B) & 0xff;
00026 unsigned CC = ((unsigned)C) & 0xff;
00027
00028 char buff[4];
00029
00030 buff[0] = encode64[(AA >> 2) & 0x3f];
00031 buff[1] = encode64[((AA << 4) & 0x3f) | ((BB >> 4) & 0x3f)];
00032 buff[2] = encode64[((BB << 2) & 0x3f) | ((CC >> 6) & 0x3f)];
00033 buff[3] = encode64[CC & 0x3f];
00034
00035 abcd.append(buff, 4);
00036
00037 #if 0
00038 unsigned AA = ((unsigned)A) & 0xff;
00039 unsigned BB = ((unsigned)B) & 0xff;
00040 unsigned CC = ((unsigned)C) & 0xff;
00041
00042 char a, b, c, d;
00043
00044 a = encode64[(AA >> 2) & 0x3f];
00045 b = encode64[((AA << 4) & 0x3f) | ((BB >> 4) & 0x3f)];
00046 c = encode64[((BB << 2) & 0x3f) | ((CC >> 6) & 0x3f)];
00047 d = encode64[CC & 0x3f];
00048
00049 abcd.append(a).append(b).append(c).append(d);
00050 #endif
00051 #if 0
00052
00053 buff[0] = encode64[A >> 2];
00054 buff[1] = encode64[(A << 4) | (B >> 4)];
00055 buff[2] = encode64[(B << 2) | (C >> 6)];
00056 buff[3] = encode64[C];
00057
00058 abcd.append(buff, 4);
00059 #endif
00060 }
00061
00062
00063 void Base64::encodeBytes(const std::vector<uint8_t> &source, std::string &dest)
00064 {
00065 dest.clear();
00066
00067 int n = source.size()/3;
00068 int i, j;
00069
00070 for (i = 0, j = 1; j <= n; ++j, i += 3)
00071 map3to4(source[i], source[i+1], source[i+2], dest);
00072
00073 uint8_t zero = 0;
00074
00075 switch (source.size() % 3)
00076 {
00077 case 1:
00078 map3to4(source[i], zero, zero, dest);
00079 dest.replace(dest.size()-2, 2, "==");
00080 break;
00081
00082 case 2:
00083 map3to4(source[i], source[i+1], zero, dest);
00084 dest.replace(dest.size()-1, 1, "=");
00085 break;
00086 }
00087
00088 }
00089
00090
00091 uint8_t Base64::decode64(char c) throw(std::invalid_argument)
00092 {
00093 uint8_t cc = (uint8_t)c;
00094 int b;
00095
00096 if ('A' <= cc && cc <= 'Z')
00097 b = (int)cc - (int)'A';
00098
00099 else if ('a' <= cc && cc <= 'z')
00100 b = (int)cc - (int)'a' + 26;
00101
00102 else if ('0' <= cc && cc <= '9')
00103 b = (int)cc - (int)'0' + 52;
00104
00105 else if (cc == '+')
00106 b = 62;
00107
00108 else if (cc == '/')
00109 b = 63;
00110
00111 else
00112 {
00113 std::stringstream s;
00114 s << "Base64 string contains invalid character with decimal value "
00115 << (unsigned)cc;
00116 throw std::invalid_argument(s.str());
00117 }
00118
00119 return (uint8_t)b;
00120 }
00121
00122 void Base64::map4to3(
00123 char a, char b, char c, char d,
00124 std::vector<uint8_t> &ABC, int j,
00125 int n) throw(std::invalid_argument)
00126 {
00127 int aa = decode64(a);
00128 int bb = decode64(b);
00129 int cc = decode64(c);
00130 int dd = decode64(d);
00131
00132 uint8_t A = (uint8_t)((aa << 2) | (bb >> 4));
00133 uint8_t B = (uint8_t)((bb << 4) | (cc >> 2));
00134 uint8_t C = (uint8_t)((cc << 6) | dd);
00135
00136 ABC[j] = A;
00137 --n;
00138 if (n-- > 0)
00139 ABC[j+1] = B;
00140 if (n > 0)
00141 ABC[j+2] = C;
00142 }
00143
00144
00145
00146 static bool ends_with(const std::string &s, const std::string &ending)
00147 {
00148 if (ending.size() > s.size())
00149 return false;
00150
00151 return s.compare(s.size()-ending.size(), ending.size(), ending) == 0;
00152 }
00153
00154 void Base64::decodeString(
00155 const std::string &source,
00156 std::vector<uint8_t> &dest) throw(std::invalid_argument)
00157 {
00158 int m = source.size();
00159
00160 if (m % 4 != 0)
00161 {
00162 std::stringstream s;
00163 s << "Base64 string length " << m << "is not a multiple of 4";
00164 throw std::invalid_argument(s.str());
00165 }
00166
00167 int resultLen = (m/4) * 3;
00168
00169 if (ends_with(source, "=="))
00170 {
00171 resultLen -= 2;
00172 m -= 2;
00173 }
00174 else if (ends_with(source, "="))
00175 {
00176 --resultLen;
00177 --m;
00178 }
00179
00180
00181
00182
00183 dest.resize(resultLen, 0);
00184
00185 int n = m / 4;
00186 int i, j, k = 0;
00187
00188 for (i = 0, j = 1; j <= n; ++j, i += 4, k += 3)
00189 map4to3(source[i], source[i+1], source[i+2], source[i+3], dest, k, 3);
00190
00191 switch (m % 4)
00192 {
00193 case 1:
00194 assert(false);
00195 break;
00196
00197 case 2:
00198 map4to3(source[i], source[i+1], 'A', 'A', dest, k, 1);
00199 break;
00200
00201 case 3:
00202 map4to3(source[i], source[i+1], source[i+2], 'A', dest, k, 2);
00203 break;
00204 }
00205
00206 }
00207
00208