diff options
| author | Remko Tronçon <git@el-tramo.be> | 2013-04-26 18:04:37 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2013-04-26 18:04:37 (GMT) | 
| commit | aa131405927fc7f597ed06aff71abb0a30b59926 (patch) | |
| tree | 4289d7dc61a0f19efad3434b155e29d3843b4461 | |
| parent | 7ef27db79a528263b17610444f4f85bafd0fa6fa (diff) | |
| download | swift-aa131405927fc7f597ed06aff71abb0a30b59926.zip swift-aa131405927fc7f597ed06aff71abb0a30b59926.tar.bz2 | |
Replace third-party Base64 by our own algorithm.
Change-Id: I48037fbc475c84f55dd74054bceb187a4798244a
| -rw-r--r-- | Swiften/StringCodecs/Base64.cpp | 179 | ||||
| -rw-r--r-- | Swiften/StringCodecs/UnitTest/Base64Test.cpp | 42 | 
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); | 
 Swift
 Swift