Decode a string from base64 encoding to ascii. The char * returned must be free'd after use. len is a return pointer with the length of the string returned.
char to_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char* b64dec(const char* string, int *len)
{
/* return a decoded memchunk, or a null pointer in case of failure */
int rc = 0;
char *data = NULL;
int count = 0, rem = 0;
int i, vrfy;
int qw = 0, tw = 0;
int length;
const char *tmp;
int skip;
char ch;
char bits;
if (!string)
return NULL;
if (len <= 0)
return NULL;
if (string)
{
length = strlen(string);
/* do a format verification first */
if (length > 0)
{
tmp = string;
while (length > 0)
{
skip = strspn(tmp, to_b64);
count += skip;
length -= skip;
tmp += skip;
if (length > 0)
{
vrfy = strcspn(tmp, to_b64);
for (i = 0; i < vrfy; i++)
{
if (isspace(tmp[i]))
continue;
if (tmp[i] == '=')
{
/* we should check if we're close to the end of the string */
rem = count % 4;
/* rem must be either 2 or 3, otherwise no '=' should be here */
if (rem < 2)
return 0;
/* end-of-message recognized */
break;
}
else
{
/* Transmission error; RFC tells us to ignore this, but:
* - the rest of the message is going to even more corrupt since we're sliding bits out of place
* If a message is corrupt, it should be dropped. Period.
*/
return 0;
}
}
length -= vrfy;
tmp += vrfy;
} //end of while loop
}
rc = ((count / 4) * 3 + (rem ? (rem - 1) : 0));
if (rc)
{
if (count > 0)
{
qw = 0;
tw = 0;
data = (char *)malloc(rc + 1);
memset(data, '\0', rc + 1);
length = strlen(tmp = string);
for (i = 0; i < length; i++)
{
ch = string[i];
//char bits;
if (isspace(ch))
continue;
bits = 0;
if ((ch >= 'A') && (ch <= 'Z'))
{
bits = (unsigned char)(ch - 'A');
}
else if ((ch >= 'a') && (ch <= 'z'))
{
bits = (unsigned char)(ch - 'a' + 26);
}
else if ((ch >= '0') && (ch <= '9'))
{
bits = (unsigned char)(ch - '0' + 52);
}
else if ( ch == '+')
{
bits = (unsigned char) 62;
}
else if ( ch == '/')
{
bits = (unsigned char) 63;
}
else if (ch == '=')
{
break;
}
else
{
bits = (unsigned char) 'y';
}
switch (qw++)
{
case 0:
data[tw+0] = (bits << 2) & 0xfc;
*len = tw;
break;
case 1:
data[tw+0] |= (bits >> 4) & 0x03;
data[tw+1] = (bits << 4) & 0xf0;
*len = tw + 1;
break;
case 2:
data[tw+1] |= (bits >> 2) & 0x0f;
data[tw+2] = (bits << 6) & 0xc0;
*len = tw + 2;
break;
case 3:
data[tw+2] |= bits & 0x3f;
*len = tw + 2;
break;
}
if (qw == 4)
{
qw = 0;
tw += 3;
*len = tw;
}
} //end if for loop
}
}
}
}
return data;
}