Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 71 additions & 171 deletions src/addagent/b64.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,202 +24,102 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TRUE 1
#define FALSE 0
#include <stdbool.h> // For using bool instead of int for boolean functions

/* Prototypes */
static int is_base64(char c);
static char encode(unsigned char u);
static unsigned char decode(char c);
static bool is_base64(char c);
static char encode_char(unsigned char u);
static unsigned char decode_char(char c);

/* Global variables */
/* Global functions */
char *decode_base64(const char *src);
char *encode_base64(int size, char *src);


/* Base64 encode and return size data in 'src'. The caller must free the
* returned string.
* Returns encoded string otherwise NULL
*/
char *encode_base64(int size, char *src)
{
int i;
char *out, *p;

if (!src) {
return NULL;
}

if (!size) {
size = strlen((char *)src);
}

out = (char *)calloc(sizeof(char), size * 4 / 3 + 4);
if (!out) {
return NULL;
}

p = out;
char *encode_base64(int size, const char *src);

/* Encode a character into Base64 */
static char encode_char(unsigned char u) {
if (u < 26) return 'A' + u;
if (u < 52) return 'a' + (u - 26);
if (u < 62) return '0' + (u - 52);
return (u == 62) ? '+' : '/';
}

for (i = 0; i < size; i += 3) {
unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
/* Decode a Base64 character */
static unsigned char decode_char(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
return (c == '+') ? 62 : 63;
}

b1 = src[i];
/* Check if a character is a valid Base64 character */
static bool is_base64(char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || (c == '+') ||
(c == '/') || (c == '=');
}

if (i + 1 < size) {
b2 = src[i + 1];
}
/* Encode data to Base64 */
char *encode_base64(int size, const char *src) {
if (!src) return NULL;

if (i + 2 < size) {
b3 = src[i + 2];
}
if (size == 0) size = strlen(src);

b4 = b1 >> 2;
b5 = ((b1 & 0x3) << 4) | (b2 >> 4);
b6 = ((b2 & 0xf) << 2) | (b3 >> 6);
b7 = b3 & 0x3f;
int out_size = (size + 2) / 3 * 4 + 1; // +1 for null terminator
char *out = (char *)calloc(out_size, sizeof(char));
if (!out) return NULL;

*p++ = encode(b4);
*p++ = encode(b5);
char *p = out;

if (i + 1 < size) {
*p++ = encode(b6);
} else {
*p++ = '=';
}
for (int i = 0; i < size; i += 3) {
unsigned char b1 = src[i];
unsigned char b2 = (i + 1 < size) ? src[i + 1] : 0;
unsigned char b3 = (i + 2 < size) ? src[i + 2] : 0;

if (i + 2 < size) {
*p++ = encode(b7);
} else {
*p++ = '=';
}
*p++ = encode_char(b1 >> 2);
*p++ = encode_char(((b1 & 0x3) << 4) | (b2 >> 4));
*p++ = (i + 1 < size) ? encode_char(((b2 & 0xf) << 2) | (b3 >> 6)) : '=';
*p++ = (i + 2 < size) ? encode_char(b3 & 0x3f) : '=';
}

return out;
}

/* Decode the base64 encoded string 'src' into the memory pointed to by
* 'dest'. The dest buffer is NUL terminated.
* Returns NULL in case of error
*/
char *decode_base64(const char *src)
{
if (src && *src) {
char *dest;
unsigned char *p;
int k, l = strlen(src) + 1;
unsigned char *buf;

/* The size of the dest will always be less than the source */
dest = (char *)calloc(sizeof(char), l + 13);
if (!dest) {
return (NULL);
}

p = (unsigned char *)dest;

buf = (unsigned char *) malloc(l);
if (!buf) {
free(dest);
return (NULL);
}

/* Ignore non base64 chars as per the POSIX standard */
for (k = 0, l = 0; src[k]; k++) {
if (is_base64(src[k])) {
buf[l++] = src[k];
}
}

for (k = 0; k < l; k += 4) {
char c1 = 'A', c2 = 'A', c3 = 'A', c4 = 'A';
unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0;

c1 = buf[k];

if (k + 1 < l) {
c2 = buf[k + 1];
}

if (k + 2 < l) {
c3 = buf[k + 2];
}

if (k + 3 < l) {
c4 = buf[k + 3];
}

b1 = decode(c1);
b2 = decode(c2);
b3 = decode(c3);
b4 = decode(c4);
/* Decode Base64 encoded string */
char *decode_base64(const char *src) {
if (!src || !*src) return NULL;

*p++ = ((b1 << 2) | (b2 >> 4) );
int len = strlen(src);
int out_len = len * 3 / 4;
char *dest = (char *)calloc(out_len + 1, sizeof(char)); // +1 for null terminator
if (!dest) return NULL;

if (c3 != '=') {
*p++ = (((b2 & 0xf) << 4) | (b3 >> 2) );
}

if (c4 != '=') {
*p++ = (((b3 & 0x3) << 6) | b4 );
}
unsigned char *buf = (unsigned char *)malloc(len);
if (!buf) {
free(dest);
return NULL;
}

// Ignore non-Base64 characters
int l = 0;
for (int k = 0; k < len; k++) {
if (is_base64(src[k])) {
buf[l++] = src[k];
}

free(buf);

return (dest);
}
return (NULL);
}

static char encode(unsigned char u)
{
if (u < 26) {
return 'A' + u;
}
if (u < 52) {
return 'a' + (u - 26);
}
if (u < 62) {
return '0' + (u - 52);
}
if (u == 62) {
return '+';
}
unsigned char *p = (unsigned char *)dest;

return '/';
}
for (int k = 0; k < l; k += 4) {
unsigned char b1 = decode_char(buf[k]);
unsigned char b2 = decode_char((k + 1 < l) ? buf[k + 1] : 'A');
unsigned char b3 = decode_char((k + 2 < l) ? buf[k + 2] : 'A');
unsigned char b4 = decode_char((k + 3 < l) ? buf[k + 3] : 'A');

/* Decode a base64 character */
static unsigned char decode(char c)
{
if (c >= 'A' && c <= 'Z') {
return (c - 'A');
}
if (c >= 'a' && c <= 'z') {
return (c - 'a' + 26);
}
if (c >= '0' && c <= '9') {
return (c - '0' + 52);
*p++ = (b1 << 2) | (b2 >> 4);
if (buf[k + 2] != '=') *p++ = ((b2 & 0xf) << 4) | (b3 >> 2);
if (buf[k + 3] != '=') *p++ = ((b3 & 0x3) << 6) | b4;
}
if (c == '+') {
return 62;
}

return 63;
}

/* Returns TRUE if 'c' is a valid base64 character, otherwise FALSE */
static int is_base64(char c)
{
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || (c == '+') ||
(c == '/') || (c == '=')) {

return TRUE;
}
return FALSE;
free(buf);
return dest;
}