Quick actions

cmd+k|ctrl+k

Navigation

Languages

Base64

Snippet info

Language

C

Visibility

public

Author

evine

Created

2020-04-27T13:20:25Z

Updated

2020-04-28T00:10:23Z

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

uint8_t *encode_table = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uint8_t decode_table[256] = {};

void base64_init() {
    for(size_t i = 0; i < 64; ++i) {
        uint8_t v = encode_table[i];
        decode_table[v] = i;
    }
    
    // default init to zero anyway
    //decode_table['='] = 0;
}

void base64_encode(char *in, uint8_t *out, size_t in_len, size_t out_len, size_t *written_len) {
    *written_len = 0;
    if(in_len == 0)
        return;
        
    size_t len_remainder = in_len % 3;
    size_t len_trunck = in_len - len_remainder;
    
    size_t out_i = 0;
    
    for(size_t i = 0; i < len_trunck; i += 3) {
        uint32_t v = (in[i + 0] << 16) | (in[i + 1] << 8) | (in[i + 2] << 0);
    
        out[out_i + 3] = encode_table[(v >>  0) & 0x3f];
        out[out_i + 2] = encode_table[(v >>  6) & 0x3f];
        out[out_i + 1] = encode_table[(v >> 12) & 0x3f];
        out[out_i + 0] = encode_table[(v >> 18) & 0x3f];
        
        out_i += 4;
    }
    
    if(len_remainder == 1) {
        uint32_t v = in[len_trunck] << 16;
        
        out[out_i + 3] = '=';
        out[out_i + 2] = '=';
        out[out_i + 1] = encode_table[(v >> 12) & 0x3f];
        out[out_i + 0] = encode_table[(v >> 18) & 0x3f];
        
        out_i += 4;
    } else if(len_remainder == 2) {
        uint32_t v = (in[len_trunck + 0] << 16) | (in[len_trunck + 1] << 8);
        
        out[out_i + 3] = '=';
        out[out_i + 2] = encode_table[(v >>  6) & 0x3f];
        out[out_i + 1] = encode_table[(v >> 12) & 0x3f];
        out[out_i + 0] = encode_table[(v >> 18) & 0x3f];
        
        out_i += 4;
    }
    
    *written_len = out_i;
}

void base64_decode(uint8_t *in, char *out, size_t in_len, size_t out_len, size_t *written_len) {
    *written_len = 0;
    if(in_len == 0)
        return;
    
    size_t len_trunck = in_len & ~3ULL;
    // Fix: implement slowpath for incorrect base64
    assert((in_len & 3) == 0 && "Input must be padded to 4 bytes");
    
    size_t out_i = 0;
    
    for(size_t i = 0; i < len_trunck; i += 4) {
        uint32_t d0 = decode_table[in[i + 0]] << 18;
        uint32_t d1 = decode_table[in[i + 1]] << 12;
        uint32_t d2 = decode_table[in[i + 2]] << 6;
        uint32_t d3 = decode_table[in[i + 3]] << 0;
        
        uint32_t v = d0 | d1 | d2 | d3;
        
        out[out_i + 0] = v >> 16;
        out[out_i + 1] = v >> 8;
        out[out_i + 2] = v >> 0;
        
        out_i += 3;
    }
    
    *written_len = out_i;
}

int main(void) {
    base64_init();
    
    char *text = "epletest";
    
    uint8_t encoded[1000];
    size_t written_len_encoded = 0;
    base64_encode(text, encoded, strlen(text), sizeof(encoded), &written_len_encoded);
    printf("%.*s\n", (int)written_len_encoded, encoded);
    
    char decoded[1000];
    size_t written_len_decoded = 0;
    base64_decode(encoded, decoded, written_len_encoded, sizeof(decoded), &written_len_decoded);
    printf("%.*s\n", (int)written_len_decoded, decoded);
    
    return 0;
}
INFO