added base64 codec

This commit is contained in:
Erik Ekman 2007-06-09 17:49:19 +00:00
parent 1e7486bdd2
commit 7c53be08c0
3 changed files with 268 additions and 0 deletions

159
src/base64.c Normal file
View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encoding.h"
#include "base64.h"
static const char cb64[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.";
static unsigned char rev64[128];
static int reverse_init = 0;
static struct encoder base64_encoder =
{
"BASE64",
base64_encode,
base64_decode,
base64_handles_dots,
base64_handles_dots
};
struct encoder
*get_base64_encoder()
{
return &base64_encoder;
}
int
base64_handles_dots()
{
return 1;
}
int
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
{
size_t newsize;
size_t maxsize;
unsigned char *s;
unsigned char *p;
unsigned char *q;
int i;
memset(buf, 0, *buflen);
/* how many chars can we encode within the buf */
maxsize = 3 * (*buflen / 4 - 1) - 1;
/* how big will the encoded data be */
newsize = 4 * (size / 3 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
}
p = s = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=3) {
p[0] = cb64[((q[0] & 0xfc) >> 2)];
p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
q += 3;
p += 4;
}
*p = 0;
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf) - 1;
}
#define DECODE_ERROR 0xffffffff
#define REV64(x) rev64[(int) (x)]
static int
decode_token(const unsigned char *t, unsigned char *data, size_t len)
{
if (len < 2)
return 0;
data[0] = ((REV64(t[0]) & 0x3f) << 2) |
((REV64(t[1]) & 0x30) >> 4);
if (len < 3)
return 1;
data[1] = ((REV64(t[1]) & 0x0f) << 4) |
((REV64(t[2]) & 0x3c) >> 2);
if (len < 4)
return 2;
data[2] = ((REV64(t[2]) & 0x03) << 6) |
(REV64(t[3]) & 0x3f);
return 3;
}
int
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{
unsigned char *q;
size_t newsize;
size_t maxsize;
const char *p;
unsigned char c;
int len;
int i;
if (!reverse_init) {
for (i = 0; i < 64; i++) {
c = cb64[i];
rev64[(int) c] = i;
}
reverse_init = 1;
}
/* chars needed to decode slen */
newsize = 3 * (slen / 4 + 1) + 1;
/* encoded chars that fit in buf */
maxsize = 4 * (*buflen / 3 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
q = buf;
for (p = str; *p && strchr(cb64, *p); p += 4) {
len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
q += len;
slen -= 4;
if (len < 3)
break;
}
*q = '\0';
return q - (unsigned char *) buf;
}

25
src/base64.h Normal file
View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __BASE64_H__
#define __BASE64_H__
struct encoder *get_base64_encoder(void);
int base64_handles_dots();
int base64_encode(char *, size_t *, const void *, size_t);
int base64_decode(void *, size_t *, const char *, size_t);
#endif

84
tests/base64.c Normal file
View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <check.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "encoding.h"
#include "base64.h"
#include "test.h"
static struct tuple
{
char *a;
char *b;
} testpairs[] = {
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
{ "abc123", "ywjJmtiZ" },
{ NULL, NULL }
};
START_TEST(test_base64_encode)
{
size_t len;
char buf[4096];
int val;
int i;
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].b));
}
}
END_TEST
START_TEST(test_base64_decode)
{
size_t len;
char buf[4096];
int val;
int i;
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a));
}
}
END_TEST
TCase *
test_base64_create_tests()
{
TCase *tc;
tc = tcase_create("Base64");
tcase_add_test(tc, test_base64_encode);
tcase_add_test(tc, test_base64_decode);
return tc;
}