diff --git a/bench-src/Main.hs b/bench-src/Main.hs
new file mode 100644
--- /dev/null
+++ b/bench-src/Main.hs
@@ -0,0 +1,32 @@
+module Main where
+
+import Criterion.Main (bench, defaultMain, nf)
+import qualified Data.ByteString as BS
+import System.IO
+
+import qualified Codec.Binary.Base16Bench as B16B
+import qualified Codec.Binary.Base32Bench as B32B
+import qualified Codec.Binary.Base32HexBench as B32HB
+import qualified Codec.Binary.Base64Bench as B64B
+import qualified Codec.Binary.Base64UrlBench as B64UB
+import qualified Codec.Binary.Base85Bench as B85B
+import qualified Codec.Binary.QuotedPrintableBench as QPB
+import qualified Codec.Binary.UuBench as UuB
+import qualified Codec.Binary.XxBench as XxB
+import qualified Codec.Binary.YencBench as YB
+
+main :: IO ()
+main = do
+    h <- openFile "/dev/urandom" ReadMode
+    data1M <- BS.hGet h (1024 * 1024)
+    data10M <- BS.hGet h (10 * 1024 * 1024)
+    defaultMain $ B16B.mkBenchs data1M data10M ++
+        B32B.mkBenchs data1M data10M ++
+        B32HB.mkBenchs data1M data10M ++
+        B64B.mkBenchs data1M data10M ++
+        B64UB.mkBenchs data1M data10M ++
+        B85B.mkBenchs data1M data10M ++
+        QPB.mkBenchs data1M data10M ++
+        UuB.mkBenchs data1M data10M ++
+        XxB.mkBenchs data1M data10M ++
+        YB.mkBenchs data1M data10M
diff --git a/csrc/b16.c b/csrc/b16.c
deleted file mode 100644
--- a/csrc/b16.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "b16.h"
-
-static char const encmap[] = "0123456789ABCDEF";
-
-void b16_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-
-    assert(src || srclen == 0);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen + 1 < od; i++, *dstlen += 2) {
-        uint8_t o0 = src[i] >> 4, o1 = src[i] & 0x0f;
-        dst[*dstlen] = encmap[o0];
-        dst[*dstlen + 1] = encmap[o1];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-};
-
-int b16_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    assert(src || srclen == 0);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i += 2, (*dstlen)++) {
-        if(i + 1 >= srclen) { res = 1; break; }
-        uint8_t o0 = decmap[src[i]], o1 = decmap[src[i + 1]];
-        if((o0 | o1) & 0xf0) { res = 1; break; }
-        else dst[*dstlen] = o0 << 4 | o1;
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-
-    return(res);
-}
diff --git a/csrc/b16.h b/csrc/b16.h
deleted file mode 100644
--- a/csrc/b16.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B16_H_
-#define _B16_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b16_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b16_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-
-#endif
diff --git a/csrc/b32.c b/csrc/b32.c
deleted file mode 100644
--- a/csrc/b32.c
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "b32.h"
-
-static char const encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
-
-void b32_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i + 5 <= srclen && *dstlen + 8 <= od; i += 5, *dstlen += 8) {
-        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
-        o0 = src[i] >> 3;
-        o1 = ((src[i] << 2) | (src[i+1] >> 6)) & 0x1f;
-        o2 = (src[i+1] >> 1) & 0x1f;
-        o3 = ((src[i+1] << 4) | (src[i+2] >> 4)) & 0x1f;
-        o4 = ((src[i+2] << 1) | (src[i+3] >> 7)) & 0x1f;
-        o5 = (src[i+3] >>2) & 0x1f;
-        o6 = ((src[i+3] << 3) | (src[i+4] >> 5)) & 0x1f;
-        o7 = src[i+4] & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = encmap[o5];
-        *dst++ = encmap[o6];
-        *dst++ = encmap[o7];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int b32_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 3;
-        o1 = (src[0] << 2) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = src[1] << 4 & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 3:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
-        o4 = (src[2] << 1) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 4:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
-        o4 = ((src[2] << 1) | (src[3] >> 7)) & 0x1f;
-        o5 = (src[3] >>2) & 0x1f;
-        o6 = (src[3] << 3) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = encmap[o5];
-        *dst++ = encmap[o6];
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
-    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
-
-int b32_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i + 8 <= srclen && *dstlen + 5 <= od; i += 8, *dstlen += 5) {
-        uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        o4 = decmap[src[i+4]];
-        o5 = decmap[src[i+5]];
-        o6 = decmap[src[i+6]];
-        o7 = decmap[src[i+7]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6 | o7))) { // no illegal chars, and no '='
-            *dst++ = (o0 << 3) | (o1 >> 2);
-            *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-            *dst++ = (o3 << 4) | (o4 >> 1);
-            *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-            *dst++ = (o6 << 5) | o7;
-        } else if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7) // two legal chars, six '='
-            || !(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7) // four legal chars, four '='
-            || !(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7) // five legal chars, three '='
-            || !(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
-            res = 0;
-            break;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int b32_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    if(0 == srclen) {
-        *dstlen = 0;
-        return(0);
-    }
-    o0 = decmap[src[0]];
-    o1 = decmap[src[1]];
-    o2 = decmap[src[2]];
-    o3 = decmap[src[3]];
-    o4 = decmap[src[4]];
-    o5 = decmap[src[5]];
-    o6 = decmap[src[6]];
-    o7 = decmap[src[7]];
-    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) { // two legal chars, six '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6);
-        *dstlen = 1;
-    } else if(!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) { // four legal chars, four '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4);
-        *dstlen = 2;
-    }
-    else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) { // five legal chars, three '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4) | (o4 >> 1);
-        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-        *dstlen = 3;
-    } else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4) | (o4 >> 1);
-        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-        *dst++ = (o6 << 5);
-        *dstlen = 4;
-    } else
-        return(1);
-
-    return(0);
-}
diff --git a/csrc/b32.h b/csrc/b32.h
deleted file mode 100644
--- a/csrc/b32.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B32_H_
-#define _B32_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b32_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b32_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int b32_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b32_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/b32hex.c b/csrc/b32hex.c
deleted file mode 100644
--- a/csrc/b32hex.c
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "b32hex.h"
-
-static char const encmap[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
-
-void b32h_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i + 5 <= srclen && *dstlen + 8 <= od; i += 5, *dstlen += 8) {
-        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
-        o0 = src[i] >> 3;
-        o1 = ((src[i] << 2) | (src[i+1] >> 6)) & 0x1f;
-        o2 = (src[i+1] >> 1) & 0x1f;
-        o3 = ((src[i+1] << 4) | (src[i+2] >> 4)) & 0x1f;
-        o4 = ((src[i+2] << 1) | (src[i+3] >> 7)) & 0x1f;
-        o5 = (src[i+3] >>2) & 0x1f;
-        o6 = ((src[i+3] << 3) | (src[i+4] >> 5)) & 0x1f;
-        o7 = src[i+4] & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = encmap[o5];
-        *dst++ = encmap[o6];
-        *dst++ = encmap[o7];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int b32h_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 3;
-        o1 = (src[0] << 2) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = src[1] << 4 & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 3:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
-        o4 = (src[2] << 1) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    case 4:
-        o0 = src[0] >> 3;
-        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
-        o2 = (src[1] >> 1) & 0x1f;
-        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
-        o4 = ((src[2] << 1) | (src[3] >> 7)) & 0x1f;
-        o5 = (src[3] >>2) & 0x1f;
-        o6 = (src[3] << 3) & 0x1f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-        *dst++ = encmap[o4];
-        *dst++ = encmap[o5];
-        *dst++ = encmap[o6];
-        *dst++ = '=';
-        *dstlen = 8;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
-    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-    0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
-
-int b32h_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    for(i = 0, *dstlen = 0; i + 8 <= srclen && *dstlen + 5 <= od; i += 8, *dstlen += 5) {
-        uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        o4 = decmap[src[i+4]];
-        o5 = decmap[src[i+5]];
-        o6 = decmap[src[i+6]];
-        o7 = decmap[src[i+7]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6 | o7))) { // no illegal chars, and no '='
-            *dst++ = (o0 << 3) | (o1 >> 2);
-            *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-            *dst++ = (o3 << 4) | (o4 >> 1);
-            *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-            *dst++ = (o6 << 5) | o7;
-        } else if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7) // two legal chars, six '='
-            || !(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7) // four legal chars, four '='
-            || !(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7) // five legal chars, three '='
-            || !(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
-            res = 0;
-            break;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int b32h_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
-
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    if(0 == srclen) {
-        *dstlen = 0;
-        return(0);
-    }
-    o0 = decmap[src[0]];
-    o1 = decmap[src[1]];
-    o2 = decmap[src[2]];
-    o3 = decmap[src[3]];
-    o4 = decmap[src[4]];
-    o5 = decmap[src[5]];
-    o6 = decmap[src[6]];
-    o7 = decmap[src[7]];
-    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) { // two legal chars, six '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6);
-        *dstlen = 1;
-    } else if(!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) { // four legal chars, four '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4);
-        *dstlen = 2;
-    }
-    else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) { // five legal chars, three '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4) | (o4 >> 1);
-        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-        *dstlen = 3;
-    } else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
-        *dst++ = (o0 << 3) | (o1 >> 2);
-        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
-        *dst++ = (o3 << 4) | (o4 >> 1);
-        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
-        *dst++ = (o6 << 5);
-        *dstlen = 4;
-    } else
-        return(1);
-
-    return(0);
-}
diff --git a/csrc/b32hex.h b/csrc/b32hex.h
deleted file mode 100644
--- a/csrc/b32hex.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B32_H_
-#define _B32_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b32h_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b32h_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int b32h_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b32h_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/b64.c b/csrc/b64.c
deleted file mode 100644
--- a/csrc/b64.c
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "b64.h"
-
-static char const encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-void b64_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
-        int32_t o0, o1, o2, o3;
-        o0 = src[i] >> 2;
-        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
-        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
-        o3 = src[i+2] & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int b64_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 2;
-        o1 = (src[0] << 4) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 4;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 2;
-        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
-        o2 = (src[1] << 2) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = '=';
-        *dstlen = 4;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
-    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
-    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
-    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
-
-
-int b64_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
-        uint8_t o0, o1, o2, o3;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no '='
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dst++ = (o2 << 6) | o3;
-        } else if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3) // two legal chars, two '='
-            || !(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
-            res = 0;
-            break;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int b64_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    uint8_t o0, o1, o2, o3;
-
-    if(0 == srclen) {
-        *dstlen = 0;
-        return(0);
-    }
-    o0 = decmap[src[0]];
-    o1 = decmap[src[1]];
-    o2 = decmap[src[2]];
-    o3 = decmap[src[3]];
-    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) { // two legal chars, two '='
-        *dst++ = (o0 << 2) | (o1 >> 4);
-        *dstlen = 1;
-    } else if(!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dstlen = 2;
-    } else
-        return(1);
-
-    return(0);
-}
diff --git a/csrc/b64.h b/csrc/b64.h
deleted file mode 100644
--- a/csrc/b64.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B64_H_
-#define _B64_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b64_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b64_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int b64_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b64_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/b64url.c b/csrc/b64url.c
deleted file mode 100644
--- a/csrc/b64url.c
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "b64url.h"
-
-static char const encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
-void b64u_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
-        int32_t o0, o1, o2, o3;
-        o0 = src[i] >> 2;
-        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
-        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
-        o3 = src[i+2] & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int b64u_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 2;
-        o1 = (src[0] << 4) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = '=';
-        *dst++ = '=';
-        *dstlen = 4;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 2;
-        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
-        o2 = (src[1] << 2) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = '=';
-        *dstlen = 4;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80,
-    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
-    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x3f,
-    0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
-    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
-
-
-int b64u_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
-        uint8_t o0, o1, o2, o3;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no '='
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dst++ = (o2 << 6) | o3;
-        } else if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3) // two legal chars, two '='
-            || !(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
-            res = 0;
-            break;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int b64u_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    uint8_t o0, o1, o2, o3;
-
-    if(0 == srclen) {
-        *dstlen = 0;
-        return(0);
-    }
-    o0 = decmap[src[0]];
-    o1 = decmap[src[1]];
-    o2 = decmap[src[2]];
-    o3 = decmap[src[3]];
-    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) { // two legal chars, two '='
-        *dst++ = (o0 << 2) | (o1 >> 4);
-        *dstlen = 1;
-    } else if(!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dstlen = 2;
-    } else
-        return(1);
-
-    return(0);
-}
diff --git a/csrc/b64url.h b/csrc/b64url.h
deleted file mode 100644
--- a/csrc/b64url.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B64URL_H_
-#define _B64URL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b64u_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b64u_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int b64u_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b64u_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/b85.c b/csrc/b85.c
deleted file mode 100644
--- a/csrc/b85.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-#include <string.h>
-
-#include "b85.h"
-
-uint8_t zeroes[] = { 0, 0, 0, 0 };
-uint8_t spaces[] = { 0x20, 0x20, 0x20, 0x20 };
-
-void b85_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src ||  0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen < od; i += 4) {
-        if(memcmp(src + i, zeroes, 4) == 0) {
-            dst[*dstlen] = 'z';
-            *dstlen += 1;
-        } else if(memcmp(src + i, spaces, 4) == 0) {
-            dst[*dstlen] = 'y';
-            *dstlen += 1;
-        } else {
-            if(od < *dstlen + 5) goto exit;
-            uint32_t v = (src[i] << 24) | (src[i+1] << 16) | (src[i+2] << 8) | src[i+3];
-            dst[*dstlen + 4] = v % 85 + 33; v /= 85;
-            dst[*dstlen + 3] = v % 85 + 33; v /= 85;
-            dst[*dstlen + 2] = v % 85 + 33; v /= 85;
-            dst[*dstlen + 1] = v % 85 + 33; v /= 85;
-            dst[*dstlen] = v % 85 + 33;
-            *dstlen += 5;
-        }
-    }
-exit:
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int b85_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src ||  0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        uint32_t v;
-
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        v = (src[0] << 24) | 1;
-        v /= 85; v /= 85; v /= 85;
-        dst[1] = v % 85 + 33; v /= 85;
-        dst[0] = v % 85 + 33;
-        *dstlen = 2;
-        return(0);
-        break;
-    case 2:
-        v = (src[0] << 24) | (src[1] << 16) | 1;
-        v /= 85; v /= 85;
-        dst[2] = v % 85 + 33; v /= 85;
-        dst[1] = v % 85 + 33; v /= 85;
-        dst[0] = v % 85 + 33;
-        *dstlen = 3;
-        return(0);
-        break;
-    case 3:
-        v = (src[0] << 24) | (src[1] << 16) |(src[2] << 8) | 1;
-        v /= 85;
-        dst[3] = v % 85 + 33; v /= 85;
-        dst[2] = v % 85 + 33; v /= 85;
-        dst[1] = v % 85 + 33; v /= 85;
-        dst[0] = v % 85 + 33;
-        *dstlen = 4;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
-    0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
-    0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
-    0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-    0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-};
-
-int b85_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src ||  0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen + 4 <= od; *dstlen += 4) {
-        switch(src[i]) {
-            uint32_t o0, o1, o2, o3, o4, v;
-        case 'z':
-            dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0;
-            i++;
-            break;
-        case 'y':
-            dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0x20;
-            i++;
-            break;
-        default:
-            if(srclen < i + 5) { res = 0; goto exit; }
-            o0 = decmap[src[i]];
-            o1 = decmap[src[i + 1]];
-            o2 = decmap[src[i + 2]];
-            o3 = decmap[src[i + 3]];
-            o4 = decmap[src[i + 4]];
-            if(0x80 & (o0 | o1 | o2 | o3 | o4)) { res = 1; goto exit; }
-            v = o0 * 52200625; // 85 ** 4
-            v += o1 * 614125; // 85 ** 3
-            v += o2 * 7225; // 85 ** 2
-            v += o3 * 85; // 85 ** 1
-            v += o4; // 85 ** 0
-            dst[*dstlen + 3] = v & 0xff; v = v >> 8;
-            dst[*dstlen + 2] = v & 0xff; v = v >> 8;
-            dst[*dstlen + 1] = v & 0xff; v = v >> 8;
-            dst[*dstlen + 0] = v & 0xff;
-            i += 5;
-            break;
-        }
-    }
-exit:
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int b85_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src ||  0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        uint32_t o0, o1, o2, o3, o4, v;
-
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 2:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        o2 = decmap['u'];
-        o3 = decmap['u'];
-        o4 = decmap['u'];
-        if(0x80 & ( o0 | o1)) { return(1); }
-        v = o0 * 52200625; // 85 ** 4
-        v += o1 * 614125; // 85 ** 3
-        v += o2 * 7225; // 85 ** 2
-        v += o3 * 85; // 85 ** 1
-        v += o4; // 85 ** 0
-        v = v >> 24;
-        dst[0] = v & 0xff;
-        *dstlen = 1;
-        return(0);
-        break;
-    case 3:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        o2 = decmap[src[2]];
-        o3 = decmap['u'];
-        o4 = decmap['u'];
-        if(0x80 & ( o0 | o1 | o2)) { return(1); }
-        v = o0 * 52200625; // 85 ** 4
-        v += o1 * 614125; // 85 ** 3
-        v += o2 * 7225; // 85 ** 2
-        v += o3 * 85; // 85 ** 1
-        v += o4; // 85 ** 0
-        v = v >> 16;
-        dst[1] = v & 0xff; v = v >> 8;
-        dst[0] = v & 0xff;
-        *dstlen = 2;
-        return(0);
-        break;
-    case 4:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        o2 = decmap[src[2]];
-        o3 = decmap[src[3]];
-        o4 = decmap['u'];
-        if(0x80 & ( o0 | o1 | o2 | o3)) { return(1); }
-        v = o0 * 52200625; // 85 ** 4
-        v += o1 * 614125; // 85 ** 3
-        v += o2 * 7225; // 85 ** 2
-        v += o3 * 85; // 85 ** 1
-        v += o4; // 85 ** 0
-        v = v >> 8;
-        dst[2] = v & 0xff; v = v >> 8;
-        dst[1] = v & 0xff; v = v >> 8;
-        dst[0] = v & 0xff;
-        *dstlen = 3;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
diff --git a/csrc/b85.h b/csrc/b85.h
deleted file mode 100644
--- a/csrc/b85.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _B85_H_
-#define _B85_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void b85_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b85_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int b85_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int b85_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/codec.c b/csrc/codec.c
new file mode 100644
--- /dev/null
+++ b/csrc/codec.c
@@ -0,0 +1,1586 @@
+// Copyright: (c) Magnus Therning, 2012
+// License: BSD3, found in the LICENSE file
+
+#include <assert.h>
+#include <string.h>
+
+#include "codec.h"
+
+// {{{1 base16
+static char const b16_encmap[] = "0123456789ABCDEF";
+
+void b16_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+
+    assert(src || srclen == 0);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen + 1 < od; i++, *dstlen += 2) {
+        uint8_t o0 = src[i] >> 4, o1 = src[i] & 0x0f;
+        dst[*dstlen] = b16_encmap[o0];
+        dst[*dstlen + 1] = b16_encmap[o1];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+static uint8_t const b16_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+int b16_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    assert(src || srclen == 0);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i += 2, (*dstlen)++) {
+        if(i + 1 >= srclen) { res = 0; break; }
+        uint8_t o0 = b16_decmap[src[i]], o1 = b16_decmap[src[i + 1]];
+        if((o0 | o1) & 0xf0) { res = 1; break; }
+        else dst[*dstlen] = o0 << 4 | o1;
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+
+    return(res);
+}
+
+// {{{1 base32
+
+static char const b32_encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+void b32_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i + 5 <= srclen && *dstlen + 8 <= od; i += 5, *dstlen += 8) {
+        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
+        o0 = src[i] >> 3;
+        o1 = ((src[i] << 2) | (src[i+1] >> 6)) & 0x1f;
+        o2 = (src[i+1] >> 1) & 0x1f;
+        o3 = ((src[i+1] << 4) | (src[i+2] >> 4)) & 0x1f;
+        o4 = ((src[i+2] << 1) | (src[i+3] >> 7)) & 0x1f;
+        o5 = (src[i+3] >>2) & 0x1f;
+        o6 = ((src[i+3] << 3) | (src[i+4] >> 5)) & 0x1f;
+        o7 = src[i+4] & 0x1f;
+        *dst++ = b32_encmap[o0];
+        *dst++ = b32_encmap[o1];
+        *dst++ = b32_encmap[o2];
+        *dst++ = b32_encmap[o3];
+        *dst++ = b32_encmap[o4];
+        *dst++ = b32_encmap[o5];
+        *dst++ = b32_encmap[o6];
+        *dst++ = b32_encmap[o7];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int b32_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2, o3, o4, o5, o6;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 3;
+        o1 = (src[0] << 2) & 0x1f;
+        *dst++ = b32_encmap[o0];
+        *dst++ = b32_encmap[o1];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = src[1] << 4 & 0x1f;
+        *dst++ = b32_encmap[o0];
+        *dst++ = b32_encmap[o1];
+        *dst++ = b32_encmap[o2];
+        *dst++ = b32_encmap[o3];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 3:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
+        o4 = (src[2] << 1) & 0x1f;
+        *dst++ = b32_encmap[o0];
+        *dst++ = b32_encmap[o1];
+        *dst++ = b32_encmap[o2];
+        *dst++ = b32_encmap[o3];
+        *dst++ = b32_encmap[o4];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 4:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
+        o4 = ((src[2] << 1) | (src[3] >> 7)) & 0x1f;
+        o5 = (src[3] >>2) & 0x1f;
+        o6 = (src[3] << 3) & 0x1f;
+        *dst++ = b32_encmap[o0];
+        *dst++ = b32_encmap[o1];
+        *dst++ = b32_encmap[o2];
+        *dst++ = b32_encmap[o3];
+        *dst++ = b32_encmap[o4];
+        *dst++ = b32_encmap[o5];
+        *dst++ = b32_encmap[o6];
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const b32_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
+    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
+
+int b32_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i + 8 <= srclen && *dstlen + 5 <= od; i += 8, *dstlen += 5) {
+        uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
+
+        o0 = b32_decmap[src[i]];
+        o1 = b32_decmap[src[i+1]];
+        o2 = b32_decmap[src[i+2]];
+        o3 = b32_decmap[src[i+3]];
+        o4 = b32_decmap[src[i+4]];
+        o5 = b32_decmap[src[i+5]];
+        o6 = b32_decmap[src[i+6]];
+        o7 = b32_decmap[src[i+7]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6 | o7))) { // no illegal chars, and no '='
+            *dst++ = (o0 << 3) | (o1 >> 2);
+            *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+            *dst++ = (o3 << 4) | (o4 >> 1);
+            *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+            *dst++ = (o6 << 5) | o7;
+        } else if((!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) // two legal chars, six '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) // four legal chars, four '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) // five legal chars, three '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7))) { // seven legal chars, one '='
+            res = 0;
+            break;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int b32_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    if(0 == srclen) {
+        *dstlen = 0;
+        return(0);
+    }
+    o0 = b32_decmap[src[0]];
+    o1 = b32_decmap[src[1]];
+    o2 = b32_decmap[src[2]];
+    o3 = b32_decmap[src[3]];
+    o4 = b32_decmap[src[4]];
+    o5 = b32_decmap[src[5]];
+    o6 = b32_decmap[src[6]];
+    o7 = b32_decmap[src[7]];
+    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) { // two legal chars, six '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6);
+        *dstlen = 1;
+    } else if(!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) { // four legal chars, four '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4);
+        *dstlen = 2;
+    }
+    else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) { // five legal chars, three '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4) | (o4 >> 1);
+        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+        *dstlen = 3;
+    } else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4) | (o4 >> 1);
+        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+        *dst++ = (o6 << 5);
+        *dstlen = 4;
+    } else
+        return(1);
+
+    return(0);
+}
+
+// {{{1 base32hex
+
+static char const b32h_encmap[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+void b32h_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i + 5 <= srclen && *dstlen + 8 <= od; i += 5, *dstlen += 8) {
+        int32_t o0, o1, o2, o3, o4, o5, o6, o7;
+        o0 = src[i] >> 3;
+        o1 = ((src[i] << 2) | (src[i+1] >> 6)) & 0x1f;
+        o2 = (src[i+1] >> 1) & 0x1f;
+        o3 = ((src[i+1] << 4) | (src[i+2] >> 4)) & 0x1f;
+        o4 = ((src[i+2] << 1) | (src[i+3] >> 7)) & 0x1f;
+        o5 = (src[i+3] >>2) & 0x1f;
+        o6 = ((src[i+3] << 3) | (src[i+4] >> 5)) & 0x1f;
+        o7 = src[i+4] & 0x1f;
+        *dst++ = b32h_encmap[o0];
+        *dst++ = b32h_encmap[o1];
+        *dst++ = b32h_encmap[o2];
+        *dst++ = b32h_encmap[o3];
+        *dst++ = b32h_encmap[o4];
+        *dst++ = b32h_encmap[o5];
+        *dst++ = b32h_encmap[o6];
+        *dst++ = b32h_encmap[o7];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int b32h_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2, o3, o4, o5, o6;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 3;
+        o1 = (src[0] << 2) & 0x1f;
+        *dst++ = b32h_encmap[o0];
+        *dst++ = b32h_encmap[o1];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = src[1] << 4 & 0x1f;
+        *dst++ = b32h_encmap[o0];
+        *dst++ = b32h_encmap[o1];
+        *dst++ = b32h_encmap[o2];
+        *dst++ = b32h_encmap[o3];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 3:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
+        o4 = (src[2] << 1) & 0x1f;
+        *dst++ = b32h_encmap[o0];
+        *dst++ = b32h_encmap[o1];
+        *dst++ = b32h_encmap[o2];
+        *dst++ = b32h_encmap[o3];
+        *dst++ = b32h_encmap[o4];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    case 4:
+        o0 = src[0] >> 3;
+        o1 = ((src[0] << 2) | (src[1] >> 6)) & 0x1f;
+        o2 = (src[1] >> 1) & 0x1f;
+        o3 = ((src[1] << 4) | (src[2] >> 4)) & 0x1f;
+        o4 = ((src[2] << 1) | (src[3] >> 7)) & 0x1f;
+        o5 = (src[3] >>2) & 0x1f;
+        o6 = (src[3] << 3) & 0x1f;
+        *dst++ = b32h_encmap[o0];
+        *dst++ = b32h_encmap[o1];
+        *dst++ = b32h_encmap[o2];
+        *dst++ = b32h_encmap[o3];
+        *dst++ = b32h_encmap[o4];
+        *dst++ = b32h_encmap[o5];
+        *dst++ = b32h_encmap[o6];
+        *dst++ = '=';
+        *dstlen = 8;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const b32h_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
+    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
+
+int b32h_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    for(i = 0, *dstlen = 0; i + 8 <= srclen && *dstlen + 5 <= od; i += 8, *dstlen += 5) {
+        uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
+
+        o0 = b32h_decmap[src[i]];
+        o1 = b32h_decmap[src[i+1]];
+        o2 = b32h_decmap[src[i+2]];
+        o3 = b32h_decmap[src[i+3]];
+        o4 = b32h_decmap[src[i+4]];
+        o5 = b32h_decmap[src[i+5]];
+        o6 = b32h_decmap[src[i+6]];
+        o7 = b32h_decmap[src[i+7]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6 | o7))) { // no illegal chars, and no '='
+            *dst++ = (o0 << 3) | (o1 >> 2);
+            *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+            *dst++ = (o3 << 4) | (o4 >> 1);
+            *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+            *dst++ = (o6 << 5) | o7;
+        } else if((!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) // two legal chars, six '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) // four legal chars, four '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) // five legal chars, three '='
+            || (!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7))) { // seven legal chars, one '='
+            res = 0;
+            break;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int b32h_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    uint8_t o0, o1, o2, o3, o4, o5, o6, o7;
+
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    if(0 == srclen) {
+        *dstlen = 0;
+        return(0);
+    }
+    o0 = b32h_decmap[src[0]];
+    o1 = b32h_decmap[src[1]];
+    o2 = b32h_decmap[src[2]];
+    o3 = b32h_decmap[src[3]];
+    o4 = b32h_decmap[src[4]];
+    o5 = b32h_decmap[src[5]];
+    o6 = b32h_decmap[src[6]];
+    o7 = b32h_decmap[src[7]];
+    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3 & o4 & o5 & o6 & o7)) { // two legal chars, six '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6);
+        *dstlen = 1;
+    } else if(!(0xc0 & (o0 | o1 | o2 | o3)) && (0x40 & o4 & o5 & o6 & o7)) { // four legal chars, four '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4);
+        *dstlen = 2;
+    }
+    else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4)) && (0x40 & o5 & o6 & o7)) { // five legal chars, three '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4) | (o4 >> 1);
+        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+        *dstlen = 3;
+    } else if(!(0xc0 & (o0 | o1 | o2 | o3 | o4 | o5 | o6)) && (0x40 & o7)) { // seven legal chars, one '='
+        *dst++ = (o0 << 3) | (o1 >> 2);
+        *dst++ = (o1 << 6) | (o2 << 1) | (o3 >> 4);
+        *dst++ = (o3 << 4) | (o4 >> 1);
+        *dst++ = (o4 << 7) | (o5 << 2) | (o6 >> 3);
+        *dst++ = (o6 << 5);
+        *dstlen = 4;
+    } else
+        return(1);
+
+    return(0);
+}
+
+// {{{1 base64
+
+static char const b64_encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+void b64_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
+        int32_t o0, o1, o2, o3;
+        o0 = src[i] >> 2;
+        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
+        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
+        o3 = src[i+2] & 0x3f;
+        *dst++ = b64_encmap[o0];
+        *dst++ = b64_encmap[o1];
+        *dst++ = b64_encmap[o2];
+        *dst++ = b64_encmap[o3];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int b64_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 2;
+        o1 = (src[0] << 4) & 0x3f;
+        *dst++ = b64_encmap[o0];
+        *dst++ = b64_encmap[o1];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 4;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 2;
+        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
+        o2 = (src[1] << 2) & 0x3f;
+        *dst++ = b64_encmap[o0];
+        *dst++ = b64_encmap[o1];
+        *dst++ = b64_encmap[o2];
+        *dst++ = '=';
+        *dstlen = 4;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const b64_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
+    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
+    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
+
+
+int b64_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
+        uint8_t o0, o1, o2, o3;
+
+        o0 = b64_decmap[src[i]];
+        o1 = b64_decmap[src[i+1]];
+        o2 = b64_decmap[src[i+2]];
+        o3 = b64_decmap[src[i+3]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no '='
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dst++ = (o2 << 6) | o3;
+        } else if((!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) // two legal chars, two '='
+            || (!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3))) { // three legal chars, one '='
+            res = 0;
+            break;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int b64_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    uint8_t o0, o1, o2, o3;
+
+    if(0 == srclen) {
+        *dstlen = 0;
+        return(0);
+    }
+    o0 = b64_decmap[src[0]];
+    o1 = b64_decmap[src[1]];
+    o2 = b64_decmap[src[2]];
+    o3 = b64_decmap[src[3]];
+    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) { // two legal chars, two '='
+        *dst++ = (o0 << 2) | (o1 >> 4);
+        *dstlen = 1;
+    } else if(!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dstlen = 2;
+    } else
+        return(1);
+
+    return(0);
+}
+
+// {{{1 base64url
+
+static char const b64u_encmap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+void b64u_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
+        int32_t o0, o1, o2, o3;
+        o0 = src[i] >> 2;
+        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
+        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
+        o3 = src[i+2] & 0x3f;
+        *dst++ = b64u_encmap[o0];
+        *dst++ = b64u_encmap[o1];
+        *dst++ = b64u_encmap[o2];
+        *dst++ = b64u_encmap[o3];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int b64u_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 2;
+        o1 = (src[0] << 4) & 0x3f;
+        *dst++ = b64u_encmap[o0];
+        *dst++ = b64u_encmap[o1];
+        *dst++ = '=';
+        *dst++ = '=';
+        *dstlen = 4;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 2;
+        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
+        o2 = (src[1] << 2) & 0x3f;
+        *dst++ = b64u_encmap[o0];
+        *dst++ = b64u_encmap[o1];
+        *dst++ = b64u_encmap[o2];
+        *dst++ = '=';
+        *dstlen = 4;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const b64u_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80,
+    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
+    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x3f,
+    0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
+
+
+int b64u_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
+        uint8_t o0, o1, o2, o3;
+
+        o0 = b64u_decmap[src[i]];
+        o1 = b64u_decmap[src[i+1]];
+        o2 = b64u_decmap[src[i+2]];
+        o3 = b64u_decmap[src[i+3]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no '='
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dst++ = (o2 << 6) | o3;
+        } else if((!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) // two legal chars, two '='
+            || (!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3))) { // three legal chars, one '='
+            res = 0;
+            break;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int b64u_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    uint8_t o0, o1, o2, o3;
+
+    if(0 == srclen) {
+        *dstlen = 0;
+        return(0);
+    }
+    o0 = b64u_decmap[src[0]];
+    o1 = b64u_decmap[src[1]];
+    o2 = b64u_decmap[src[2]];
+    o3 = b64u_decmap[src[3]];
+    if(!(0xc0 & (o0 | o1)) && (0x40 & o2 & o3)) { // two legal chars, two '='
+        *dst++ = (o0 << 2) | (o1 >> 4);
+        *dstlen = 1;
+    } else if(!(0xc0 & (o0 | o1 | o2)) && (0x40 & o3)) { // three legal chars, one '='
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dstlen = 2;
+    } else
+        return(1);
+
+    return(0);
+}
+
+// {{{1 base85
+
+uint8_t b85_zeroes[] = { 0, 0, 0, 0 };
+uint8_t b85_spaces[] = { 0x20, 0x20, 0x20, 0x20 };
+
+void b85_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src ||  0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen < od; i += 4) {
+        if(memcmp(src + i, b85_zeroes, 4) == 0) {
+            dst[*dstlen] = 'z';
+            *dstlen += 1;
+        } else if(memcmp(src + i, b85_spaces, 4) == 0) {
+            dst[*dstlen] = 'y';
+            *dstlen += 1;
+        } else {
+            if(od < *dstlen + 5) goto exit;
+            uint32_t v = (src[i] << 24) | (src[i+1] << 16) | (src[i+2] << 8) | src[i+3];
+            dst[*dstlen + 4] = v % 85 + 33; v /= 85;
+            dst[*dstlen + 3] = v % 85 + 33; v /= 85;
+            dst[*dstlen + 2] = v % 85 + 33; v /= 85;
+            dst[*dstlen + 1] = v % 85 + 33; v /= 85;
+            dst[*dstlen] = v % 85 + 33;
+            *dstlen += 5;
+        }
+    }
+exit:
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int b85_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src ||  0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        uint32_t v;
+
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        v = (src[0] << 24) | 1;
+        v /= 85; v /= 85; v /= 85;
+        dst[1] = v % 85 + 33; v /= 85;
+        dst[0] = v % 85 + 33;
+        *dstlen = 2;
+        return(0);
+        break;
+    case 2:
+        v = (src[0] << 24) | (src[1] << 16) | 1;
+        v /= 85; v /= 85;
+        dst[2] = v % 85 + 33; v /= 85;
+        dst[1] = v % 85 + 33; v /= 85;
+        dst[0] = v % 85 + 33;
+        *dstlen = 3;
+        return(0);
+        break;
+    case 3:
+        v = (src[0] << 24) | (src[1] << 16) |(src[2] << 8) | 1;
+        v /= 85;
+        dst[3] = v % 85 + 33; v /= 85;
+        dst[2] = v % 85 + 33; v /= 85;
+        dst[1] = v % 85 + 33; v /= 85;
+        dst[0] = v % 85 + 33;
+        *dstlen = 4;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+static uint8_t const b85_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+    0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+    0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
+    0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+int b85_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src ||  0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen + 4 <= od; *dstlen += 4) {
+        switch(src[i]) {
+            uint32_t o0, o1, o2, o3, o4, v;
+        case 'z':
+            dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0;
+            i++;
+            break;
+        case 'y':
+            dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0x20;
+            i++;
+            break;
+        default:
+            if(srclen < i + 5) { res = 0; goto exit; }
+            o0 = b85_decmap[src[i]];
+            o1 = b85_decmap[src[i + 1]];
+            o2 = b85_decmap[src[i + 2]];
+            o3 = b85_decmap[src[i + 3]];
+            o4 = b85_decmap[src[i + 4]];
+            if(0x80 & (o0 | o1 | o2 | o3 | o4)) { res = 1; goto exit; }
+            v = o0 * 52200625; // 85 ** 4
+            v += o1 * 614125; // 85 ** 3
+            v += o2 * 7225; // 85 ** 2
+            v += o3 * 85; // 85 ** 1
+            v += o4; // 85 ** 0
+            dst[*dstlen + 3] = v & 0xff; v = v >> 8;
+            dst[*dstlen + 2] = v & 0xff; v = v >> 8;
+            dst[*dstlen + 1] = v & 0xff; v = v >> 8;
+            dst[*dstlen + 0] = v & 0xff;
+            i += 5;
+            break;
+        }
+    }
+exit:
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int b85_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src ||  0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        uint32_t o0, o1, o2, o3, o4, v;
+
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 2:
+        o0 = b85_decmap[src[0]];
+        o1 = b85_decmap[src[1]];
+        o2 = b85_decmap[(uint8_t)'u'];
+        o3 = b85_decmap[(uint8_t)'u'];
+        o4 = b85_decmap[(uint8_t)'u'];
+        if(0x80 & ( o0 | o1)) { return(1); }
+        v = o0 * 52200625; // 85 ** 4
+        v += o1 * 614125; // 85 ** 3
+        v += o2 * 7225; // 85 ** 2
+        v += o3 * 85; // 85 ** 1
+        v += o4; // 85 ** 0
+        v = v >> 24;
+        dst[0] = v & 0xff;
+        *dstlen = 1;
+        return(0);
+        break;
+    case 3:
+        o0 = b85_decmap[src[0]];
+        o1 = b85_decmap[src[1]];
+        o2 = b85_decmap[src[2]];
+        o3 = b85_decmap[(uint8_t)'u'];
+        o4 = b85_decmap[(uint8_t)'u'];
+        if(0x80 & ( o0 | o1 | o2)) { return(1); }
+        v = o0 * 52200625; // 85 ** 4
+        v += o1 * 614125; // 85 ** 3
+        v += o2 * 7225; // 85 ** 2
+        v += o3 * 85; // 85 ** 1
+        v += o4; // 85 ** 0
+        v = v >> 16;
+        dst[1] = v & 0xff; v = v >> 8;
+        dst[0] = v & 0xff;
+        *dstlen = 2;
+        return(0);
+        break;
+    case 4:
+        o0 = b85_decmap[src[0]];
+        o1 = b85_decmap[src[1]];
+        o2 = b85_decmap[src[2]];
+        o3 = b85_decmap[src[3]];
+        o4 = b85_decmap[(uint8_t)'u'];
+        if(0x80 & ( o0 | o1 | o2 | o3)) { return(1); }
+        v = o0 * 52200625; // 85 ** 4
+        v += o1 * 614125; // 85 ** 3
+        v += o2 * 7225; // 85 ** 2
+        v += o3 * 85; // 85 ** 1
+        v += o4; // 85 ** 0
+        v = v >> 8;
+        dst[2] = v & 0xff; v = v >> 8;
+        dst[1] = v & 0xff; v = v >> 8;
+        dst[0] = v & 0xff;
+        *dstlen = 3;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// {{{1 quoted-printable
+
+static char const qp_encmap[] = "0123456789ABCDEF";
+
+void qp_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || srclen == 0);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
+        if((33 <= src[i] && src[i] <= 60) ||
+            (62 <= src[i] && src[i] <= 126)) {
+            dst[*dstlen] = src[i];
+        } else {
+            uint8_t o0 = src[i] >> 4, o1 = src[i] & 0x0f;
+            if(*dstlen + 3 >= od) goto exit;
+            dst[*dstlen] = '=';
+            dst[*dstlen + 1] = qp_encmap[o0];
+            dst[*dstlen + 2] = qp_encmap[o1];
+            *dstlen += 2;
+        }
+    }
+
+exit:
+    *rem = src + i;
+    *remlen = srclen -i;
+}
+
+static uint8_t const qp_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+int qp_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || srclen == 0);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
+        if((33 <= src[i] && src[i] <= 60) ||
+            (62 <= src[i] && src[i] <= 126)) {
+            dst[*dstlen] = src[i];
+        } else if('=' == src[i]) {
+            if(i + 2 >= srclen) { res = 0; goto exit; }
+            uint8_t o0 = qp_decmap[src[i + 1]], o1 = qp_decmap[src[i + 2]];
+            if((o0 | o1) & 0xf0) { res = 1; break; }
+            dst[*dstlen] = o0 << 4 | o1;
+            i += 2;
+        } else { res = 1; goto exit; }
+    }
+
+exit:
+    *rem = src + i;
+    *remlen = srclen -i;
+
+    return(res);
+}
+
+// {{{1 uu
+
+static char const uu_encmap[] = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
+
+void uu_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
+        int32_t o0, o1, o2, o3;
+        o0 = src[i] >> 2;
+        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
+        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
+        o3 = src[i+2] & 0x3f;
+        *dst++ = uu_encmap[o0];
+        *dst++ = uu_encmap[o1];
+        *dst++ = uu_encmap[o2];
+        *dst++ = uu_encmap[o3];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int uu_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 2;
+        o1 = (src[0] << 4) & 0x3f;
+        *dst++ = uu_encmap[o0];
+        *dst++ = uu_encmap[o1];
+        *dstlen = 2;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 2;
+        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
+        o2 = (src[1] << 2) & 0x3f;
+        *dst++ = uu_encmap[o0];
+        *dst++ = uu_encmap[o1];
+        *dst++ = uu_encmap[o2];
+        *dstlen = 3;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const uu_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x40, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 
+    0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
+
+int uu_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
+        uint8_t o0, o1, o2, o3;
+
+        o0 = uu_decmap[src[i]];
+        o1 = uu_decmap[src[i+1]];
+        o2 = uu_decmap[src[i+2]];
+        o3 = uu_decmap[src[i+3]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no ' '
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dst++ = (o2 << 6) | o3;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int uu_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    uint8_t o0, o1, o2;
+
+    switch(srclen) {
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 2:
+        o0 = uu_decmap[src[0]];
+        o1 = uu_decmap[src[1]];
+        if(0xc0 & (o0 | o1)) goto error;
+        dst[0] = (o0 << 2) | (o1 >> 4);
+        *dstlen = 1;
+        return(0);
+        break;
+    case 3:
+        o0 = uu_decmap[src[0]];
+        o1 = uu_decmap[src[1]];
+        o2 = uu_decmap[src[2]];
+        if(0xc0 & (o0 | o1 | o2)) goto error;
+        dst[0] = (o0 << 2) | (o1 >> 4);
+        dst[1] = (o1 << 4) | (o2 >> 2);
+        *dstlen = 2;
+        return(0);
+        break;
+    }
+
+error:
+    *dstlen = 0;
+    return(1);
+}
+
+// {{{1 xx
+
+static char const xx_encmap[] = "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void xx_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
+        int32_t o0, o1, o2, o3;
+        o0 = src[i] >> 2;
+        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
+        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
+        o3 = src[i+2] & 0x3f;
+        *dst++ = xx_encmap[o0];
+        *dst++ = xx_encmap[o1];
+        *dst++ = xx_encmap[o2];
+        *dst++ = xx_encmap[o3];
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int xx_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    switch(srclen) {
+        int32_t o0, o1, o2;
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 1:
+        o0 = src[0] >> 2;
+        o1 = (src[0] << 4) & 0x3f;
+        *dst++ = xx_encmap[o0];
+        *dst++ = xx_encmap[o1];
+        *dstlen = 2;
+        return(0);
+        break;
+    case 2:
+        o0 = src[0] >> 2;
+        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
+        o2 = (src[1] << 2) & 0x3f;
+        *dst++ = xx_encmap[o0];
+        *dst++ = xx_encmap[o1];
+        *dst++ = xx_encmap[o2];
+        *dstlen = 3;
+        return(0);
+        break;
+    default:
+        return(1);
+        break;
+    }
+}
+
+// decode map, 0x80 = not allowed, 0x40 = end char
+static uint8_t const xx_decmap[] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x01, 0x80, 0x80, 
+    0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 
+    0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 
+    0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+int xx_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+    int res = 0;
+
+    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
+        uint8_t o0, o1, o2, o3;
+
+        o0 = xx_decmap[src[i]];
+        o1 = xx_decmap[src[i+1]];
+        o2 = xx_decmap[src[i+2]];
+        o3 = xx_decmap[src[i+3]];
+        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no ' '
+            *dst++ = (o0 << 2) | (o1 >> 4);
+            *dst++ = (o1 << 4) | (o2 >> 2);
+            *dst++ = (o2 << 6) | o3;
+        } else {
+            res = 1;
+            break;
+        }
+    }
+
+    *rem = src + i;
+    *remlen = srclen - i;
+    return(res);
+}
+
+int xx_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+
+    uint8_t o0, o1, o2;
+
+    switch(srclen) {
+    case 0:
+        *dstlen = 0;
+        return(0);
+        break;
+    case 2:
+        o0 = xx_decmap[src[0]];
+        o1 = xx_decmap[src[1]];
+        if(0xc0 & (o0 | o1)) goto error;
+        dst[0] = (o0 << 2) | (o1 >> 4);
+        *dstlen = 1;
+        return(0);
+        break;
+    case 3:
+        o0 = xx_decmap[src[0]];
+        o1 = xx_decmap[src[1]];
+        o2 = xx_decmap[src[2]];
+        if(0xc0 & (o0 | o1 | o2)) goto error;
+        dst[0] = (o0 << 2) | (o1 >> 4);
+        dst[1] = (o1 << 4) | (o2 >> 2);
+        *dstlen = 2;
+        return(0);
+        break;
+    }
+
+error:
+    *dstlen = 0;
+    return(1);
+}
+
+// {{{1 yenc
+
+void y_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
+        switch(src[i]) {
+        case 19:
+        case 214:
+        case 224:
+        case 227:
+            if(*dstlen >= od - 1) goto exit; // is there room for 2 chars in dst?
+            dst[(*dstlen)++] = 61;
+            dst[*dstlen] = src[i] + 106;
+            break;
+        default:
+            dst[*dstlen] = src[i] + 42;
+            break;
+        }
+    }
+
+exit:
+    *rem = src + i;
+    *remlen = srclen - i;
+}
+
+int y_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen)
+{
+    assert(src || 0 == srclen);
+    assert(dst);
+    assert(dstlen);
+    assert(rem);
+    assert(remlen);
+
+    size_t od = *dstlen, i;
+
+    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
+        if(61 == src[i]) {
+            if(srclen <= i + 1) goto exit;
+            dst[*dstlen] = src[++i] - 106;
+        } else
+            dst[*dstlen] = src[i] - 42;
+    }
+
+exit:
+    *rem = src + i;
+    *remlen = srclen - i;
+
+    return(0);
+}
diff --git a/csrc/codec.h b/csrc/codec.h
new file mode 100644
--- /dev/null
+++ b/csrc/codec.h
@@ -0,0 +1,108 @@
+// Copyright: (c) Magnus Therning, 2012, 2013
+// License: BSD3, found in the LICENSE file
+
+#ifndef _CODEC_H_
+#define _CODEC_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+void b16_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b16_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+
+void b32_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b32_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int b32_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b32_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void b32h_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b32h_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int b32h_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b32h_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void b64_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b64_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int b64_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b64_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void b64u_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b64u_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int b64u_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b64u_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void b85_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b85_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int b85_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int b85_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void qp_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int qp_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+
+void uu_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int uu_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int uu_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int uu_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void xx_enc_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int xx_enc_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+int xx_dec_part(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int xx_dec_final(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen);
+
+void y_enc(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+int y_dec(uint8_t const *src, size_t srclen,
+    uint8_t *dst, size_t *dstlen,
+    uint8_t const **rem, size_t *remlen);
+
+#endif
diff --git a/csrc/qp.c b/csrc/qp.c
deleted file mode 100644
--- a/csrc/qp.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "qp.h"
-
-static char const encmap[] = "0123456789ABCDEF";
-
-void qp_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || srclen == 0);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
-        if((33 <= src[i] && src[i] <= 60) ||
-            (62 <= src[i] && src[i] <= 126)) {
-            dst[*dstlen] = src[i];
-        } else {
-            uint8_t o0 = src[i] >> 4, o1 = src[i] & 0x0f;
-            if(*dstlen + 3 >= od) goto exit;
-            dst[*dstlen] = '=';
-            dst[*dstlen + 1] = encmap[o0];
-            dst[*dstlen + 2] = encmap[o1];
-            *dstlen += 2;
-        }
-    }
-
-exit:
-    *rem = src + i;
-    *remlen = srclen -i;
-}
-
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-};
-
-int qp_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || srclen == 0);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
-        if((33 <= src[i] && src[i] <= 60) ||
-            (62 <= src[i] && src[i] <= 126)) {
-            dst[*dstlen] = src[i];
-        } else if('=' == src[i]) {
-            if(i + 2 >= srclen) { res = 1; goto exit; }
-            uint8_t o0 = decmap[src[i + 1]], o1 = decmap[src[i + 2]];
-            if((o0 | o1) & 0xf0) { res = 1; break; }
-            dst[*dstlen] = o0 << 4 | o1;
-            i += 2;
-        } else { res = 1; goto exit; }
-    }
-
-exit:
-    *rem = src + i;
-    *remlen = srclen -i;
-
-    return(res);
-}
diff --git a/csrc/qp.h b/csrc/qp.h
deleted file mode 100644
--- a/csrc/qp.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _QP_H_
-#define _QP_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void qp_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int qp_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-
-#endif
diff --git a/csrc/uu.c b/csrc/uu.c
deleted file mode 100644
--- a/csrc/uu.c
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "uu.h"
-
-static char const encmap[] = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
-
-void uu_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
-        int32_t o0, o1, o2, o3;
-        o0 = src[i] >> 2;
-        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
-        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
-        o3 = src[i+2] & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int uu_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 2;
-        o1 = (src[0] << 4) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dstlen = 2;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 2;
-        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
-        o2 = (src[1] << 2) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dstlen = 3;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x40, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 
-    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 
-    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 
-    0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
-
-int uu_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
-        uint8_t o0, o1, o2, o3;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no ' '
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dst++ = (o2 << 6) | o3;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int uu_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    uint8_t o0, o1, o2, o3;
-
-    switch(srclen) {
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 2:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        if(0xc0 & (o0 | o1)) goto error;
-        dst[0] = (o0 << 2) | (o1 >> 4);
-        *dstlen = 1;
-        return(0);
-        break;
-    case 3:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        o2 = decmap[src[2]];
-        if(0xc0 & (o0 | o1 | o2)) goto error;
-        dst[0] = (o0 << 2) | (o1 >> 4);
-        dst[1] = (o1 << 4) | (o2 >> 2);
-        *dstlen = 2;
-        return(0);
-        break;
-    }
-
-error:
-    *dstlen = 0;
-    return(1);
-}
diff --git a/csrc/uu.h b/csrc/uu.h
deleted file mode 100644
--- a/csrc/uu.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _UU_H_
-#define _UU_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void uu_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int uu_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int uu_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int uu_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/xx.c b/csrc/xx.c
deleted file mode 100644
--- a/csrc/xx.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "xx.h"
-
-static char const encmap[] = "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-void xx_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i + 3 <= srclen && *dstlen + 4 <= od; i += 3, *dstlen += 4) {
-        int32_t o0, o1, o2, o3;
-        o0 = src[i] >> 2;
-        o1 = ((src[i] << 4) | (src[i+1] >> 4)) & 0x3f;
-        o2 = ((src[i+1] << 2) | (src[i+2] >> 6)) & 0x3f;
-        o3 = src[i+2] & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dst++ = encmap[o3];
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int xx_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    switch(srclen) {
-        int32_t o0, o1, o2, o3;
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 1:
-        o0 = src[0] >> 2;
-        o1 = (src[0] << 4) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dstlen = 2;
-        return(0);
-        break;
-    case 2:
-        o0 = src[0] >> 2;
-        o1 = ((src[0] << 4) | (src[1] >> 4)) & 0x3f;
-        o2 = (src[1] << 2) & 0x3f;
-        *dst++ = encmap[o0];
-        *dst++ = encmap[o1];
-        *dst++ = encmap[o2];
-        *dstlen = 3;
-        return(0);
-        break;
-    default:
-        return(1);
-        break;
-    }
-}
-
-// decode map, 0x80 = not allowed, 0x40 = end char
-static uint8_t const decmap[] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x01, 0x80, 0x80, 
-    0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 
-    0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 
-    0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-};
-
-int xx_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-    int res = 0;
-
-    for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen + 3 <= od; i += 4, *dstlen += 3) {
-        uint8_t o0, o1, o2, o3;
-
-        o0 = decmap[src[i]];
-        o1 = decmap[src[i+1]];
-        o2 = decmap[src[i+2]];
-        o3 = decmap[src[i+3]];
-        if(!(0xc0 & (o0 | o1 | o2 | o3))) { // no illegal chars, and no ' '
-            *dst++ = (o0 << 2) | (o1 >> 4);
-            *dst++ = (o1 << 4) | (o2 >> 2);
-            *dst++ = (o2 << 6) | o3;
-        } else {
-            res = 1;
-            break;
-        }
-    }
-
-    *rem = src + i;
-    *remlen = srclen - i;
-    return(res);
-}
-
-int xx_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-
-    uint8_t o0, o1, o2, o3;
-
-    switch(srclen) {
-    case 0:
-        *dstlen = 0;
-        return(0);
-        break;
-    case 2:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        if(0xc0 & (o0 | o1)) goto error;
-        dst[0] = (o0 << 2) | (o1 >> 4);
-        *dstlen = 1;
-        return(0);
-        break;
-    case 3:
-        o0 = decmap[src[0]];
-        o1 = decmap[src[1]];
-        o2 = decmap[src[2]];
-        if(0xc0 & (o0 | o1 | o2)) goto error;
-        dst[0] = (o0 << 2) | (o1 >> 4);
-        dst[1] = (o1 << 4) | (o2 >> 2);
-        *dstlen = 2;
-        return(0);
-        break;
-    }
-
-error:
-    *dstlen = 0;
-    return(1);
-}
diff --git a/csrc/xx.h b/csrc/xx.h
deleted file mode 100644
--- a/csrc/xx.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _XX_H_
-#define _XX_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void xx_enc_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int xx_enc_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-int xx_dec_part(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int xx_dec_final(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen);
-
-#endif
diff --git a/csrc/yenc.c b/csrc/yenc.c
deleted file mode 100644
--- a/csrc/yenc.c
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#include <assert.h>
-
-#include "yenc.h"
-
-void y_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
-        switch(src[i]) {
-        case 19:
-        case 214:
-        case 224:
-        case 227:
-            if(*dstlen >= od - 1) goto exit; // is there room for 2 chars in dst?
-            dst[(*dstlen)++] = 61;
-            dst[*dstlen] = src[i] + 106;
-            break;
-        default:
-            dst[*dstlen] = src[i] + 42;
-            break;
-        }
-    }
-
-exit:
-    *rem = src + i;
-    *remlen = srclen - i;
-}
-
-int y_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen)
-{
-    assert(src || 0 == srclen);
-    assert(dst);
-    assert(dstlen);
-    assert(rem);
-    assert(remlen);
-
-    size_t od = *dstlen, i;
-
-    for(i = 0, *dstlen = 0; i < srclen && *dstlen < od; i++, (*dstlen)++) {
-        if(61 == src[i]) {
-            if(srclen <= i + 1) goto exit;
-            dst[*dstlen] = src[++i] - 106;
-        } else
-            dst[*dstlen] = src[i] - 42;
-    }
-
-exit:
-    *rem = src + i;
-    *remlen = srclen - i;
-
-    return(0);
-}
diff --git a/csrc/yenc.h b/csrc/yenc.h
deleted file mode 100644
--- a/csrc/yenc.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright: (c) Magnus Therning, 2012
-// License: BSD3, found in the LICENSE file
-
-#ifndef _YENC_H_
-#define _YENC_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-void y_enc(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-int y_dec(uint8_t const *src, size_t srclen,
-    uint8_t *dst, size_t *dstlen,
-    uint8_t const **rem, size_t *remlen);
-
-#endif
diff --git a/sandi.cabal b/sandi.cabal
--- a/sandi.cabal
+++ b/sandi.cabal
@@ -1,5 +1,5 @@
 name: sandi
-version: 0.1.1
+version: 0.2
 license: BSD3
 license-file: LICENSE
 cabal-version: >= 1.8
@@ -17,27 +17,17 @@
     type: git
     location: https://github.com/magthe/sandi
 
-flag tests
-    description: Build tests
-    default: False
-
 library
     hs-source-dirs: src
-    c-sources:
-        csrc/b16.c
-        csrc/b32.c
-        csrc/b32hex.c
-        csrc/b64.c
-        csrc/b64url.c
-        csrc/b85.c
-        csrc/qp.c
-        csrc/uu.c
-        csrc/xx.c
-        csrc/yenc.c
+    c-sources: csrc/codec.c
     include-dirs: csrc
+    ghc-options: -Wall
+    cc-options: -Wall -Wextra
     build-depends:
         base ==4.6.*,
-        bytestring ==0.10.*
+        bytestring ==0.10.*,
+        conduit ==1.0.*,
+        resourcet ==0.4.*
     exposed-modules:
             Codec.Binary.Base16
             Codec.Binary.Base32
@@ -49,24 +39,39 @@
             Codec.Binary.Uu
             Codec.Binary.Xx
             Codec.Binary.Yenc
-    if !flag(tests)
-        cc-options: "-DNDEBUG"
-    else
-        cc-options: "-DDEBUG"
+            Data.Conduit.Codec.Base16
+            Data.Conduit.Codec.Base32
+            Data.Conduit.Codec.Base32Hex
+            Data.Conduit.Codec.Base64
+            Data.Conduit.Codec.Base64Url
+            Data.Conduit.Codec.Base85
+            Data.Conduit.Codec.QuotedPrintable
+            Data.Conduit.Codec.Uu
+            Data.Conduit.Codec.Xx
+            Data.Conduit.Codec.Yenc
+    other-modules:
+        Data.Conduit.Codec.Util
 
-executable tests
+test-suite sandi-tests
+    type: exitcode-stdio-1.0
+    hs-source-dirs: src, test-src
     main-is: Main.hs
-    hs-source-dirs: test-src
-    if flag(tests)
-        buildable: True
-        build-depends:
-            sandi,
-            base ==4.6.*,
-            bytestring ==0.10.*,
-            HUnit ==1.2.*,
-            test-framework-th ==0.2.*,
-            test-framework ==0.8.*,
-            test-framework-hunit ==0.3.*,
-            test-framework-quickcheck2 ==0.3.*
-    else
-        buildable: False
+    build-depends:
+        sandi,
+        base,
+        bytestring,
+        HUnit,
+        test-framework-quickcheck2,
+        test-framework-hunit,
+        test-framework-th,
+        test-framework
+
+benchmark sandi-bench
+    type: exitcode-stdio-1.0
+    hs-source-dirs:   src, bench-src
+    main-is: Main.hs
+    build-depends:
+        sandi,
+        base,
+        bytestring,
+        criterion
diff --git a/src/Codec/Binary/Base16.hs b/src/Codec/Binary/Base16.hs
--- a/src/Codec/Binary/Base16.hs
+++ b/src/Codec/Binary/Base16.hs
@@ -56,20 +56,23 @@
 
 -- | Decoding function.
 --
--- The returned value on success is @Right \<decoded string>@, and on failure
--- it's @Left (\<decoded part\>, \<undecodable part>)@.  Space equal to the
--- length of the input string is allocated, which is more than enough to hold
--- the decoded data.
+-- The returned value on success is @Right (\<decoded part>, \<undecoded
+-- part>)@ (the undecoded part is either a empty or a single byte), and on
+-- failure it's @Left (\<decoded part\>, \<undecodable part>)@.  Space equal to
+-- the length of the input string is allocated, which is more than enough to
+-- hold the decoded data.
 --
 -- >>> b16_dec $ Data.ByteString.Char8.pack "00"
--- Right "\NUL"
+-- Right ("\NUL","")
 --
 -- >>> b16_dec $ Data.ByteString.Char8.pack "666F6F626172"
--- Right "foobar"
+-- Right ("foobar","")
 --
 -- >>> b16_dec $ Data.ByteString.Char8.pack "666F6F62617"
--- Left ("fooba","7")
-b16_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
+-- Right ("fooba","7")
+-- >>> b16_dec $ Data.ByteString.Char8.pack "666F6F62617g"
+-- Left ("fooba","g")
+b16_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)
 b16_dec bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
     outBuf <- mallocBytes inLen
     alloca $ \ pOutLen ->
@@ -84,7 +87,7 @@
                 remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)
                 outBs <- BSU.unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)
                 if r == 0
-                    then return $ Right outBs
+                    then return $ Right (outBs, remBs)
                     else return $ Left (outBs, remBs)
 
 -- | A synonym for 'b16_enc'.
@@ -93,4 +96,8 @@
 
 -- | A synonum for 'b16_dec'.
 decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
-decode = b16_dec
+decode bs = case b16_dec bs of
+    Right a@(d, r) -> if BS.null r
+            then Right d
+            else Left a
+    Left a -> Left a
diff --git a/src/Codec/Binary/Base32.hs b/src/Codec/Binary/Base32.hs
--- a/src/Codec/Binary/Base32.hs
+++ b/src/Codec/Binary/Base32.hs
@@ -22,8 +22,6 @@
 
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import qualified Data.ByteString as BS
 import Data.ByteString.Unsafe
 import System.IO.Unsafe as U
diff --git a/src/Codec/Binary/Base32Hex.hs b/src/Codec/Binary/Base32Hex.hs
--- a/src/Codec/Binary/Base32Hex.hs
+++ b/src/Codec/Binary/Base32Hex.hs
@@ -20,8 +20,6 @@
 
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import qualified Data.ByteString as BS
 import Data.ByteString.Unsafe
 import System.IO.Unsafe as U
diff --git a/src/Codec/Binary/Base64.hs b/src/Codec/Binary/Base64.hs
--- a/src/Codec/Binary/Base64.hs
+++ b/src/Codec/Binary/Base64.hs
@@ -22,8 +22,6 @@
 
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import qualified Data.ByteString as BS
 import Data.ByteString.Unsafe
 import System.IO.Unsafe as U
diff --git a/src/Codec/Binary/Base64Url.hs b/src/Codec/Binary/Base64Url.hs
--- a/src/Codec/Binary/Base64Url.hs
+++ b/src/Codec/Binary/Base64Url.hs
@@ -16,16 +16,14 @@
 module Codec.Binary.Base64Url
     ( b64u_encode_part
     , b64u_encode_final
-    , b64url_decode_part
-    , b64url_decode_final
+    , b64u_decode_part
+    , b64u_decode_final
     , encode
     , decode
     ) where
 
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import qualified Data.ByteString as BS
 import Data.ByteString.Unsafe
 import System.IO.Unsafe as U
@@ -74,8 +72,8 @@
                 return $ Just outBs
             else free outBuf >> return Nothing
 
-b64url_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)
-b64url_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
+b64u_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)
+b64u_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
     let maxOutLen = inLen `div` 4 * 3
     outBuf <- mallocBytes maxOutLen
     alloca $ \ pOutLen ->
@@ -93,8 +91,8 @@
                     then return $ Right (outBs, remBs)
                     else return $ Left (outBs, remBs)
 
-b64url_decode_final :: BS.ByteString -> Maybe BS.ByteString
-b64url_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
+b64u_decode_final :: BS.ByteString -> Maybe BS.ByteString
+b64u_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
     outBuf <- mallocBytes 3
     alloca $ \ pOutLen -> do
         r <- c_b64u_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen
@@ -119,5 +117,5 @@
         maybe
             (Left (first, rest))
             (\ fin -> Right (first `BS.append` fin))
-            (b64url_decode_final rest))
-    (b64url_decode_part bs)
+            (b64u_decode_final rest))
+    (b64u_decode_part bs)
diff --git a/src/Codec/Binary/Base85.hs b/src/Codec/Binary/Base85.hs
--- a/src/Codec/Binary/Base85.hs
+++ b/src/Codec/Binary/Base85.hs
@@ -164,7 +164,7 @@
 -- "foobar"
 decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
 decode bs = let
-        iterateDecode bss rem = case b85_decode_part rem of
+        iterateDecode bss re = case b85_decode_part re of
             Right (d, r) ->
                 if BS.null d
                     then Right (BS.concat (reverse bss), r)
diff --git a/src/Codec/Binary/QuotedPrintable.hs b/src/Codec/Binary/QuotedPrintable.hs
--- a/src/Codec/Binary/QuotedPrintable.hs
+++ b/src/Codec/Binary/QuotedPrintable.hs
@@ -83,17 +83,17 @@
 -- representation:
 --
 -- >>> qp_dec $ Data.ByteString.Char8.pack "=20!"
--- Right " !"
+-- Right (" !","")
 -- >>> qp_dec $ Data.ByteString.Char8.pack "=20=21"
--- Right " !"
+-- Right (" !","")
 --
 -- A @Left@ value is only ever returned on decoding errors.
 --
 -- >>> qp_dec $ Data.ByteString.Char8.pack "=2"
--- Left ("","=2")
+-- Right ("","=2")
 -- >>> qp_dec $ Data.ByteString.Char8.pack "=2g"
 -- Left ("","=2g")
-qp_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
+qp_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)
 qp_dec bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
     outBuf <- mallocBytes inLen
     alloca $ \ pOutLen ->
@@ -108,7 +108,7 @@
                 remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)
                 outBs <- BSU.unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)
                 if r == 0
-                    then return $ Right outBs
+                    then return $ Right (outBs, remBs)
                     else return $ Left (outBs, remBs)
 
 -- | Convenient function that calls 'qp_enc' repeatedly until the whole input
@@ -118,4 +118,8 @@
 
 -- | A synonym for 'qp_dec'.
 decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
-decode = qp_dec
+decode bs = case qp_dec bs of
+    Right a@(d, r) -> if BS.null r
+            then Right d
+            else Left a
+    Left a -> Left a
diff --git a/src/Codec/Binary/Uu.hs b/src/Codec/Binary/Uu.hs
--- a/src/Codec/Binary/Uu.hs
+++ b/src/Codec/Binary/Uu.hs
@@ -29,8 +29,6 @@
 import Data.ByteString.Unsafe
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import System.IO.Unsafe as U
 import qualified Data.ByteString as BS
 
diff --git a/src/Codec/Binary/Xx.hs b/src/Codec/Binary/Xx.hs
--- a/src/Codec/Binary/Xx.hs
+++ b/src/Codec/Binary/Xx.hs
@@ -25,8 +25,6 @@
 import Data.ByteString.Unsafe
 import Foreign
 import Foreign.C.Types
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
 import System.IO.Unsafe as U
 import qualified Data.ByteString as BS
 
diff --git a/src/Codec/Binary/Yenc.hs b/src/Codec/Binary/Yenc.hs
--- a/src/Codec/Binary/Yenc.hs
+++ b/src/Codec/Binary/Yenc.hs
@@ -61,30 +61,31 @@
 -- | Decoding function.
 --
 -- >>> y_dec $ Data.ByteString.pack [144,153,153,140,139,156]
--- Right "foobar"
+-- Right ("foobar","")
 -- >>> y_dec $ Data.ByteString.Char8.pack "=}"
--- Right "\DC3"
+-- Right ("\DC3","")
 --
--- A @Left@ value is only ever returned on decoding errors.
+-- A @Left@ value is only ever returned on decoding errors which, due to
+-- characteristics of the encoding, can never happen.
 --
 -- >>> y_dec $ Data.ByteString.Char8.pack "="
--- Left ("","=")
-y_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
+-- Right ("","=")
+y_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)
 y_dec bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do
     outBuf <- mallocBytes inLen
     alloca $ \ pOutLen ->
         alloca $ \ pRemBuf ->
             alloca $ \ pRemLen -> do
                 poke pOutLen (castEnum inLen)
-                _ <- c_y_dec (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen
+                r <- c_y_dec (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen
                 outLen <- peek pOutLen
                 newOutBuf <- reallocBytes outBuf (castEnum outLen)
                 remBuf <- peek pRemBuf
                 remLen <- peek pRemLen
                 remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)
                 outBs <- BSU.unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)
-                if remLen == 0
-                    then return $ Right outBs
+                if r == 0
+                    then return $ Right (outBs, remBs)
                     else return $ Left (outBs, remBs)
 
 -- | Convenient function that calls 'y_enc' repeatedly until the whole input
@@ -94,4 +95,8 @@
 
 -- | A synonym for 'y_dec'.
 decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString
-decode = y_dec
+decode bs = case y_dec bs of
+    Right a@(d, r) -> if BS.null r
+        then Right d
+        else Left a
+    Left a -> Left a
diff --git a/src/Data/Conduit/Codec/Base16.hs b/src/Data/Conduit/Codec/Base16.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base16.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base16 where
+
+import qualified Codec.Binary.Base16 as B16
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit
+import Data.ByteString as BS
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeII B16.encode
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeII B16.b16_dec empty
diff --git a/src/Data/Conduit/Codec/Base32.hs b/src/Data/Conduit/Codec/Base32.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base32.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base32 where
+
+import qualified Codec.Binary.Base32 as B32
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI B32.b32_encode_part B32.b32_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI B32.b32_decode_part B32.b32_decode_final empty
diff --git a/src/Data/Conduit/Codec/Base32Hex.hs b/src/Data/Conduit/Codec/Base32Hex.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base32Hex.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base32Hex where
+
+import qualified Codec.Binary.Base32Hex as B32H
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI B32H.b32h_encode_part B32H.b32h_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI B32H.b32h_decode_part B32H.b32h_decode_final empty
diff --git a/src/Data/Conduit/Codec/Base64.hs b/src/Data/Conduit/Codec/Base64.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base64.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base64 where
+
+import qualified Codec.Binary.Base64 as B64
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI B64.b64_encode_part B64.b64_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI B64.b64_decode_part B64.b64_decode_final empty
diff --git a/src/Data/Conduit/Codec/Base64Url.hs b/src/Data/Conduit/Codec/Base64Url.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base64Url.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base64Url where
+
+import qualified Codec.Binary.Base64Url as B64U
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI B64U.b64u_encode_part B64U.b64u_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI B64U.b64u_decode_part B64U.b64u_decode_final empty
diff --git a/src/Data/Conduit/Codec/Base85.hs b/src/Data/Conduit/Codec/Base85.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Base85.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Base85 where
+
+import qualified Codec.Binary.Base85 as B85
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI B85.b85_encode_part B85.b85_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI B85.b85_decode_part B85.b85_decode_final empty
diff --git a/src/Data/Conduit/Codec/QuotedPrintable.hs b/src/Data/Conduit/Codec/QuotedPrintable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/QuotedPrintable.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.QuotedPrintable where
+
+import qualified Codec.Binary.QuotedPrintable as Qp
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit
+import Data.ByteString as BS
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeII Qp.encode
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeII Qp.qp_dec empty
diff --git a/src/Data/Conduit/Codec/Util.hs b/src/Data/Conduit/Codec/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Util.hs
@@ -0,0 +1,79 @@
+{-# OPTIONS_GHC -XDeriveDataTypeable #-}
+
+module Data.Conduit.Codec.Util
+    ( CodecDecodeException(..)
+    , encodeI
+    , decodeI
+    , decodeII
+    , encodeII
+    ) where
+
+import Data.Typeable (Typeable)
+import Control.Exception (Exception)
+import Data.ByteString as BS (ByteString, append, null)
+import Data.Conduit (Conduit, MonadThrow, await, monadThrow, yield)
+import Data.Maybe (fromJust)
+import Control.Monad (unless)
+
+type EncFunc = ByteString -> ByteString
+type EncFuncPart = ByteString -> (ByteString, ByteString)
+type EncFuncFinal = ByteString -> Maybe ByteString
+type DecFunc = ByteString -> Either (ByteString, ByteString) (ByteString, ByteString)
+type DecFuncFinal = ByteString -> Maybe ByteString
+
+data CodecDecodeException = CodecDecodeException ByteString
+    deriving (Typeable, Show)
+
+instance Exception CodecDecodeException
+
+encodeI :: (Monad m) => EncFuncPart -> EncFuncFinal -> ByteString -> Conduit ByteString m ByteString
+encodeI enc_part enc_final i = do
+    clear <- await
+    case clear of
+        Nothing -> (yield $ fromJust $ enc_final i) >> return ()
+        Just s -> let
+                (a, b) = enc_part (i `append` s)
+            in do
+                unless (BS.null a) $ yield a
+                encodeI enc_part enc_final b
+
+decodeI :: (Monad m, MonadThrow m) => DecFunc -> DecFuncFinal -> ByteString -> Conduit ByteString m ByteString
+decodeI dec_part dec_final i = do
+    enc <- await
+    case enc of
+        Nothing -> 
+            case dec_final i of
+                Nothing -> monadThrow (CodecDecodeException i)
+                Just s -> yield s >> return ()
+        Just s ->
+            case dec_part (i `append` s) of
+                Left (a, b) -> do
+                    unless (BS.null a) $ yield a
+                    monadThrow (CodecDecodeException b)
+                Right (a, b) -> do
+                    unless (BS.null a) $ yield a
+                    decodeI dec_part dec_final b
+
+encodeII :: (Monad m) => EncFunc -> Conduit ByteString m ByteString
+encodeII enc = do
+    clear <- await
+    case clear of
+        Nothing -> return ()
+        Just s -> do
+            yield $ enc s
+            encodeII enc
+
+decodeII :: (Monad m, MonadThrow m) => DecFunc -> ByteString -> Conduit ByteString m ByteString
+decodeII dec i = do
+    enc <- await
+    case enc of
+        Nothing -> if BS.null i
+            then return ()
+            else monadThrow $ CodecDecodeException i
+        Just s -> case (dec $ i `append` s) of
+            Left (c, b) -> do
+                unless (BS.null c) $ yield c
+                monadThrow $ CodecDecodeException b
+            Right (c, r) -> do
+                unless (BS.null c) $ yield c
+                decodeII dec r
diff --git a/src/Data/Conduit/Codec/Uu.hs b/src/Data/Conduit/Codec/Uu.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Uu.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Uu where
+
+import qualified Codec.Binary.Uu as Uu
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI Uu.uu_encode_part Uu.uu_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI Uu.uu_decode_part Uu.uu_decode_final empty
diff --git a/src/Data/Conduit/Codec/Xx.hs b/src/Data/Conduit/Codec/Xx.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Xx.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Xx where
+
+import qualified Codec.Binary.Xx as Xx
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeI Xx.xx_encode_part Xx.xx_encode_final empty
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeI Xx.xx_decode_part Xx.xx_decode_final empty
diff --git a/src/Data/Conduit/Codec/Yenc.hs b/src/Data/Conduit/Codec/Yenc.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Conduit/Codec/Yenc.hs
@@ -0,0 +1,13 @@
+module Data.Conduit.Codec.Yenc where
+
+import qualified Codec.Binary.Yenc as Y
+import qualified Data.Conduit.Codec.Util as U
+
+import Data.Conduit (Conduit, MonadThrow)
+import Data.ByteString (ByteString, empty)
+
+encode :: (Monad m) => Conduit ByteString m ByteString
+encode = U.encodeII Y.encode
+
+decode :: (Monad m, MonadThrow m) => Conduit ByteString m ByteString
+decode = U.decodeII Y.y_dec empty
diff --git a/test-src/Main.hs b/test-src/Main.hs
--- a/test-src/Main.hs
+++ b/test-src/Main.hs
@@ -7,296 +7,37 @@
 
 import Test.Framework
 import Test.Framework.TH
-import Test.Framework.Providers.HUnit
-import Test.Framework.Providers.QuickCheck2
-import Test.HUnit
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Char8 as BSC
-
-import qualified Codec.Binary.Base16 as B16
-import qualified Codec.Binary.Base32 as B32
-import qualified Codec.Binary.Base32Hex as B32H
-import qualified Codec.Binary.Base64 as B64
-import qualified Codec.Binary.Base64Url as B64U
-import qualified Codec.Binary.Base85 as B85
-import qualified Codec.Binary.QuotedPrintable as QP
-import qualified Codec.Binary.Uu as Uu
-import qualified Codec.Binary.Xx as Xx
-import qualified Codec.Binary.Yenc as Y
-
--- {{{1 utils
-fromRight (Right a) = a
-
--- {{{1 base16
-case_b16_enc_foobar = do
-    BSC.empty               @=? B16.encode BSC.empty
-    BSC.pack "66"           @=? B16.encode (BSC.pack "f")
-    BSC.pack "666F"         @=? B16.encode (BSC.pack "fo")
-    BSC.pack "666F6F"       @=? B16.encode (BSC.pack "foo")
-    BSC.pack "666F6F62"     @=? B16.encode (BSC.pack "foob")
-    BSC.pack "666F6F6261"   @=? B16.encode (BSC.pack "fooba")
-    BSC.pack "666F6F626172" @=? B16.encode (BSC.pack "foobar")
-
-case_b16_dec_foobar = do
-    Right BS.empty            @=? B16.decode BS.empty
-    Right (BSC.pack "f")      @=? B16.decode (BSC.pack "66")
-    Right (BSC.pack "fo")     @=? B16.decode (BSC.pack "666F")
-    Right (BSC.pack "foo")    @=? B16.decode (BSC.pack "666F6F")
-    Right (BSC.pack "foob")   @=? B16.decode (BSC.pack "666F6F62")
-    Right (BSC.pack "fooba")  @=? B16.decode (BSC.pack "666F6F6261")
-    Right (BSC.pack "foobar") @=? B16.decode (BSC.pack "666F6F626172")
-
-case_b16_dec_failure = do
-    -- odd number of input bytes
-    (Left (BSC.pack "fooba", BS.pack [55])) @=? (B16.decode $ BS.pack [54,54,54,70,54,70,54,50,54,49,55])
-
-prop_b16_encdec ws = (BS.pack ws) == (fromRight $ B16.decode $ B16.encode $ BS.pack ws)
-
--- {{{1 base32
-case_b32_enc_foobar = do
-    BSC.empty                   @=? B32.encode BSC.empty
-    BSC.pack "MY======"         @=? B32.encode (BSC.pack "f")
-    BSC.pack "MZXQ===="         @=? B32.encode (BSC.pack "fo")
-    BSC.pack "MZXW6==="         @=? B32.encode (BSC.pack "foo")
-    BSC.pack "MZXW6YQ="         @=? B32.encode (BSC.pack "foob")
-    BSC.pack "MZXW6YTB"         @=? B32.encode (BSC.pack "fooba")
-    BSC.pack "MZXW6YTBOI======" @=? B32.encode (BSC.pack "foobar")
-
-case_b32_dec_foobar = do
-    Right BS.empty            @=? B32.decode BS.empty
-    Right (BSC.pack "f")      @=? B32.decode (BSC.pack "MY======")
-    Right (BSC.pack "fo")     @=? B32.decode (BSC.pack "MZXQ====")
-    Right (BSC.pack "foo")    @=? B32.decode (BSC.pack "MZXW6===")
-    Right (BSC.pack "foob")   @=? B32.decode (BSC.pack "MZXW6YQ=")
-    Right (BSC.pack "fooba")  @=? B32.decode (BSC.pack "MZXW6YTB")
-    Right (BSC.pack "foobar") @=? B32.decode (BSC.pack "MZXW6YTBOI======")
-
-case_b32_dec_failures = do
-    -- illegal char
-    Left (BSC.empty, BSC.pack "M=XW6YTB") @=? (B32.b32_decode_part $ BSC.pack "M=XW6YTB")
-    -- full block
-    Nothing @=? (B32.b32_decode_final $ BSC.pack "MZXW6YTB")
-    -- too short
-    Nothing @=? (B32.b32_decode_final $ BSC.pack "MZXW6Y=")
-
-prop_b36_encdec ws = (BS.pack ws) == (fromRight $ B32.decode $ B32.encode $ BS.pack ws)
-
--- {{{1 base32hex
-case_b32h_enc_foobar = do
-    BSC.empty                   @=? B32H.encode BS.empty
-    BSC.pack "CO======"         @=? B32H.encode (BSC.pack "f")
-    BSC.pack "CPNG===="         @=? B32H.encode (BSC.pack "fo")
-    BSC.pack "CPNMU==="         @=? B32H.encode (BSC.pack "foo")
-    BSC.pack "CPNMUOG="         @=? B32H.encode (BSC.pack "foob")
-    BSC.pack "CPNMUOJ1"         @=? B32H.encode (BSC.pack "fooba")
-    BSC.pack "CPNMUOJ1E8======" @=? B32H.encode (BSC.pack "foobar")
-
-case_b32h_dec_foobar = do
-    Right BS.empty            @=? B32H.decode BS.empty
-    Right (BSC.pack "f")      @=? B32H.decode (BSC.pack "CO======")
-    Right (BSC.pack "fo")     @=? B32H.decode (BSC.pack "CPNG====")
-    Right (BSC.pack "foo")    @=? B32H.decode (BSC.pack "CPNMU===")
-    Right (BSC.pack "foob")   @=? B32H.decode (BSC.pack "CPNMUOG=")
-    Right (BSC.pack "fooba")  @=? B32H.decode (BSC.pack "CPNMUOJ1")
-    Right (BSC.pack "foobar") @=? B32H.decode (BSC.pack "CPNMUOJ1E8======")
-
-case_b32h_dec_failures = do
-    --  illegal char
-    Left (BS.empty, BSC.pack "C=NMUOJ1") @=? (B32H.b32h_decode_part $ BSC.pack "C=NMUOJ1")
-    -- full block
-    Nothing @=? (B32H.b32h_decode_final $ BSC.pack "CPNMUOJ1")
-    -- too short
-    Nothing @=? (B32H.b32h_decode_final $ BSC.pack "CPNMUO=")
-
-prop_b32H_encdec ws = (BS.pack ws) == (fromRight $ B32H.decode $ B32H.encode $ BS.pack ws)
-
--- {{{1 base64
-case_b64_enc_foobar = do
-    BSC.empty           @=? B64.encode BSC.empty
-    BSC.pack "Zg=="     @=? B64.encode (BSC.pack "f")
-    BSC.pack "Zm8="     @=? B64.encode (BSC.pack "fo")
-    BSC.pack "Zm9v"     @=? B64.encode (BSC.pack "foo")
-    BSC.pack "Zm9vYg==" @=? B64.encode (BSC.pack "foob")
-    BSC.pack "Zm9vYmE=" @=? B64.encode (BSC.pack "fooba")
-    BSC.pack "Zm9vYmFy" @=? B64.encode (BSC.pack "foobar")
-
-case_b64_enc_specials = do
-    -- /++/
-    BSC.pack "/++/" @=? B64.encode (BS.pack [255,239,191])
-
-case_b64_dec_foobar = do
-    Right BSC.empty           @=? B64.decode BSC.empty
-    Right (BSC.pack "f")      @=? B64.decode (BSC.pack "Zg==")
-    Right (BSC.pack "fo")     @=? B64.decode (BSC.pack "Zm8=")
-    Right (BSC.pack "foo")    @=? B64.decode (BSC.pack "Zm9v")
-    Right (BSC.pack "foob")   @=? B64.decode (BSC.pack "Zm9vYg==")
-    Right (BSC.pack "fooba")  @=? B64.decode (BSC.pack "Zm9vYmE=")
-    Right (BSC.pack "foobar") @=? B64.decode (BSC.pack "Zm9vYmFy")
-
-case_b64_dec_specials = do
-    -- /++/
-    Right (BS.pack [255,239,191]) @=? B64.decode (BSC.pack "/++/")
-
-prop_b64_encdec ws = (BS.pack ws) == (fromRight $ B64.decode $ B64.encode $ BS.pack ws)
-
--- {{{1 base64url
-case_b64u_enc_foobar = do
-    BSC.empty           @=? B64U.encode BSC.empty
-    BSC.pack "Zg=="     @=? B64U.encode (BSC.pack "f")
-    BSC.pack "Zm8="     @=? B64U.encode (BSC.pack "fo")
-    BSC.pack "Zm9v"     @=? B64U.encode (BSC.pack "foo")
-    BSC.pack "Zm9vYg==" @=? B64U.encode (BSC.pack "foob")
-    BSC.pack "Zm9vYmE=" @=? B64U.encode (BSC.pack "fooba")
-    BSC.pack "Zm9vYmFy" @=? B64U.encode (BSC.pack "foobar")
-
-case_b64u_enc_specials = do
-    -- _--_
-    BSC.pack "_--_" @=? (B64U.encode $ BS.pack [255,239,191])
-
-case_b64u_dec_foobar = do
-    Right BSC.empty           @=? B64U.decode BSC.empty
-    Right (BSC.pack "f")      @=? B64U.decode (BSC.pack "Zg==")
-    Right (BSC.pack "fo")     @=? B64U.decode (BSC.pack "Zm8=")
-    Right (BSC.pack "foo")    @=? B64U.decode (BSC.pack "Zm9v")
-    Right (BSC.pack "foob")   @=? B64U.decode (BSC.pack "Zm9vYg==")
-    Right (BSC.pack "fooba")  @=? B64U.decode (BSC.pack "Zm9vYmE=")
-    Right (BSC.pack "foobar") @=? B64U.decode (BSC.pack "Zm9vYmFy")
-
-case_b64u_dec_specials = do
-    -- _--_
-    Right (BS.pack [255,239,191]) @=? B64U.decode (BSC.pack "_--_")
-
-prop_b64U_encdec ws = (BS.pack ws) == (fromRight $ B64U.decode $ B64U.encode $ BS.pack ws)
-
--- {{{1 base85
-case_b85_enc_foobar = do
-    BS.empty @=? B85.encode BS.empty
-    BSC.pack "Ac"       @=? B85.encode (BSC.pack "f")
-    BSC.pack "Ao@"      @=? B85.encode (BSC.pack "fo")
-    BSC.pack "AoDS"     @=? B85.encode (BSC.pack "foo")
-    BSC.pack "AoDTs"    @=? B85.encode (BSC.pack "foob")
-    BSC.pack "AoDTs@/"  @=? B85.encode (BSC.pack "fooba")
-    BSC.pack "AoDTs@<)" @=? B85.encode (BSC.pack "foobar")
-
-case_b85_enc_specials = do
-    -- all zero
-    BSC.pack "z" @=? B85.encode (BS.pack [0,0,0,0])
-    -- all space
-    BSC.pack "y" @=? B85.encode (BS.pack [32,32,32,32])
-    -- double special
-    BSC.pack "yz" @=? B85.encode (BS.pack [32,32,32,32,0,0,0,0])
-
-case_b85_dec_foobar = do
-    -- foobar
-    Right BS.empty            @=? B85.decode BS.empty
-    Right (BSC.pack "f")      @=? B85.decode (BSC.pack "Ac")
-    Right (BSC.pack "fo")     @=? B85.decode (BSC.pack "Ao@")
-    Right (BSC.pack "foo")    @=? B85.decode (BSC.pack "AoDS")
-    Right (BSC.pack "foob")   @=? B85.decode (BSC.pack "AoDTs")
-    Right (BSC.pack "fooba")  @=? B85.decode (BSC.pack "AoDTs@/")
-    Right (BSC.pack "foobar") @=? B85.decode (BSC.pack "AoDTs@<)")
-
-case_b85_dec_specials = do
-    -- all zero
-    Right (BS.pack [0,0,0,0]) @=? B85.decode (BSC.pack "z")
-    -- all space
-    Right (BS.pack [32,32,32,32]) @=? B85.decode (BSC.pack "y")
-    -- double special
-    Right (BS.pack [32,32,32,32,0,0,0,0]) @=? B85.decode (BSC.pack "yz")
-
-prop_b85_encdec ws = (BS.pack ws) == (fromRight $ B85.decode $ B85.encode $ BS.pack ws)
-
--- {{{1 quoted printable
-case_qp_enc_foobar = do
-    BS.empty          @=? QP.encode BS.empty
-    BSC.pack "foobar" @=? QP.encode (BSC.pack "foobar")
-
-case_qp_dec_foobar = do
-    Right BS.empty            @=? QP.decode BS.empty
-    Right (BSC.pack "foobar") @=? QP.decode (BSC.pack "foobar")
-
-prop_qp_encdec ws = (BS.pack ws) == (fromRight $ QP.decode $ QP.encode $ BS.pack ws)
-
--- {{{1 uu
-case_uu_enc_foobar = do
-    BS.empty            @=? Uu.encode BS.empty
-    BSC.pack "9@"       @=? Uu.encode (BSC.pack "f")
-    BSC.pack "9F\\"     @=? Uu.encode (BSC.pack "fo")
-    BSC.pack "9F]O"     @=? Uu.encode (BSC.pack "foo")
-    BSC.pack "9F]O8@"   @=? Uu.encode (BSC.pack "foob")
-    BSC.pack "9F]O8F$"  @=? Uu.encode (BSC.pack "fooba")
-    BSC.pack "9F]O8F%R" @=? Uu.encode (BSC.pack "foobar")
-
-case_uu_dec_foobar = do
-    Right BS.empty            @=? Uu.decode BS.empty
-    Right (BSC.pack "f")      @=? Uu.decode (BSC.pack "9@")
-    Right (BSC.pack "fo")     @=? Uu.decode (BSC.pack "9F\\")
-    Right (BSC.pack "foo")    @=? Uu.decode (BSC.pack "9F]O")
-    Right (BSC.pack "foob")   @=? Uu.decode (BSC.pack "9F]O8@")
-    Right (BSC.pack "fooba")  @=? Uu.decode (BSC.pack "9F]O8F$")
-    Right (BSC.pack "foobar") @=? Uu.decode (BSC.pack "9F]O8F%R")
-
-prop_uu_encdec ws = (BS.pack ws) == (fromRight $ Uu.decode $ Uu.encode $ BS.pack ws)
-
--- {{{1 xx
-case_xx_enc_foobar = do
-    -- foobar
-    BS.empty            @=? Xx.encode BS.empty
-    BSC.pack "NU"       @=? Xx.encode (BSC.pack "f")
-    BSC.pack "Naw"      @=? Xx.encode (BSC.pack "fo")
-    BSC.pack "Naxj"     @=? Xx.encode (BSC.pack "foo")
-    BSC.pack "NaxjMU"   @=? Xx.encode (BSC.pack "foob")
-    BSC.pack "NaxjMa2"  @=? Xx.encode (BSC.pack "fooba")
-    BSC.pack "NaxjMa3m" @=? Xx.encode (BSC.pack "foobar")
-
-case_xx_dec_foobar = do
-    -- foobar
-    Right BS.empty            @=? Xx.decode BS.empty
-    Right (BSC.pack "f")      @=? Xx.decode (BSC.pack "NU")
-    Right (BSC.pack "fo")     @=? Xx.decode (BSC.pack "Naw")
-    Right (BSC.pack "foo")    @=? Xx.decode (BSC.pack "Naxj")
-    Right (BSC.pack "foob")   @=? Xx.decode (BSC.pack "NaxjMU")
-    Right (BSC.pack "fooba")  @=? Xx.decode (BSC.pack "NaxjMa2")
-    Right (BSC.pack "foobar") @=? Xx.decode (BSC.pack "NaxjMa3m")
-
-prop_xx_encdec ws = (BS.pack ws) == (fromRight $ Xx.decode $ Xx.encode $ BS.pack ws)
-
--- {{{1 yenc
-case_y_enc_foobar = do
-    BS.empty                          @=? Y.encode BS.empty
-    BS.pack [144]                     @=? Y.encode (BSC.pack "f")
-    BS.pack [144,153]                 @=? Y.encode (BSC.pack "fo")
-    BS.pack [144,153,153]             @=? Y.encode (BSC.pack "foo")
-    BS.pack [144,153,153,140]         @=? Y.encode (BSC.pack "foob")
-    BS.pack [144,153,153,140,139]     @=? Y.encode (BSC.pack "fooba")
-    BS.pack [144,153,153,140,139,156] @=? Y.encode (BSC.pack "foobar")
-
-case_y_enc_specials = do
-    -- expanded chars
-    BS.pack [61,64]  @=? Y.encode (BS.pack [214])
-    BS.pack [61,74]  @=? Y.encode (BS.pack [224])
-    BS.pack [61,77]  @=? Y.encode (BS.pack [227])
-    BS.pack [61,125] @=? Y.encode (BS.pack [19])
-
-case_y_dec_foobar = do
-    Right BS.empty            @=? Y.decode BS.empty
-    Right (BSC.pack "f")      @=? Y.decode (BS.pack [144])
-    Right (BSC.pack "fo")     @=? Y.decode (BS.pack [144,153])
-    Right (BSC.pack "foo")    @=? Y.decode (BS.pack [144,153,153])
-    Right (BSC.pack "foob")   @=? Y.decode (BS.pack [144,153,153,140])
-    Right (BSC.pack "fooba")  @=? Y.decode (BS.pack [144,153,153,140,139])
-    Right (BSC.pack "foobar") @=? Y.decode (BS.pack [144,153,153,140,139,156])
-
-case_y_dec_specials = do
-    -- expanded chars
-    Right (BS.pack [214]) @=? Y.decode (BS.pack [61,64])
-    Right (BS.pack [224]) @=? Y.decode (BS.pack [61,74])
-    Right (BS.pack [227]) @=? Y.decode (BS.pack [61,77])
-    Right (BS.pack [19])  @=? Y.decode (BS.pack [61,125])
+-- import Test.Framework.Providers.HUnit
+-- import Test.Framework.Providers.QuickCheck2
+-- import Test.HUnit
+-- import qualified Data.ByteString as BS
+-- import qualified Data.ByteString.Char8 as BSC
 
-prop_y_encdec ws = (BS.pack ws) == (fromRight $ Y.decode $ Y.encode $ BS.pack ws)
+import qualified Codec.Binary.Base16Test as B16Test
+import qualified Codec.Binary.Base32Test as B32Test
+import qualified Codec.Binary.Base32HexTest as B32HTest
+import qualified Codec.Binary.Base64Test as B64Test
+import qualified Codec.Binary.Base64UrlTest as B64UTest
+import qualified Codec.Binary.Base85Test as B85Test
+import qualified Codec.Binary.QuotedPrintableTest as QPTest
+import qualified Codec.Binary.UuTest as UuTest
+import qualified Codec.Binary.XxTest as XxTest
+import qualified Codec.Binary.YencTest as YTest
 
--- {{{1 tests & main
-tests = [$(testGroupGenerator)]
+tests :: [Test.Framework.Test]
+tests =
+    [ $(testGroupGenerator)
+    , B16Test.tests
+    , B32Test.tests
+    , B32HTest.tests
+    , B64Test.tests
+    , B64UTest.tests
+    , B85Test.tests
+    , QPTest.tests
+    , UuTest.tests
+    , XxTest.tests
+    , YTest.tests
+    ]
 
+main :: IO ()
 main = defaultMain tests
