194 lines
4.7 KiB
C
194 lines
4.7 KiB
C
#include "base64.h"
|
|
|
|
// 63rd char used for Base64 code
|
|
#define CHAR_63 '*'
|
|
|
|
// 64th char used for Base64 code
|
|
#define CHAR_64 '-'
|
|
|
|
// Char used for padding
|
|
#define CHAR_PAD '='
|
|
|
|
// Encodes binary data to Base64 code
|
|
// Returns size of encoded data.
|
|
int Base64_Encode(const char* inData,
|
|
int dataLength,
|
|
char* out)
|
|
{
|
|
// charachers used by Base64
|
|
static const char alph[] =
|
|
{
|
|
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
|
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
|
|
'0','1','2','3','4','5','6','7','8','9',CHAR_63,CHAR_64
|
|
};
|
|
|
|
// mask - first six bits
|
|
const int mask = 0x3F;
|
|
int i, j, left;
|
|
|
|
// used as temp 24-bits buffer
|
|
union
|
|
{
|
|
unsigned char bytes[ 4 ];
|
|
unsigned int block;
|
|
} buffer;
|
|
|
|
// coversation is done by taking three bytes at time of input data int temp
|
|
// then four six-bits values are extracted, converted to base64 characters
|
|
// and at the end they are written to output buffer
|
|
for(i = 0, j = 0, left = dataLength; i < dataLength; i += 3, j += 4, left -= 3 )
|
|
{
|
|
//------------------------
|
|
// filling temp buffer
|
|
|
|
// get first byte and puts it at MSB position in temp buffer
|
|
buffer.bytes[ 2 ] = inData[ i ];
|
|
|
|
// more data left?
|
|
if( left > 1 )
|
|
{
|
|
// get second byte and puts it at middle position in temp buffer
|
|
buffer.bytes[ 1 ] = inData[ i + 1 ];
|
|
// more data left?
|
|
if( left > 2 )
|
|
// get third byte and puts it at LSB position in temp buffer
|
|
buffer.bytes[ 0 ] = inData[ i + 2 ];
|
|
else
|
|
// zero-padding of input data (last bytes)
|
|
buffer.bytes[ 0 ] = 0;
|
|
}
|
|
else
|
|
{
|
|
// zero-padding of input data (last two bytes)
|
|
buffer.bytes[ 1 ] = 0;
|
|
buffer.bytes[ 0 ] = 0;
|
|
}
|
|
|
|
//------------------------
|
|
// constructing code from temp buffer
|
|
// and putting it in output buffer
|
|
|
|
// extract first and second six-bit value from temp buffer
|
|
// and convert is to base64 character
|
|
out[ j ] = alph[ ( buffer.block >> 18 ) & mask ];
|
|
out[ j + 1 ] = alph[ ( buffer.block >> 12 ) & mask ];
|
|
// more data left?
|
|
if( left > 1 )
|
|
{
|
|
// extract third six-bit value from temp buffer
|
|
// and convert it to base64 character
|
|
out[ j + 2 ] = alph[ ( buffer.block >> 6 ) & mask ];
|
|
// more data left?
|
|
if( left > 2 )
|
|
// extract forth six-bit value from temp buffer
|
|
// and convert it to base64 character
|
|
out[ j + 3 ] = alph[ buffer.block & mask ];
|
|
else
|
|
// pad output code
|
|
out[ j + 3 ] = CHAR_PAD;
|
|
}
|
|
else
|
|
{
|
|
// pad output code
|
|
out[ j + 2 ] = CHAR_PAD;
|
|
out[ j + 3 ] = CHAR_PAD;
|
|
}
|
|
}
|
|
|
|
out[j] = 0;
|
|
return j;
|
|
}
|
|
|
|
// Decodes Base64 code to binary data
|
|
// Returns size of decoded data.
|
|
int Base64_Decode(const char* inCode,
|
|
int codeLength,
|
|
char* outData)
|
|
{
|
|
// number of decoded bytes
|
|
int j = 0;
|
|
int i;
|
|
|
|
// used as temp 24-bits buffer
|
|
union
|
|
{
|
|
unsigned char bytes[ 4 ];
|
|
unsigned int block;
|
|
} buffer;
|
|
buffer.block = 0;
|
|
|
|
for( i = 0; i < codeLength; i++ )
|
|
{
|
|
// position in temp buffer
|
|
int m = i % 4;
|
|
|
|
char x = inCode[ i ];
|
|
int val = 0;
|
|
|
|
// converts base64 character to six-bit value
|
|
if( x >= 'A' && x <= 'Z' )
|
|
val = x - 'A';
|
|
else if( x >= 'a' && x <= 'z' )
|
|
val = x - 'a' + 'Z' - 'A' + 1;
|
|
else if( x >= '0' && x <= '9' )
|
|
val = x - '0' + ( 'Z' - 'A' + 1 ) * 2;
|
|
else if( x == CHAR_63 )
|
|
val = 62;
|
|
else if( x == CHAR_64 )
|
|
val = 63;
|
|
|
|
// padding chars are not decoded and written to output buffer
|
|
if( x != CHAR_PAD )
|
|
buffer.block |= val << ( 3 - m ) * 6;
|
|
else
|
|
m--;
|
|
|
|
// temp buffer is full or end of code is reached
|
|
// flushing temp buffer
|
|
if( m == 3 || x == CHAR_PAD )
|
|
{
|
|
// writes byte from temp buffer (combined from two six-bit values) to output buffer
|
|
outData[ j++ ] = buffer.bytes[ 2 ];
|
|
// more data left?
|
|
if( x != CHAR_PAD || m > 1 )
|
|
{
|
|
// writes byte from temp buffer (combined from two six-bit values) to output buffer
|
|
outData[ j++ ] = buffer.bytes[ 1 ];
|
|
// more data left?
|
|
if( x != CHAR_PAD || m > 2 )
|
|
// writes byte from temp buffer (combined from two six-bit values) to output buffer
|
|
outData[ j++ ] = buffer.bytes[ 0 ];
|
|
}
|
|
|
|
// restarts temp buffer
|
|
buffer.block = 0;
|
|
}
|
|
|
|
// when padding char is reached it is the end of code
|
|
if( x == CHAR_PAD )
|
|
break;
|
|
}
|
|
|
|
outData[j] = 0;
|
|
return j;
|
|
}
|
|
|
|
// Returns maximum size of decoded data based on size of Base64 code.
|
|
int Base64_GetDataLength(int codeLength)
|
|
{
|
|
return codeLength - codeLength / 4 + 2;
|
|
}
|
|
|
|
// Returns maximum length of Base64 code based on size of uncoded data.
|
|
int Base64_GetCodeLength(int dataLength)
|
|
{
|
|
int len = dataLength + dataLength / 3 + (int)( dataLength % 3 != 0 );
|
|
|
|
// output code size must be multiple of 4 bytes
|
|
if( len % 4 )
|
|
len += 4 - len % 4;
|
|
|
|
return len + 2;
|
|
}
|