1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-29 01:45:34 +00:00
elinks/src/util/base64.c

158 lines
3.0 KiB
C

/** Base64 encode/decode implementation.
* @file */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "elinks.h"
#include "util/base64.h"
#include "util/error.h"
#include "util/memory.h"
static unsigned char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *
base64_encode(char *in)
{
assert(in && *in);
if_assert_failed return NULL;
return base64_encode_bin(in, strlen(in), NULL);
}
char *
base64_encode_bin(char *in, int inlen, int *outlen)
{
char *out;
char *outstr;
assert(in && *in);
if_assert_failed return NULL;
out = outstr = (char *)mem_alloc((inlen / 3) * 4 + 4 + 1);
if (!out) return NULL;
while (inlen >= 3) {
*out++ = base64_chars[ *in >> 2 ];
*out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
*out++ = base64_chars[ (*(in + 1) << 2 | *(in + 2) >> 6) & 63 ];
*out++ = base64_chars[ *(in + 2) & 63 ];
inlen -= 3; in += 3;
}
if (inlen == 1) {
*out++ = base64_chars[ *in >> 2 ];
*out++ = base64_chars[ *in << 4 & 63 ];
*out++ = '=';
*out++ = '=';
}
if (inlen == 2) {
*out++ = base64_chars[ *in >> 2 ];
*out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
*out++ = base64_chars[ (*(in + 1) << 2) & 63 ];
*out++ = '=';
}
*out = 0;
if (outlen)
*outlen = out-outstr;
return outstr;
}
char *
base64_decode(const char *in)
{
assert(in && *in);
if_assert_failed return NULL;
return base64_decode_bin(in, strlen(in), NULL);
}
/** Decode a Base64 string.
* @param in Input Base64 string
* @param inlen Length of @a in, in bytes
* @param[out] outlen Length of decoded string
*
* @returns the string decoded (must be freed by the caller)
* or NULL if an error occurred (syntax error or out of memory) */
char *
base64_decode_bin(const char *in, int inlen, int *outlen)
{
static unsigned char is_base64_char[256]; /* static to force initialization at zero */
static unsigned char decode[256];
char *out;
char *outstr;
int count = 0;
unsigned int bits = 0;
static int once = 0;
assert(in && *in);
if_assert_failed return NULL;
outstr = out = (char *)mem_alloc(inlen / 4 * 3 + 1);
if (!outstr) return NULL;
if (!once) {
int i = sizeof(base64_chars) - 1;
while (i >= 0) {
is_base64_char[base64_chars[i]] = 1;
decode[base64_chars[i]] = i;
i--;
}
once = 1;
}
while (*in) {
if (*in == '=') break;
if (!is_base64_char[(unsigned char)*in])
goto decode_error;
bits += decode[(unsigned char)*in];
count++;
if (count == 4) {
*out++ = bits >> 16;
*out++ = (bits >> 8) & 0xff;
*out++ = bits & 0xff;
bits = 0;
count = 0;
} else {
bits <<= 6;
}
++in;
}
if (!*in) {
if (count) goto decode_error;
} else { /* '=' */
switch (count) {
case 1:
goto decode_error;
break;
case 2:
*out++ = bits >> 10;
break;
case 3:
*out++ = bits >> 16;
*out++ = (bits >> 8) & 0xff;
break;
}
}
*out = 0;
if (outlen)
*outlen = out-outstr;
return outstr;
decode_error:
mem_free(outstr);
return NULL;
}