/*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
+ * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#define BLKSIZE_RAW 5
#define BLKSIZE_ENC 8
-static const char cb32[] =
+static const char cb32[] =
"abcdefghijklmnopqrstuvwxyz012345";
-static unsigned char rev32[128];
+static const char cb32_ucase[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
+static unsigned char rev32[256];
static int reverse_init = 0;
-static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_encode(char *, size_t *, const void *, size_t);
+static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_handles_dots();
static int base32_blksize_raw();
static int base32_blksize_enc();
return &base32_encoder;
}
-static int
+static int
base32_handles_dots()
{
return 0;
}
-static int
+static int
base32_blksize_raw()
{
return BLKSIZE_RAW;
}
-static int
+static int
base32_blksize_enc()
{
return BLKSIZE_ENC;
}
-int
-b32_5to8(int in)
-{
- return cb32[in & 31];
-}
-
-int
-b32_8to5(int in)
+inline static void
+base32_reverse_init()
{
int i;
- int c;
+ unsigned char c;
+
if (!reverse_init) {
+ memset (rev32, 0, 256);
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
+ c = cb32_ucase[i];
+ rev32[(int) c] = i;
}
reverse_init = 1;
}
- return rev32[in];
}
-static int
-base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
+int
+b32_5to8(int in)
{
- size_t newsize;
- size_t maxsize;
- unsigned char *p;
- unsigned char *q;
- int i;
-
- memset(buf, 0, *buflen);
-
- /* how many chars can we encode within the buf */
- maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
- /* how big will the encoded data be */
- newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
- /* if the buffer is too small, eat some of the data */
- if (*buflen < newsize) {
- size = maxsize;
- }
-
- p = (unsigned char *) buf;
- q = (unsigned char *)data;
-
- for(i=0;i<size;i+=BLKSIZE_RAW) {
- p[0] = cb32[((q[0] & 0xf8) >> 3)];
- p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
- p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
- p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
- p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
- p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
- p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
- p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
-
- q += BLKSIZE_RAW;
- p += BLKSIZE_ENC;
- }
- *p = 0;
-
- /* store number of bytes from data that was used */
- *buflen = size;
-
- return strlen(buf) - 1;
+ return cb32[in & 31];
}
-#define DECODE_ERROR 0xffffffff
-#define REV32(x) rev32[(int) (x)]
+int
+b32_8to5(int in)
+{
+ base32_reverse_init();
+ return rev32[in];
+}
static int
-decode_token(const unsigned char *t, unsigned char *data, size_t len)
+base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
+/*
+ * Fills *buf with max. *buflen characters, encoding size bytes of *data.
+ *
+ * NOTE: *buf space should be at least 1 byte _more_ than *buflen
+ * to hold the trailing '\0'.
+ *
+ * return value : #bytes filled in buf (excluding \0)
+ * sets *buflen to : #bytes encoded from data
+ */
{
- if (len < 2)
- return 0;
+ unsigned char *udata = (unsigned char *) data;
+ int iout = 0; /* to-be-filled output char */
+ int iin = 0; /* one more than last input byte that can be
+ successfully decoded */
- data[0] = ((REV32(t[0]) & 0x1f) << 3) |
- ((REV32(t[1]) & 0x1c) >> 2);
-
- if (len < 4)
- return 1;
+ /* Note: Don't bother to optimize manually. GCC optimizes
+ better(!) when using simplistic array indexing. */
- data[1] = ((REV32(t[1]) & 0x03) << 6) |
- ((REV32(t[2]) & 0x1f) << 1) |
- ((REV32(t[3]) & 0x10) >> 4);
+ while (1) {
+ if (iout >= *buflen || iin >= size)
+ break;
+ buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
+ iout++;
+
+ if (iout >= *buflen || iin >= size) {
+ iout--; /* previous char is useless */
+ break;
+ }
+ buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
+ ((iin + 1 < size) ?
+ ((udata[iin + 1] & 0xc0) >> 6) : 0)];
+ iin++; /* 0 complete, iin=1 */
+ iout++;
+
+ if (iout >= *buflen || iin >= size)
+ break;
+ buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
+ iout++;
- if (len < 5)
- return 2;
+ if (iout >= *buflen || iin >= size) {
+ iout--; /* previous char is useless */
+ break;
+ }
+ buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
+ ((iin + 1 < size) ?
+ ((udata[iin + 1] & 0xf0) >> 4) : 0)];
+ iin++; /* 1 complete, iin=2 */
+ iout++;
+
+ if (iout >= *buflen || iin >= size)
+ break;
+ buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
+ ((iin + 1 < size) ?
+ ((udata[iin + 1] & 0x80) >> 7) : 0)];
+ iin++; /* 2 complete, iin=3 */
+ iout++;
- data[2] = ((REV32(t[3]) & 0x0f) << 4) |
- ((REV32(t[4]) & 0x1e) >> 1);
+ if (iout >= *buflen || iin >= size)
+ break;
+ buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
+ iout++;
- if (len < 7)
- return 3;
+ if (iout >= *buflen || iin >= size) {
+ iout--; /* previous char is useless */
+ break;
+ }
+ buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
+ ((iin + 1 < size) ?
+ ((udata[iin + 1] & 0xe0) >> 5) : 0)];
+ iin++; /* 3 complete, iin=4 */
+ iout++;
- data[3] = ((REV32(t[4]) & 0x01) << 7) |
- ((REV32(t[5]) & 0x1f) << 2) |
- ((REV32(t[6]) & 0x18) >> 3);
+ if (iout >= *buflen || iin >= size)
+ break;
+ buf[iout] = cb32[((udata[iin] & 0x1f))];
+ iin++; /* 4 complete, iin=5 */
+ iout++;
+ }
- if (len < 8)
- return 4;
+ buf[iout] = '\0';
- data[4] = ((REV32(t[6]) & 0x07) << 5) |
- ((REV32(t[7]) & 0x1f));
+ /* store number of bytes from data that was used */
+ *buflen = iin;
- return 5;
+ return iout;
}
+#define REV32(x) rev32[(int) (x)]
+
static int
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
+/*
+ * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
+ * Decoding stops early when *str contains \0.
+ * Illegal encoded chars are assumed to decode to zero.
+ *
+ * NOTE: *buf space should be at least 1 byte _more_ than *buflen
+ * to hold a trailing '\0' that is added (though *buf will usually
+ * contain full-binary data).
+ *
+ * return value : #bytes filled in buf (excluding \0)
+ */
{
- unsigned char *q;
- size_t newsize;
- size_t maxsize;
- const char *p;
- unsigned char c;
- int len;
- int i;
+ unsigned char *ubuf = (unsigned char *) buf;
+ int iout = 0; /* to-be-filled output byte */
+ int iin = 0; /* next input char to use in decoding */
- if (!reverse_init) {
- for (i = 0; i < 32; i++) {
- c = cb32[i];
- rev32[(int) c] = i;
- }
- reverse_init = 1;
- }
-
- /* chars needed to decode slen */
- newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
- /* encoded chars that fit in buf */
- maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
- /* if the buffer is too small, eat some of the data */
- if (*buflen < newsize) {
- slen = maxsize;
- }
+ base32_reverse_init ();
+
+ /* Note: Don't bother to optimize manually. GCC optimizes
+ better(!) when using simplistic array indexing. */
- q = buf;
- for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
- len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
- q += len;
- slen -= BLKSIZE_ENC;
-
- if (len < BLKSIZE_RAW)
+ while (1) {
+ if (iout >= *buflen || iin + 1 >= slen ||
+ str[iin] == '\0' || str[iin + 1] == '\0')
+ break;
+ ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
+ ((REV32(str[iin + 1]) & 0x1c) >> 2);
+ iin++; /* 0 used up, iin=1 */
+ iout++;
+
+ if (iout >= *buflen || iin + 2 >= slen ||
+ str[iin] == '\0' || str[iin + 1] == '\0' ||
+ str[iin + 2] == '\0')
+ break;
+ ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
+ ((REV32(str[iin + 1]) & 0x1f) << 1) |
+ ((REV32(str[iin + 2]) & 0x10) >> 4);
+ iin += 2; /* 1,2 used up, iin=3 */
+ iout++;
+
+ if (iout >= *buflen || iin + 1 >= slen ||
+ str[iin] == '\0' || str[iin + 1] == '\0')
break;
+ ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |
+ ((REV32(str[iin + 1]) & 0x1e) >> 1);
+ iin++; /* 3 used up, iin=4 */
+ iout++;
+
+ if (iout >= *buflen || iin + 2 >= slen ||
+ str[iin] == '\0' || str[iin + 1] == '\0' ||
+ str[iin + 2] == '\0')
+ break;
+ ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |
+ ((REV32(str[iin + 1]) & 0x1f) << 2) |
+ ((REV32(str[iin + 2]) & 0x18) >> 3);
+ iin += 2; /* 4,5 used up, iin=6 */
+ iout++;
+
+ if (iout >= *buflen || iin + 1 >= slen ||
+ str[iin] == '\0' || str[iin + 1] == '\0')
+ break;
+ ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |
+ ((REV32(str[iin + 1]) & 0x1f));
+ iin += 2; /* 6,7 used up, iin=8 */
+ iout++;
}
- *q = '\0';
-
- return q - (unsigned char *) buf;
-}
+ ubuf[iout] = '\0';
+
+ return iout;
+}