Base64 library
Library for encoding and decoding data to/from Base64 (RFC 4648). The alphabet is the standard A–Z, a–z, 0–9, +, /, with = padding.
Null terminator
All encoding and decoding functions null-terminate the result. The *_len functions return the required buffer size including the null terminator — so malloc(base64_*_len(...)) allocates exactly as much memory as needed. The encode/decode functions themselves return the length of the payload excluding the null terminator.
Encoding
Calculating buffer size
#include "base64.h"
int base64_encode_len(const int len);Returns the buffer size required to encode len bytes, including the null terminator.
Parameterslen — length of the source data.
Return value
Buffer size in bytes (including \0).
Encoding
int base64_encode(char* encoded, const char* string, const int string_len);Encodes string_len bytes from string into Base64 and appends a null terminator.
Parametersencoded — destination buffer (at least base64_encode_len(string_len) bytes).string — source data.string_len — length of the source data.
Return value
Length of the encoded string excluding the null terminator.
Encoding with line wrapping
int base64_encode_nl_len(const int len, int wrap);
int base64_encode_nl(char* encoded, const char* string, const int string_len, const int wrap);Encodes data, inserting \r\n every wrap characters of output — the format used by PEM and MIME (RFC 2045; a typical line width is 76 characters). With wrap == 0 it behaves like plain encoding.
Parameterslen — length of the source data (for *_len).encoded — destination buffer.string — source data.string_len — length of the source data.wrap — line width in characters; 0 disables wrapping.
Return valuebase64_encode_nl_len — buffer size including \0 and the line-break characters.base64_encode_nl — length of the encoded data excluding the null terminator.
Decoding
Calculating buffer size
int base64_decode_len(const char* bufcoded);Returns an upper bound for the decoded size based on the encoded string, including the null terminator. \r and \n in bufcoded are skipped, so the input may contain line breaks.
Parametersbufcoded — encoded string (null-terminated).
Return value
Buffer size in bytes (including \0).
Decoding
int base64_decode(char* bufplain, const char* bufcoded);Decodes bufcoded from Base64 and appends a null terminator. \r and \n characters in the input are ignored.
Parametersbufplain — destination buffer (at least base64_decode_len(bufcoded) bytes).bufcoded — encoded string (null-terminated).
Return value
Length of the decoded data excluding the null terminator.
Usage examples
Encoding data
#include "http.h"
#include "base64.h"
#include <stdlib.h>
#include <string.h>
void encode_example(httpctx_t* ctx) {
const char* original = "Hello, World!";
int original_len = strlen(original);
// base64_encode_len already accounts for the null terminator
char* encoded = malloc(base64_encode_len(original_len));
if (encoded == NULL) {
ctx->response->send_data(ctx->response, "Memory error");
return;
}
// Encode — the result is null-terminated
base64_encode(encoded, original, original_len);
// encoded = "SGVsbG8sIFdvcmxkIQ=="
ctx->response->send_data(ctx->response, encoded);
free(encoded);
}Decoding data
void decode_example(httpctx_t* ctx) {
const char* encoded = "SGVsbG8sIFdvcmxkIQ==";
// base64_decode_len already accounts for the null terminator
char* decoded = malloc(base64_decode_len(encoded));
if (decoded == NULL) {
ctx->response->send_data(ctx->response, "Memory error");
return;
}
// Decode — the result is null-terminated
base64_decode(decoded, encoded);
// decoded = "Hello, World!"
ctx->response->send_data(ctx->response, decoded);
free(decoded);
}Encoding binary data
void encode_binary(httpctx_t* ctx) {
// Binary data (e.g. a PNG signature)
unsigned char binary_data[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
int data_len = sizeof(binary_data);
char* encoded = malloc(base64_encode_len(data_len));
if (encoded == NULL) {
ctx->response->send_data(ctx->response, "Memory error");
return;
}
base64_encode(encoded, (const char*)binary_data, data_len);
ctx->response->send_data(ctx->response, encoded);
free(encoded);
}Encoding with line wrapping (PEM/MIME)
void encode_pem(httpctx_t* ctx) {
const char* original = "Very long payload ...";
int original_len = strlen(original);
// 76 is the standard PEM/MIME line width
char* encoded = malloc(base64_encode_nl_len(original_len, 76));
if (encoded == NULL) {
ctx->response->send_data(ctx->response, "Memory error");
return;
}
base64_encode_nl(encoded, original, original_len, 76);
ctx->response->send_data(ctx->response, encoded);
free(encoded);
}Using in API
#include "http.h"
#include "base64.h"
#include "storage.h"
#include <stdlib.h>
void get_file_base64(httpctx_t* ctx) {
// Get file from storage
file_t file = storage_file_get("local", "images/logo.png");
if (!file.ok) {
ctx->response->status_code = 404;
ctx->response->send_data(ctx->response, "File not found");
return;
}
// Read file content
char* content = file.content(&file);
if (content == NULL) {
file.close(&file);
ctx->response->send_data(ctx->response, "Read error");
return;
}
// Encode to Base64
char* encoded = malloc(base64_encode_len(file.size));
if (encoded == NULL) {
free(content);
file.close(&file);
ctx->response->send_data(ctx->response, "Memory error");
return;
}
base64_encode(encoded, content, file.size);
// Form JSON response
json_doc_t* doc = json_root_create_object();
json_token_t* root = json_root(doc);
json_object_set(root, "filename", json_create_string(file.name));
json_object_set(root, "data", json_create_string(encoded));
ctx->response->add_header(ctx->response, "Content-Type", "application/json");
ctx->response->send_data(ctx->response, json_stringify(doc));
json_free(doc);
free(encoded);
free(content);
file.close(&file);
}Data URL for images
void get_image_data_url(httpctx_t* ctx) {
const char* image_data = "..."; // binary image data
int image_size = 1024; // data size
const char* prefix = "data:image/png;base64,";
// base64_encode_len already accounts for the null terminator; +strlen(prefix) for the prefix
char* data_url = malloc(base64_encode_len(image_size) + strlen(prefix));
if (data_url == NULL) {
ctx->response->send_data(ctx->response, "Memory error");
return;
}
// Write the prefix, then encode the data right after it
strcpy(data_url, prefix);
base64_encode(data_url + strlen(prefix), image_data, image_size);
ctx->response->send_data(ctx->response, data_url);
free(data_url);
}