toys/simple-http-server-c/source/base64.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;
}