Skip to content

Instantly share code, notes, and snippets.

@kballenegger
Created March 12, 2013 07:28
Show Gist options
  • Select an option

  • Save kballenegger/5140933 to your computer and use it in GitHub Desktop.

Select an option

Save kballenegger/5140933 to your computer and use it in GitHub Desktop.
Base 64 encoding / decoding routines written in C.
// out must be cb_b642bytes_outsize(sizeof(in)-1) aka cb_b642bytes_outsize(strlen(in))
// returns length of out, (which *may* be zero-padded) if return val > cb_b642bytes_outsize
static inline int cb_b642bytes_outsize(int insize) { return ((insize-insize%4)+(insize%4==0?0:4))/4*3; }
int cb_b642bytes(unsigned char *out, const char *in);
// out must be cb_bytes2b64_outsize(sizeof(in))
// returns null-terminated string
static inline int cb_bytes2b64_outsize(int insize) { return ((insize-insize%3)+(insize%3==0?0:3))/3*4+1; }
void cb_bytes2b64(char *out, const unsigned char *in, int in_length);
static const unsigned char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int cb_b642bytes(unsigned char *out, const char *in) {
// technically, the string should be =-padded, but it'll still work if it isn't :)
unsigned char *write = out;
int in_len = strlen(in);
int i = 0; int last_i = 0;
char tuple[4] = {0,0,0,0};
for (int c = 0; c < in_len; c++) {
if (c < in_len) {
char index = 0;
for (; index < sizeof(base64_table)-1+1; index++) {
if (base64_table[index] == in[c]) break;
}
if (index >= sizeof(base64_table)-1) continue; // out of bounds
// we've found a good character, and index contains its numerical value
tuple[i++%4] = index;
}
// every tuple
if (i > last_i && (i%4 == 0 || c+2>=in_len)) {
last_i = i;
// inverse conversion
for (int j = 0; j < (i%4==0 ? 4 : i%4); j++) {
switch (j) {
case 1: {
*(write++) = (tuple[0] << 2) | (tuple[1] >> 4);
} break;
case 2: {
*(write++) = (tuple[1] << 4) | (tuple[2] >> 2);
} break;
case 3: {
*(write++) = (tuple[2] << 6) | tuple[3];
} break;
default: break;
}
}
}
}
// fill remainder of buffer with zeros. unnecessary but safer and cheap
// for (unsigned char *to_zero = write; to_zero < out + cb_bytes2b64_outsize(in_len); to_zero++) {
// *to_zero = 0;
// }
return write - out;
}
void cb_bytes2b64(char *out, const unsigned char *in, int in_length) {
int mod = in_length % 3;
for (int i = 0; i < in_length; i+=3) {
int last = in_length-i <= 3;
unsigned char in_word[3] = {0,0,0};
memcpy(&in_word, in+i, last ? sizeof(in_word) - (3-mod)%3 : sizeof(in_word));
// in ab ef gh
// out e f g h
*(out++) = base64_table[(in_word[0] >> 2)];
*(out++) = base64_table[((in_word[0] << 4) & 63) | (in_word[1] >> 4)];
*(out++) = base64_table[((in_word[1] << 2) & 63) | (in_word[2] >> 6)];
*(out++) = base64_table[(in_word[2] & 63)];
}
if (mod == 1) *(out-2) = '=';
if (mod >= 1) *(out-1) = '=';
*(out) = 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment