228 lines
5.6 KiB
C
228 lines
5.6 KiB
C
![]() |
#ifndef HEADER_CB64_H
|
||
|
#define HEADER_CB64_H
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <math.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#define TRUE 1
|
||
|
#define FALSE 0
|
||
|
|
||
|
#define B64_TABLE_SIZE 64
|
||
|
|
||
|
#define B64_ENCODE_OK 0
|
||
|
#define B64_ENCODE_FAIL -1
|
||
|
#define B64_DECODE_OK 0
|
||
|
#define B64_DECODE_FAIL -1
|
||
|
|
||
|
struct base64_table_dict
|
||
|
{
|
||
|
char key;
|
||
|
uint8_t val;
|
||
|
} b64_dict_t;
|
||
|
|
||
|
static struct base64_table_dict dict[B64_TABLE_SIZE];
|
||
|
|
||
|
static const uint8_t BASE_64_TABLE[B64_TABLE_SIZE] = {
|
||
|
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||
|
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||
|
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||
|
0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||
|
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
|
||
|
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
||
|
0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33,
|
||
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
|
||
|
};
|
||
|
|
||
|
static const uint8_t PADDING = 0x3D;
|
||
|
static const uint8_t SIX_BIT_MASK = 0x3F; // 63 // 111111
|
||
|
static const uint8_t EIGHT_BIT_MASK = 0xFF; // 255 // 11111111
|
||
|
|
||
|
static void init_b64_table_dict()
|
||
|
{
|
||
|
for (int i = 0; i < B64_TABLE_SIZE; i++)
|
||
|
{
|
||
|
b64_dict_t.key = BASE_64_TABLE[i];
|
||
|
b64_dict_t.val = i;
|
||
|
dict[i] = b64_dict_t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static struct base64_table_dict base64_table_dict_find(char key)
|
||
|
{
|
||
|
for (int i = 0; i < B64_TABLE_SIZE; i++)
|
||
|
{
|
||
|
if (dict[i].key == key)
|
||
|
return dict[i];
|
||
|
}
|
||
|
return b64_dict_t;
|
||
|
}
|
||
|
|
||
|
static uint64_t size_char_ptr(const unsigned char* arr)
|
||
|
{
|
||
|
uint64_t size = 0;
|
||
|
|
||
|
while(*arr)
|
||
|
{
|
||
|
size++;
|
||
|
arr++;
|
||
|
}
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
int encode_b64(const unsigned char* src, size_t src_size,
|
||
|
unsigned char** dst, size_t* dst_size)
|
||
|
{
|
||
|
if (src_size == 0)
|
||
|
src_size = size_char_ptr(src);
|
||
|
|
||
|
uint32_t _dst_size = 4 * ((src_size + 2) / 3);
|
||
|
|
||
|
// caller should call free()
|
||
|
unsigned char* _dst = (unsigned char*) malloc(sizeof(*_dst) * _dst_size + 3);
|
||
|
if (_dst == NULL)
|
||
|
return B64_ENCODE_FAIL;
|
||
|
|
||
|
FILE* f = fmemopen((void*)src, src_size, "r");
|
||
|
FILE* base64_res_f = fmemopen((void*)_dst, sizeof(*_dst) * _dst_size + 3, "w");
|
||
|
|
||
|
unsigned char buffer[4];
|
||
|
uint32_t size_out = 0;
|
||
|
uint32_t total_read = 0;
|
||
|
|
||
|
while(TRUE)
|
||
|
{
|
||
|
// read data per 3 bytes to buffer
|
||
|
size_t r = fread(buffer, 1, 3, f);
|
||
|
|
||
|
// check if the entire buffer has been read
|
||
|
if (r <= 0 || total_read == src_size)
|
||
|
break;
|
||
|
|
||
|
total_read += r;
|
||
|
|
||
|
// terminate the buffer with '\0'
|
||
|
buffer[r] = '\0';
|
||
|
|
||
|
uint32_t segment_count = 0;
|
||
|
uint32_t dec = 0;
|
||
|
for (int i = 0; i < r; i++)
|
||
|
{
|
||
|
// if (buffer[i] == '\0')
|
||
|
// continue;
|
||
|
|
||
|
uint32_t l_shift = 16 - segment_count * 8;
|
||
|
uint32_t s = (uint32_t) buffer[i];
|
||
|
dec |= s << l_shift;
|
||
|
segment_count = segment_count + 1;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < segment_count+1; i++)
|
||
|
{
|
||
|
uint32_t r_shift = 18 - i * 6;
|
||
|
uint8_t idx_b = (uint8_t) (dec >> r_shift) & SIX_BIT_MASK;
|
||
|
|
||
|
uint8_t c_b64 = BASE_64_TABLE[idx_b];
|
||
|
|
||
|
fputc(c_b64, base64_res_f);
|
||
|
size_out = size_out + 1;
|
||
|
}
|
||
|
if (segment_count == 2)
|
||
|
{
|
||
|
fputc(PADDING, base64_res_f);
|
||
|
size_out = size_out + 2;
|
||
|
}
|
||
|
if (segment_count == 1)
|
||
|
{
|
||
|
fputc(PADDING, base64_res_f);
|
||
|
fputc(PADDING, base64_res_f);
|
||
|
size_out = size_out + 3;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// terminate the buffer with '\0'
|
||
|
_dst[size_out] = '\0';
|
||
|
*dst = _dst;
|
||
|
*dst_size = size_out;
|
||
|
|
||
|
fclose(f);
|
||
|
fclose(base64_res_f);
|
||
|
|
||
|
return B64_ENCODE_OK;
|
||
|
}
|
||
|
|
||
|
int decode_b64(const unsigned char* src, size_t src_size,
|
||
|
unsigned char** dst, size_t* dst_size)
|
||
|
{
|
||
|
init_b64_table_dict();
|
||
|
if (src_size == 0)
|
||
|
src_size = size_char_ptr(src);
|
||
|
|
||
|
uint32_t _dst_size = src_size / 4 * 3;
|
||
|
|
||
|
// caller should call free()
|
||
|
unsigned char* _dst = (unsigned char*) malloc(sizeof(*_dst) * _dst_size + 1);
|
||
|
if (_dst == NULL)
|
||
|
return B64_DECODE_FAIL;
|
||
|
|
||
|
FILE* base64_in_f = fmemopen((void*)src, src_size, "r");
|
||
|
FILE* text_f = fmemopen((void*)_dst, sizeof(*_dst) * _dst_size + 1, "w");
|
||
|
|
||
|
unsigned char buffer[5];
|
||
|
uint32_t size_out = 0;
|
||
|
uint32_t total_read = 0;
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
// read data per 4 bytes to buffer
|
||
|
size_t r = fread(buffer, 1, 4, base64_in_f);
|
||
|
|
||
|
// check if the entire buffer has been read
|
||
|
if (r <= 0 || total_read == src_size)
|
||
|
break;
|
||
|
|
||
|
total_read += r;
|
||
|
|
||
|
// terminate the buffer with '\0'
|
||
|
buffer[r] = '\0';
|
||
|
|
||
|
uint32_t segment_count = 0;
|
||
|
uint32_t dec = 0;
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
if (buffer[i] == '\0' || buffer[i] == PADDING)
|
||
|
continue;
|
||
|
|
||
|
struct base64_table_dict b64_idx_dict = base64_table_dict_find(buffer[i]);
|
||
|
uint32_t l_shift = 18 - segment_count * 6;
|
||
|
uint32_t b64_idx = (uint32_t) b64_idx_dict.val;
|
||
|
dec |= b64_idx << l_shift;
|
||
|
segment_count = segment_count + 1;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < segment_count-1; i++)
|
||
|
{
|
||
|
uint32_t r_shift = 16 - i * 8;
|
||
|
uint8_t c_b255 = (uint8_t) (dec >> r_shift) & EIGHT_BIT_MASK;
|
||
|
|
||
|
fputc(c_b255, text_f);
|
||
|
size_out = size_out + 1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// terminate the buffer with '\0'
|
||
|
_dst[size_out] = '\0';
|
||
|
*dst = _dst;
|
||
|
*dst_size = size_out;
|
||
|
|
||
|
fclose(base64_in_f);
|
||
|
fclose(text_f);
|
||
|
|
||
|
return B64_DECODE_OK;
|
||
|
}
|
||
|
|
||
|
#endif
|