Skip to content

Instantly share code, notes, and snippets.

@thaolt
Created June 6, 2023 15:34
Show Gist options
  • Save thaolt/42ad053c1d8a13d7dd9557b8e66f1e22 to your computer and use it in GitHub Desktop.
Save thaolt/42ad053c1d8a13d7dd9557b8e66f1e22 to your computer and use it in GitHub Desktop.
base85 encode and decode in pure C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
uint8_t _b85alphabet[85] = ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~");
char *_b85chars = NULL;
char **_b85chars2 = NULL;
uint8_t _b85dec[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,
0, 63, 64, 65, 66, 0, 67, 68, 69, 70, 0, 71, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 72, 73, 74, 75, 76,
77, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 0, 0, 0, 78, 79, 80, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 81, 82, 83, 84, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0};
#define SwapFourBytes(data) \
( (((data) >> 24) & 0x000000FF) | (((data) >> 8) & 0x0000FF00) | \
(((data) << 8) & 0x00FF0000) | (((data) << 24) & 0xFF000000) )
char *_85encode(char *b,size_t input_len, char *chars, char ** chars2, bool pad, bool foldnuls, bool foldspaces)
{
if (input_len == 0 || b == NULL)
return 0;
char *input = NULL;
size_t padding = 4 - input_len % 4;
if (padding) {
input_len += padding;
input = calloc(input_len, 1);
strcpy(input, b);
}
if (input == NULL) {
input = b;
}
size_t words_count = input_len / 4;
int *words = malloc((words_count) * sizeof (int));
memcpy(words, input, input_len);
//Convert from big endian to little endian
for(int i = 0; i < words_count; i++) {
words[i] = SwapFourBytes(words[i]);
}
char *chunks[words_count];
for (int i = 0; i < words_count; i++) {
if (foldnuls && words[i] == 0) {
chunks[i] = calloc(2, 1);
chunks[i][0] = 'z';
} else if (foldspaces && words[i] == 0x20202020) {
chunks[i] = calloc(2, 1);
chunks[i][0] = 'y';
} else {
chunks[i] = calloc(6, 1);
strcat(chunks[i], chars2[words[i] / 614125]);
strcat(chunks[i], chars2[words[i] / 85 % 7225]);
chunks[i][4] = chars[words[i] % 85];
}
}
if(padding && !pad) {
if (strcmp(chunks[words_count - 1], "z") == 0) {
chunks[words_count - 1] = realloc(chunks[words_count - 1], 6);
strcpy(chunks[words_count - 1], "00000");
}
int x = strlen(chunks[words_count - 1]) - padding;
chunks[words_count - 1] = realloc(chunks[words_count - 1], x + 1);
chunks[words_count - 1][x] = 0;
}
char * result = calloc(words_count*5 +1, 1);
for (int i = 0; i < words_count; i++) {
strcat(result, chunks[i]);
}
if (padding) {
free(input);
}
free(words);
return result;
}
char *b85encode(char *b, size_t input_len) {
if (_b85chars == NULL) {
_b85chars = calloc(85, 1);
for(int i = 0; i < 85; i++) {
_b85chars[i] = _b85alphabet[i];
}
}
if (_b85chars2 == NULL) {
_b85chars2 = calloc(85 * 85, sizeof (char *));
int index = 0;
for(int i = 0; i < 85; i++) {
for(int j = 0; j < 85; j++) {
_b85chars2[index] = calloc(3, 1);
_b85chars2[index][0] = _b85chars[i];
_b85chars2[index][1] = _b85chars[j];
index += 1;
}
}
}
return _85encode(b, input_len, _b85chars, _b85chars2, false, false, false);
}
size_t b85decode(char** result, char *b)
{
size_t input_len = strlen(b);
char *input = calloc(input_len+1, sizeof (char));
strcpy(input, b);
uint8_t padding = 5 - input_len % 5;
if (padding) {
input_len += padding;
input = realloc(input, input_len+1);
strcpy(input, b);
for (int i = 0; i < padding; i++){
strcat(input, "~");
}
}
size_t output_len = 0;
for (int i = 0; i < input_len; i += 5) {
char chucks[5] = {b[i], b[i + 1], b[i + 2], b[i +3], b[i + 4]};
int acc = 0;
for (int j = 0; j< 5; j++) {
if (chucks[j] > sizeof(_b85dec)) {
free (input);
return 0;
}
acc = acc * 85 + _b85dec[chucks[j]];
}
acc = SwapFourBytes(acc);
if (*result == NULL)
*result = malloc(sizeof (int));
else
*result = realloc(*result, output_len + sizeof (int));
memcpy(*result + output_len, &acc, sizeof (int));
output_len += sizeof (int);
}
if (padding) {
output_len -= padding + 1;
(*result)[output_len] = 0;
}
free (input);
return output_len;
}
#ifndef BASE85_H
#define BASE85_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
char *b85encode(char *b, size_t input_len);
size_t b85decode(char** ret, char *b);
#ifdef __cplusplus
}
#endif
#endif //BASE85_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment