Created
June 6, 2023 15:34
-
-
Save thaolt/42ad053c1d8a13d7dd9557b8e66f1e22 to your computer and use it in GitHub Desktop.
base85 encode and decode in pure C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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