add base64 encoder/decoder to bytevector

This commit is contained in:
Sander Jansen
2015-05-16 14:06:49 -05:00
parent ec8e611909
commit 7bbf5a2e79
3 changed files with 145 additions and 0 deletions

View File

@ -950,6 +950,98 @@ ByteVector ByteVector::toHex() const
return encoded;
}
ByteVector & ByteVector::fromBase64()
{
static const unsigned char base64[256]={
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x3e,0x80,0x80,0x80,0x3f,
0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x80,0x80,0x80,0xff,0x80,0x80,
0x80,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x80,0x80,0x80,0x80,0x80,
0x80,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
};
detach();
uint len = size();
const unsigned char * src = (unsigned char*) data();
unsigned char * dst = (unsigned char*) data();
while(4<=len) {
if(base64[src[0]]==0x80) break;
if(base64[src[1]]==0x80) break;
if(base64[src[2]]==0x80) break;
if(base64[src[3]]==0x80) break;
*dst++=((base64[src[0]]<<2)&0xfc)|((base64[src[1]]>>4)&0x03);
if(src[2]!='=') {
*dst++=((base64[src[1]]&0x0f)<<4)|((base64[src[2]]>>2)&0x0f);
if(src[3]!='=') {
*dst++=((base64[src[2]]&0x03)<<6)|(base64[src[3]]&0x3f);
}
else {
break;
}
}
else {
break;
}
src+=4;
len-=4;
}
resize(dst-(unsigned char*)data());
return *this;
}
ByteVector ByteVector::toBase64() const
{
static const char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (size()) {
uint len=size();
ByteVector output(4 * ((len-1)/3+1)); // note roundup
const char * src = data();
char * dst = output.data();
while(3<=len) {
*dst++=alphabet[(src[0]>>2)&0x3f];
*dst++=alphabet[((src[0]&0x03)<<4)|((src[1]>>4)&0x0f)];
*dst++=alphabet[((src[1]&0x0f)<<2)|((src[2]>>6)&0x03)];
*dst++=alphabet[src[2]&0x3f];
src+=3;
len-=3;
}
if(len) {
*dst++=alphabet[(src[0]>>2)&0x3f];
if(len>1) {
*dst++=alphabet[((src[0]&0x03)<<4)|((src[1]>>4)&0x0f)];
*dst++=alphabet[((src[1]&0x0f)<<2)];
}
else {
*dst++=alphabet[(src[0]&0x03)<<4];
*dst++='=';
}
*dst++='=';
}
return output;
}
return ByteVector();
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

View File

@ -573,6 +573,19 @@ namespace TagLib {
*/
ByteVector toHex() const;
/*!
* Returns a base64 encoded copy of the byte vector
*/
ByteVector toBase64() const;
/*!
* Decodes the base64 encoded byte vector in-memory. Returns a reference
* to this vector. Calls detach before decoding.
*/
ByteVector & fromBase64();
protected:
/*
* If this ByteVector is being shared via implicit sharing, do a deep copy

View File

@ -43,6 +43,7 @@ class TestByteVector : public CppUnit::TestFixture
CPPUNIT_TEST(testReplace);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testResize);
CPPUNIT_TEST(testBase64);
CPPUNIT_TEST_SUITE_END();
public:
@ -379,6 +380,45 @@ public:
CPPUNIT_ASSERT_EQUAL(-1, c.find('C'));
}
void testBase64()
{
ByteVector sempty;
ByteVector t0("a"); // test 1 byte
ByteVector t1("any carnal pleasure.");
ByteVector t2("any carnal pleasure");
ByteVector t3("any carnal pleasur");
ByteVector s0("a"); // test 1 byte
ByteVector s1("any carnal pleasure.");
ByteVector s2("any carnal pleasure");
ByteVector s3("any carnal pleasur");
ByteVector eempty;
ByteVector e0("YQ==");
ByteVector e1("YW55IGNhcm5hbCBwbGVhc3VyZS4=");
ByteVector e2("YW55IGNhcm5hbCBwbGVhc3VyZQ==");
ByteVector e3("YW55IGNhcm5hbCBwbGVhc3Vy");
// Encode
CPPUNIT_ASSERT_EQUAL(eempty, sempty.toBase64());
CPPUNIT_ASSERT_EQUAL(e0, s0.toBase64());
CPPUNIT_ASSERT_EQUAL(e1, s1.toBase64());
CPPUNIT_ASSERT_EQUAL(e2, s2.toBase64());
CPPUNIT_ASSERT_EQUAL(e3, s3.toBase64());
// Decode
CPPUNIT_ASSERT_EQUAL(sempty, eempty.toBase64());
CPPUNIT_ASSERT_EQUAL(s0, e0.fromBase64());
CPPUNIT_ASSERT_EQUAL(s1, e1.fromBase64());
CPPUNIT_ASSERT_EQUAL(s2, e2.fromBase64());
CPPUNIT_ASSERT_EQUAL(s3, e3.fromBase64());
CPPUNIT_ASSERT_EQUAL(t0, s0.toBase64().fromBase64());
CPPUNIT_ASSERT_EQUAL(t1, s1.toBase64().fromBase64());
CPPUNIT_ASSERT_EQUAL(t2, s2.toBase64().fromBase64());
CPPUNIT_ASSERT_EQUAL(t3, s3.toBase64().fromBase64());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector);