背景
网上找了一些源码,实用时都有点问题(也可能是我没用对),于是自己参考了一份源码改写了。
直接提供最简洁的源码,删减了一堆编译宏,需要使用者自己实现移植编译。
.c文件里面有使用例子参考。
源码
my_base64.h
/**
* @file my_base64.h
* @author zhongwei.peng
* @brief Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049.
* 参考了 intel base64 库,参考链接: https://github.com/intel/base64
* @version 0.1
* @date 2023-01-04
*
* @copyright Copyright (c) 2023
*
*/
#ifndef __MY_BASE64_H__
#define __MY_BASE64_H__
/*
标准Base64 = 0
URL中使用 = 1
标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,
而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
*/
#define BASE64_USE_URL (1)
// 获取 encode 需要的缓存空间, x 为十六进制数据长度,单位 byte
#define BASE64_ENCODE_BUF_SIZE(x) (((x)+5) / 3 * 4)
/**
* @brief base64 编码
*
* @param in[in] 需要编码的缓存(十六进制)
* @param len[in] 需要编码的字节数
* @param out[out] 编码后输出缓存指针(字符串)
* @param len_out[out] 编码后输出缓存指针(字符串)的长度
*/
void base64_encode(const unsigned char *in, unsigned int len_in, char *out, unsigned int *len_out);
/**
* @brief base64 解码
*
* @param base64_str[in] 需要解码的缓存(字符串)
* @param len[in] 需要解码的字节数
* @param out[out] 解码后输出缓存指针
* @param len_out[out] 解码后输出缓存长度
*/
void base64_decode(const char *base64_str, unsigned int len, unsigned char *out, unsigned int *len_out);
#endif
my_base64.c
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "my_base64.h"
/*
// test sample
void test_base64(void)
{
unsigned char src_code[] = {'b', 'a', 's', 'e', '6', '4', 'v', '1'};
char *encode_out;
unsigned int encode_len;
unsigned char *decode_out;
unsigned int decode_len;
encode_len = BASE64_ENCODE_BUF_SIZE(sizeof(src_code));
encode_out = (char *)malloc(encode_len);
if (encode_out)
{
// encode
base64_encode(src_code, sizeof(src_code), encode_out, &encode_len);
// decode
decode_out = (unsigned char *)malloc(encode_len);
if (decode_out)
{
base64_decode(encode_out, encode_len, decode_out, &decode_len);
free(decode_out);
}
free(encode_out);
}
}
*/
static const char _base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char _base64url_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static const int base64_reverse_alphabet[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static const int base64url_reverse_alphabet[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
/**
* @brief base64 编码
*
* @param in[in] 需要编码的缓存(十六进制)
* @param len[in] 需要编码的字节数
* @param out[out] 编码后输出缓存指针(字符串)
* @param len_out[out] 编码后输出缓存指针(字符串)的长度
*/
void base64_encode(const unsigned char *in, unsigned int len, char *out, unsigned int *len_out)
{
char filler = '=';
size_t i = 0;
size_t n = len;
uint_least32_t val;
unsigned int o = 0; // offset
const char *alphabet;
if (BASE64_USE_URL)
alphabet = _base64url_alphabet;
else
alphabet = _base64_alphabet;
if (n >= 3) {
for (i = 0; n - i >= 3; i += 3) {
// read 3 bytes x 8 bits = 24 bits
val = (in[i+0] << 16) | (in[i+1] << 8) | in[i+2];
// write 4 chars x 6 bits = 24 bits
out[o++] = alphabet[(val >> 18) & 0x3f];
out[o++] = alphabet[(val >> 12) & 0x3f];
out[o++] = alphabet[(val >> 6) & 0x3f];
out[o++] = alphabet[val & 0x3f];
}
}
if (n - i == 2) {
val = (in[i] << 8);
val |= in[i + 1];
out[o++] = alphabet[(val >> 10) & 0x3f];
out[o++] = alphabet[(val >> 4) & 0x3f];
out[o++] = alphabet[(val << 2) & 0x3f];
out[o++] = filler;
} else if (n - i == 1) {
out[o++] = alphabet[(in[i] >> 2) & 0x3f];
out[o++] = alphabet[(in[i] << 4) & 0x3f];
out[o++] = filler;
out[o++] = filler;
}
out[o] = '\0';
*len_out = o;
return;
}
/**
* @brief base64 解码
*
* @param base64_str[in] 需要解码的缓存(字符串)
* @param len[in] 需要解码的字节数
* @param out[out] 解码后输出缓存指针
* @param len_out[out] 解码后输出缓存长度
*/
void base64_decode(const char *base64_str, unsigned int len, unsigned char *out, unsigned int *len_out)
{
unsigned char *p = out;
const unsigned char *in = (const unsigned char *)base64_str;
const unsigned char *end = in + len;
const int *reverse_alphabet;
unsigned int val;
if (BASE64_USE_URL)
reverse_alphabet = base64url_reverse_alphabet;
else
reverse_alphabet = base64_reverse_alphabet;
while (in < end) {
if (reverse_alphabet[in[0]] < 0 || reverse_alphabet[in[1]] < 0)
break;
val = (reverse_alphabet[in[0]] & 0xFF) << 18;
val |= (reverse_alphabet[in[1]] & 0xFF) << 12;
if (in[2] == '=' || in[2] == '\0') {
*p++ = val >> 16;
break;
} else if (in[3] == '=' || in[3] == '\0') {
val |= (reverse_alphabet[in[2]] & 0xFF) << 6;
*p++ = val >> 16;
*p++ = val >> 8;
break;
} else {
val |= (reverse_alphabet[in[2]] & 0xFF) << 6;
val |= (reverse_alphabet[in[3]] & 0xFF);
*p++ = val >> 16;
*p++ = val >> 8;
*p++ = val;
in += 4;
}
} // !while
*p = '\0';
*len_out = p - out;
return;
}