summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/StringCodecs/Base64.cpp179
-rw-r--r--Swiften/StringCodecs/UnitTest/Base64Test.cpp42
2 files changed, 107 insertions, 114 deletions
diff --git a/Swiften/StringCodecs/Base64.cpp b/Swiften/StringCodecs/Base64.cpp
index 76e2833..1b039ac 100644
--- a/Swiften/StringCodecs/Base64.cpp
+++ b/Swiften/StringCodecs/Base64.cpp
@@ -1,121 +1,100 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-// Code copied & adapted from LibTomCrypt by Tom St Denis
-
-#include <boost/numeric/conversion/cast.hpp>
-
-#include <algorithm>
-
#include <Swiften/StringCodecs/Base64.h>
-#include <Swiften/Base/Algorithm.h>
-#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wconversion"
-
-static const char *codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+using namespace Swift;
namespace {
- template<typename TargetType, typename SourceType>
- TargetType base64Encode(const SourceType& in) {
- TargetType out;
+ const char* encodeMap =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const unsigned char decodeMap[255] = {
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 255, 255, 255, 255, 255, 255,
+ 255, 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, 255, 255, 255, 255, 255,
+ 255, 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, 255, 255, 255, 255, 255
+ };
+
+ template<typename ResultType, typename InputType>
+ ResultType encodeDetail(const InputType& input) {
+ ResultType result;
+ size_t i = 0;
+ for (; i < (input.size()/3)*3; i += 3) {
+ unsigned int c = input[i+2] | (input[i+1]<<8) | (input[i]<<16);
+ result.push_back(encodeMap[(c&0xFC0000)>>18]);
+ result.push_back(encodeMap[(c&0x3F000)>>12]);
+ result.push_back(encodeMap[(c&0xFC0)>>6]);
+ result.push_back(encodeMap[c&0x3F]);
+ }
+ if (input.size() % 3 == 2) {
+ unsigned int c = (input[i+1]<<8) | (input[i]<<16);
+ result.push_back(encodeMap[(c&0xFC0000)>>18]);
+ result.push_back(encodeMap[(c&0x3F000)>>12]);
+ result.push_back(encodeMap[(c&0xFC0)>>6]);
+ result.push_back('=');
+ }
+ else if (input.size() % 3 == 1) {
+ unsigned int c = input[i]<<16;
+ result.push_back(encodeMap[(c&0xFC0000)>>18]);
+ result.push_back(encodeMap[(c&0x3F000)>>12]);
+ result.push_back('=');
+ result.push_back('=');
+ }
+ return result;
+ }
+}
- size_t i;
- unsigned int leven = 3*(in.size() / 3);
- for (i = 0; i < leven; i += 3) {
- out.push_back(codes[(in[i] >> 2) & 0x3F]);
- out.push_back(codes[(((in[i] & 3) << 4) + (in[i+1] >> 4)) & 0x3F]);
- out.push_back(codes[(((in[i+1] & 0xf) << 2) + (in[i+2] >> 6)) & 0x3F]);
- out.push_back(codes[in[i+2] & 0x3F]);
- }
- if (i < in.size()) {
- unsigned int a = in[i];
- unsigned int b = (i+1 < in.size()) ? in[i+1] : 0;
- out.push_back(codes[(a >> 2) & 0x3F]);
- out.push_back(codes[(((a & 3) << 4) + (b >> 4)) & 0x3F]);
- out.push_back((i+1 < in.size()) ? codes[(((b & 0xf) << 2)) & 0x3F] : '=');
- out.push_back('=');
- }
- return out;
- }
+std::string Base64::encode(const ByteArray& s) {
+ return encodeDetail<std::string>(s);
}
-static const unsigned char map[256] = {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
- 255, 254, 255, 255, 255, 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, 255, 255, 255, 255, 255,
- 255, 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, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255 };
-
-namespace Swift {
- std::string Base64::encode(const ByteArray &s) {
- return base64Encode<std::string, ByteArray>(s);
- }
+SafeByteArray Base64::encode(const SafeByteArray& s) {
+ return encodeDetail<SafeByteArray>(s);
+}
- SafeByteArray Base64::encode(const SafeByteArray &s) {
- return base64Encode<SafeByteArray, SafeByteArray>(s);
+ByteArray Base64::decode(const std::string& input) {
+ ByteArray result;
+ if (input.size() % 4) {
+ return ByteArray();
}
-
- ByteArray Base64::decode(const std::string& input) {
- std::string inputWithoutNewlines(input);
- erase(inputWithoutNewlines, '\n');
-
- const std::string& s = inputWithoutNewlines;
- ByteArray out;
-
- int g = 3;
- size_t y, t;
- for (size_t x = y = t = 0; x < s.size(); ++x) {
- unsigned char c = map[s[x]&0xFF];
- if (c == 255) {
- continue;
- }
- /* the final = symbols are read and used to trim the remaining bytes */
- if (c == 254) {
- c = 0;
- /* prevent g < 0 which would potentially allow an overflow later */
- if (--g < 0) {
- return ByteArray();
- }
- } else if (g != 3) {
- /* we only allow = to be at the end */
- return ByteArray();
- }
-
- t = (t<<6)|c;
-
- if (++y == 4) {
- out.push_back((unsigned char)((t>>16)&255));
- if (g > 1) out.push_back((unsigned char)((t>>8)&255));
- if (g > 2) out.push_back((unsigned char)(t&255));
- y = t = 0;
- }
+ for (size_t i = 0; i < input.size(); i += 4) {
+ unsigned char c1 = input[i+0];
+ unsigned char c2 = input[i+1];
+ unsigned char c3 = input[i+2];
+ unsigned char c4 = input[i+3];
+ if (c3 == '=') {
+ unsigned int c = (((decodeMap[c1]<<6)|decodeMap[c2])&0xFF0)>>4;
+ result.push_back(c);
+ }
+ else if (c4 == '=') {
+ unsigned int c = (((decodeMap[c1]<<12)|(decodeMap[c2]<<6)|decodeMap[c3])&0x3FFFC)>>2;
+ result.push_back((c&0xFF00) >> 8);
+ result.push_back(c&0xFF);
}
- if (y != 0) {
- return ByteArray();
+ else {
+ unsigned int c = (decodeMap[c1]<<18) | (decodeMap[c2]<<12) | (decodeMap[c3]<<6) | decodeMap[c4];
+ result.push_back((c&0xFF0000) >> 16);
+ result.push_back((c&0xFF00) >> 8);
+ result.push_back(c&0xFF);
}
- return out;
}
+ return result;
}
diff --git a/Swiften/StringCodecs/UnitTest/Base64Test.cpp b/Swiften/StringCodecs/UnitTest/Base64Test.cpp
index f6a424b..4005047 100644
--- a/Swiften/StringCodecs/UnitTest/Base64Test.cpp
+++ b/Swiften/StringCodecs/UnitTest/Base64Test.cpp
@@ -16,22 +16,41 @@ using namespace Swift;
class Base64Test : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(Base64Test);
- CPPUNIT_TEST(testEncode);
- CPPUNIT_TEST(testEncode_NonAscii);
+ CPPUNIT_TEST(testEncodeDecodeAllChars);
+ CPPUNIT_TEST(testEncodeDecodeOneBytePadding);
+ CPPUNIT_TEST(testEncodeDecodeTwoBytesPadding);
CPPUNIT_TEST(testEncode_NoData);
- CPPUNIT_TEST(testDecode);
CPPUNIT_TEST(testDecode_NoData);
CPPUNIT_TEST_SUITE_END();
public:
- void testEncode() {
- std::string result(Base64::encode(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")));
- CPPUNIT_ASSERT_EQUAL(std::string("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="), result);
+ void testEncodeDecodeAllChars() {
+ ByteArray input;
+ for (unsigned char i = 0; i < 255; ++i) {
+ input.push_back(i);
+ }
+ std::string result(Base64::encode(input));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+"), result);
+ CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result));
}
- void testEncode_NonAscii() {
- std::string result(Base64::encode(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed")));
- CPPUNIT_ASSERT_EQUAL(std::string("QgayPKawpkPSDYmwT/WM94uAlu0="), result);
+ void testEncodeDecodeOneBytePadding() {
+ ByteArray input = createByteArray("ABCDE", 5);
+
+ std::string result = Base64::encode(input);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("QUJDREU="), result);
+ CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result));
+ }
+
+ void testEncodeDecodeTwoBytesPadding() {
+ ByteArray input = createByteArray("ABCD", 4);
+
+ std::string result = Base64::encode(input);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("QUJDRA=="), result);
+ CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result));
}
void testEncode_NoData() {
@@ -39,11 +58,6 @@ class Base64Test : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(std::string(""), result);
}
- void testDecode() {
- ByteArray result(Base64::decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="));
- CPPUNIT_ASSERT_EQUAL(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), result);
- }
-
void testDecode_NoData() {
ByteArray result(Base64::decode(""));
CPPUNIT_ASSERT_EQUAL(ByteArray(), result);