#### 4.5.1 Problem

You want to represent binary data in as
compact a textual representation as is reasonable, but the data must
be easy to encode and decode, and it must use printable text
characters.

#### 4.5.2 Solution

Base64 encoding encodes six bits of
data at a time, meaning that every six bits of input map to one
character of output. The characters in the output will be a numeric
digit, a letter (uppercase or lowercase), a forward slash, a plus, or
the equal sign (which is a special padding character).

Note that four output characters map exactly to three input
characters. As a result, if the input string isn't a
multiple of three characters, you'll need to do some
padding (explained in
Section 4.5.3).

#### 4.5.3 Discussion

The base64 alphabet takes 6-bit binary values representing numbers
from 0 to 63 and maps them to a set of printable
ASCII characters. The values 0 through 25
map to the uppercase letters in order. The values 26 through 51 map
to the lowercase letters. Then come the decimal digits from 0 to 9,
and finally + and /.

If the length of the input string isn't a multiple
of three bytes, the leftover bits are padded to a multiple of six
with zeros; then the last character is encoded. If only one byte
would have been needed in the input to make it a multiple of three,
the pad character (=) is added to the end of the string.
Otherwise, two pad characters are added.

#include <stdlib.h>
static char b64table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Accepts a binary buffer with an associated size.
* Returns a base64 encoded, NULL-terminated string.
*/
unsigned char *spc_base64_encode(unsigned char *input, size_t len, int wrap) {
unsigned char *output, *p;
size_t i = 0, mod = len % 3, toalloc;
toalloc = (len / 3) * 4 + (3 - mod) % 3 + 1;
if (wrap) {
toalloc += len / 57;
if (len % 57) toalloc++;
}
p = output = (unsigned char *)malloc(((len / 3) + (mod ? 1 : 0)) * 4 + 1);
if (!p) return 0;
while (i < len - mod) {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
*p++ = b64table[((input[i] << 2) | (input[i + 1] >> 6)) & 0x3f];
*p++ = b64table[input[i + 1] & 0x3f];
i += 2;
if (wrap && !(i % 57)) *p++ = '\n';
}
if (!mod) {
if (wrap && i % 57) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
if (mod = = 1) {
*p++ = '=';
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[(input[i] << 2) & 0x3f];
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
}
}
}

The
public interface to
the above code is the following:

unsigned char *spc base64_encode(unsigned char *input, size_t len, int wrap);

The result is a `NULL`-terminated string allocated
internally via `malloc( )`. Some protocols may
expect you to "wrap" base64-encoded
data so that, when printed, it takes up less than 80 columns. If such
behavior is necessary, you can pass in a non-zero value for the final
parameter, which will cause this code to insert newlines once every
76 characters. In that case, the string will always end with a
newline (followed by the expected
`NULL`-terminator).

If the call to `malloc( )` fails because there is no
memory, this function returns 0.

#### 4.5.4 See Also

Recipe 4.6