packages feed

sandi (empty) → 0.1

raw patch · 34 files changed

+3749/−0 lines, 34 filesdep +HUnitdep +basedep +bytestringsetup-changed

Dependencies added: HUnit, base, bytestring, sandi, test-framework, test-framework-hunit, test-framework-th

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2012, Magnus Therning+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    - Redistributions of source code must retain the above copyright notice,+      this list of conditions and the following disclaimer.++    - Redistributions in binary form must reproduce the above copyright notice,+      this list of conditions and the following disclaimer in the documentation+      and/or other materials provided with the distribution.++    - Neither the name of Magnus Therning nor the names of other contributors+      may be used to endorse or promote products derived from this software+      without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,22 @@+#! /usr/bin/env runhaskell++{- Copyright © 2007 Magnus Therning+ -+ - This file is part of dataenc.+ -+ - Dataenc is free software: you can redistribute it and/or modify it under+ - the terms of the GNU Lesser General Public License as published by the+ - Free Software Foundation, either version 3 of the License, or (at your+ - option) any later version.+ -+ - Dataenc is distributed in the hope that it will be useful, but WITHOUT+ - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or+ - FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public+ - License for more details.+ -+ - You should have received a copy of the GNU Lesser General Public License+ - along with dataenc.  If not, see <http://www.gnu.org/licenses/>+ -}++import Distribution.Simple+main = defaultMain
+ csrc/b16.c view
@@ -0,0 +1,75 @@+// 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);+}
+ csrc/b16.h view
@@ -0,0 +1,17 @@+// 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
+ csrc/b32.c view
@@ -0,0 +1,245 @@+// 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);+}
+ csrc/b32.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/b32hex.c view
@@ -0,0 +1,245 @@+// 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);+}
+ csrc/b32hex.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/b64.c view
@@ -0,0 +1,165 @@+// 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);+}
+ csrc/b64.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/b64url.c view
@@ -0,0 +1,165 @@+// 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);+}
+ csrc/b64url.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/b85.c view
@@ -0,0 +1,236 @@+// 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;+    }+}
+ csrc/b85.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/qp.c view
@@ -0,0 +1,91 @@+// 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);+}
+ csrc/qp.h view
@@ -0,0 +1,17 @@+// 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
+ csrc/uu.c view
@@ -0,0 +1,166 @@+// 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);+}
+ csrc/uu.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/xx.c view
@@ -0,0 +1,167 @@+// 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);+}
+ csrc/xx.h view
@@ -0,0 +1,21 @@+// 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
+ csrc/yenc.c view
@@ -0,0 +1,66 @@+// 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);+}
+ csrc/yenc.h view
@@ -0,0 +1,17 @@+// 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
+ sandi.cabal view
@@ -0,0 +1,71 @@+name: sandi+version: 0.1+license: BSD3+license-file: LICENSE+cabal-version: >= 1.8+build-type: Simple+author: Magnus Therning+maintainer: magnus@therning.org+homepage: http://hackage.haskell.org/package/sandi+copyright: Magnus Therning, 2012+category: Codec+synopsis: Data encoding library+description: Reasonably fast data encoding library.+extra-source-files: csrc/*.h++source-repository head+    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+    include-dirs: csrc+    build-depends:+        base ==4.6.*,+        bytestring ==0.10.*+    exposed-modules:+            Codec.Binary.Base16+            Codec.Binary.Base32+            Codec.Binary.Base32Hex+            Codec.Binary.Base64+            Codec.Binary.Base64Url+            Codec.Binary.Base85+            Codec.Binary.QuotedPrintable+            Codec.Binary.Uu+            Codec.Binary.Xx+            Codec.Binary.Yenc+    if !flag(tests)+        cc-options: "-DNDEBUG"+    else+        cc-options: "-DDEBUG"++executable tests+    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.6.*,+            test-framework-hunit ==0.2.*+    else+        buildable: False
+ src/Codec/Binary/Base16.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Base16+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implemention of base 16 encoding (hex encoding) as specified in RFC 4648+-- (<http://tools.ietf.org/html/rfc4648>).+module Codec.Binary.Base16+    ( b16_enc+    , b16_dec+    , encode+    , decode+    ) where++import Foreign+import Foreign.C.Types+import System.IO.Unsafe as U+import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BSU++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b16.h b16_enc"+    c_b16_enc :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b16.h b16_dec"+    c_b16_dec :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function, unlike some other encoding functions in the library, simply+-- cannot fail.  Double the length of the input string is allocated for the+-- encoded data, which is guaranteed to hold the result.+--+-- >>> b16_enc $ Data.ByteString.pack [0x00]+-- "00"+--+-- >>> b16_enc $ Data.ByteString.Char8.pack "foobar"+-- "666F6F626172"+b16_enc :: BS.ByteString+    -> BS.ByteString -- ^ The encoded string+b16_enc bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen * 2+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b16_enc (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                outBs <- BSU.unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return outBs++-- | 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.+--+-- >>> b16_dec $ Data.ByteString.Char8.pack "00"+-- Right "\NUL"+--+-- >>> b16_dec $ Data.ByteString.Char8.pack "666F6F626172"+-- Right "foobar"+--+-- >>> b16_dec $ Data.ByteString.Char8.pack "666F6F62617"+-- Left ("fooba","7")+b16_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+b16_dec bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes inLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum inLen)+                r <- c_b16_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 r == 0+                    then return $ Right outBs+                    else return $ Left (outBs, remBs)++-- | A synonym for 'b16_enc'.+encode :: BS.ByteString -> BS.ByteString+encode = b16_enc++-- | A synonum for 'b16_dec'.+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode = b16_dec
+ src/Codec/Binary/Base32.hs view
@@ -0,0 +1,192 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Base32+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implemented as specified in RFC 4648 (<http://tools.ietf.org/html/rfc4648>).+--+-- Base32 encoding works by expanding blocks of 5 bytes of data into blocks of+-- 8 bytes of data.  Finally it also includes a well defined ending of the+-- encoded data to make sure the size of the final block of encoded data is 8+-- bytes too.+module Codec.Binary.Base32+    ( b32_encode_part+    , b32_encode_final+    , b32_decode_part+    , b32_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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b32.h b32_enc_part"+    c_b32_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b32.h b32_enc_final"+    c_b32_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static b32.h b32_dec_part"+    c_b32_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static b32.h b32_dec_final"+    c_b32_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function encodes as large a portion of the input as possible and+-- returns the encoded part together with the remaining part.  Enough space is+-- allocated for the encoding to make sure that the remaining part is less than+-- 5 bytes long, which means it can be passed to 'b32_encode_final' as is.+--+-- >>> b32_encode_part $ Data.ByteString.Char8.pack "fooba"+-- ("MZXW6YTB","")+-- >>> b32_encode_part $ Data.ByteString.Char8.pack "foobar"+-- ("MZXW6YTB","r")+b32_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+b32_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 5 * 8+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b32_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- The final block has to have a size less than 5.+--+-- >>> b32_encode_final $ Data.ByteString.Char8.pack "r"+-- Just "OI======"+--+-- Trying to pass in too large a block result in failure:+--+-- >>> b32_encode_final $ Data.ByteString.Char8.pack "fooba"+-- Nothing+b32_encode_final :: BS.ByteString -> Maybe BS.ByteString+b32_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 5+    alloca $ \ pOutLen -> do+        r <- c_b32_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- Decode as large a portion of the input as possible.  Enough data is+-- allocated for the output to ensure that the remainder is less than 8 bytes+-- in size.  Success result in a @Right@ value:+--+-- >>> b32_decode_part $ Data.ByteString.Char8.pack "MZXW6YTB"+-- Right ("fooba","")+-- >>> b32_decode_part $ Data.ByteString.Char8.pack "MZXW6YTBOI======"+-- Right ("fooba","OI======")+--+-- Failures occur on bad input and result in a @Left@ value:+--+-- >>> b32_decode_part $ Data.ByteString.Char8.pack "M=XW6YTB"+-- Left ("","M=XW6YTB")+b32_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+b32_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 8 * 5+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_b32_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- The final block has to have a size of 0 or 8:+--+-- >>> b32_decode_final $ Data.ByteString.Char8.pack "MZXW6YQ="+-- Just "foob"+-- >>> b32_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> b32_decode_final $ Data.ByteString.Char8.pack "MZXW6Y="+-- Nothing+--+-- But it must be the encoding of a block that is less than 5 bytes:+--+-- >>> b32_decode_final $ encode $ Data.ByteString.Char8.pack "fooba"+-- Nothing+b32_decode_final :: BS.ByteString -> Maybe BS.ByteString+b32_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 5+    alloca $ \ pOutLen -> do+        r <- c_b32_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Convenience function that combines 'b32_encode_part' and+-- 'b32_encode_final' to encode a complete string.+--+-- >>> encode $ Data.ByteString.Char8.pack "fooba"+-- "MZXW6YTB"+-- >>> encode $ Data.ByteString.Char8.pack "foobar"+-- "MZXW6YTBOI======"+encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = b32_encode_part bs+        Just final = b32_encode_final rest+    in first `BS.append` final++-- | Convenience function that combines 'b32_decode_part' and+-- 'b32_decode_final' to decode a complete string.+--+-- >>> decode $ Data.ByteString.Char8.pack "MZXW6YTB"+-- Right "fooba"+-- >>> decode $ Data.ByteString.Char8.pack "MZXW6YTBOI======"+-- Right "foobar"+--+-- Failures when decoding returns the decoded part and the remainder:+--+-- >>> decode $ Data.ByteString.Char8.pack "MZXW6YTBOI=0===="+-- Left ("fooba","OI=0====")+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (b32_decode_final rest))+    (b32_decode_part bs)
+ src/Codec/Binary/Base32Hex.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module    : Codec.Binary.Base32Hex+-- Copyright : (c) 2012 Magnus Therning+-- License   : BSD3+--+-- Implemented as specified in RFC 4648 (<http://tools.ietf.org/html/rfc4648>).+--+-- This encoding is closely related to base 32 and so is its implementation, so+-- please refer to "Codec.Binary.Base32" for further details.+module Codec.Binary.Base32Hex+   ( b32h_encode_part+   , b32h_encode_final+   , b32h_decode_part+   , b32h_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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b32.h b32h_enc_part"+    c_b32h_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b32.h b32h_enc_final"+    c_b32h_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static b32.h b32h_dec_part"+    c_b32h_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static b32.h b32h_dec_final"+    c_b32h_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- See 'Codec.Binary.Base32.b32_encode_part'.+--+-- >>> b32h_encode_part $ Data.ByteString.Char8.pack "fooba"+-- ("CPNMUOJ1","")+-- >>> b32h_encode_part $ Data.ByteString.Char8.pack "foobar"+-- ("CPNMUOJ1","r")+b32h_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+b32h_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 5 * 8+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b32h_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- See 'Codec.Binary.Base32.b32_encode_final'.+--+-- >>> b32h_encode_final $ Data.ByteString.Char8.pack "r"+-- Just "E8======"+-- >>> b32h_encode_final $ Data.ByteString.Char8.pack "fooba"+-- Nothing+b32h_encode_final :: BS.ByteString -> Maybe BS.ByteString+b32h_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 5+    alloca $ \ pOutLen -> do+        r <- c_b32h_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- See 'Codec.Binary.Base32.b32_decode_part'.+--+-- >>> b32h_decode_part $ Data.ByteString.Char8.pack "CPNMUOJ1"+-- Right ("fooba","")+-- >>> b32h_decode_part $ Data.ByteString.Char8.pack "CPNMUOJ1E8======"+-- Right ("fooba","E8======")+-- >>> b32h_decode_part $ Data.ByteString.Char8.pack "C=NMUOJ1"+-- Left ("","C=NMUOJ1")+b32h_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+b32h_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 8 * 5+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_b32h_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- See 'Codec.Binary.Base32.b32_decode_final'.+--+-- >>> b32h_decode_final $ Data.ByteString.Char8.pack "CPNMUOG="+-- Just "foob"+-- >>> b32h_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> b32h_decode_final $ Data.ByteString.Char8.pack "CPNMUO="+-- Nothing+-- >>> b32h_decode_final $ encode $ Data.ByteString.Char8.pack "fooba"+-- Nothing+b32h_decode_final :: BS.ByteString -> Maybe BS.ByteString+b32h_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 5+    alloca $ \ pOutLen -> do+        r <- c_b32h_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Convenience function that combines 'b32h_encode_part' and+-- 'b32h_encode_final' to encode a complete string.+--+-- >>> encode $ Data.ByteString.Char8.pack "fooba"+-- "CPNMUOJ1"+-- >>> encode $ Data.ByteString.Char8.pack "foobar"+-- "CPNMUOJ1E8======"+encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = b32h_encode_part bs+        Just final = b32h_encode_final rest+    in first `BS.append` final++-- | Convenience function that combines 'b32h_decode_part' and+-- 'b32h_decode_final' to decode a complete string.+--+-- >>> decode $ Data.ByteString.Char8.pack "CPNMUOJ1"+-- Right "fooba"+-- >>> decode $ Data.ByteString.Char8.pack "CPNMUOJ1E8======"+-- Right "foobar"+--+-- Failures when decoding returns the decoded part and the remainder:+--+-- >>> decode $ Data.ByteString.Char8.pack "CPNMUOJ1=8======"+-- Left ("fooba","=8======")+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (b32h_decode_final rest))+    (b32h_decode_part bs)
+ src/Codec/Binary/Base64.hs view
@@ -0,0 +1,192 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Base64+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implemented as specified in RFC 4648 (<http://tools.ietf.org/html/rfc4648>).+--+-- Base64 encoding works by expanding blocks of 3 bytes of data into blocks of+-- 4 bytes of data.  Finally it also includes a well defined ending of the+-- encoded data to make sure the size of the final block of encoded data is 4+-- bytes too.+module Codec.Binary.Base64+    ( b64_encode_part+    , b64_encode_final+    , b64_decode_part+    , b64_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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b64.h b64_enc_part"+    c_b64_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b64.h b64_enc_final"+    c_b64_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static b64.h b64_dec_part"+    c_b64_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static b64.h b64_dec_final"+    c_b64_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function encodes as large a portion of the input as possible and+-- returns the encoded part together with the remaining part.  Enough space is+-- allocated for the encoding to make sure that the remaining part is less than+-- 3 bytes long, which means it can be passed to 'b64_encode_final' as is.+--+-- >>> b64_encode_part $ Data.ByteString.Char8.pack "foo"+-- ("Zm9v","")+-- >>> b64_encode_part $ Data.ByteString.Char8.pack "foob"+-- ("Zm9v","b")+b64_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+b64_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 3 * 4+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b64_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- The final block has to have a size less than 3.+--+-- >>> b64_encode_final $ Data.ByteString.Char8.pack "r"+-- Just "cg=="+--+-- Trying to pass in too large a block result in failure:+--+-- >>> b64_encode_final $ Data.ByteString.Char8.pack "foo"+-- Nothing+b64_encode_final :: BS.ByteString -> Maybe BS.ByteString+b64_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 4+    alloca $ \ pOutLen -> do+        r <- c_b64_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- Decode as large a portion of the input as possible.  Enough data is+-- allocated for the output to ensure that the remainder is less than 4 bytes+-- in size.  Success result in a @Right@ value:+--+-- >>> b64_decode_part $ Data.ByteString.Char8.pack "Zm9v"+-- Right ("foo","")+-- >>> b64_decode_part $ Data.ByteString.Char8.pack "Zm9vYmE="+-- Right ("foo","YmE=")+--+-- Failures occur on bad input and result in a @Left@ value:+--+-- >>> b64_decode_part $ Data.ByteString.Char8.pack "Z=9v"+-- Left ("","Z=9v")+b64_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+b64_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 4 * 3+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_b64_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- The final block has to have a size of 0 or 4:+--+-- >>> b64_decode_final $ Data.ByteString.Char8.pack "Zm8="+-- Just "fo"+-- >>> b64_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> b64_decode_final $ Data.ByteString.Char8.pack "Zm="+-- Nothing+--+-- But it must be the encoding of a block that is less than 3 bytes:+--+-- >>> b64_decode_final $ encode $ Data.ByteString.Char8.pack "foo"+-- Nothing+b64_decode_final :: BS.ByteString -> Maybe BS.ByteString+b64_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 3+    alloca $ \ pOutLen -> do+        r <- c_b64_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Convenience function that combines 'b64_encode_part' and+-- 'b64_encode_final' to encode a complete string.+--+-- >>> encode $ Data.ByteString.Char8.pack "foo"+-- "Zm9v"+-- >>> encode $ Data.ByteString.Char8.pack "foobar"+-- "Zm9vYmFy"+encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = b64_encode_part bs+        Just final = b64_encode_final rest+    in first `BS.append` final++-- | Convenience function that combines 'b64_decode_part' and+-- 'b64_decode_final' to decode a complete string.+--+-- >>> decode $ Data.ByteString.Char8.pack "Zm9v"+-- Right "foo"+-- >>> decode $ Data.ByteString.Char8.pack "Zm9vYmFy"+-- Right "foobar"+--+-- Failures when decoding returns the decoded part and the remainder:+--+-- >>> decode $ Data.ByteString.Char8.pack "Zm9vYm=y"+-- Left ("foo","Ym=y")+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (b64_decode_final rest))+    (b64_decode_part bs)
+ src/Codec/Binary/Base64Url.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Base64Url+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implemented as specified in RFC 4648 (<http://tools.ietf.org/html/rfc4648>).+--+-- The difference compared to vanilla Base64 encoding is just in two+-- characters.  In Base64 the characters @/+@ are used, and in Base64Url they+-- are replaced by @_-@ respectively.+--+-- Please refer to "Codec.Binary.Base64" for the details of all functions in+-- this module.+module Codec.Binary.Base64Url+    ( b64u_encode_part+    , b64u_encode_final+    , b64url_decode_part+    , b64url_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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b64.h b64u_enc_part"+    c_b64u_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b64.h b64u_enc_final"+    c_b64u_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static b64.h b64u_dec_part"+    c_b64u_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static b64.h b64u_dec_final"+    c_b64u_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++b64u_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+b64u_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 3 * 4+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b64u_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++b64u_encode_final :: BS.ByteString -> Maybe BS.ByteString+b64u_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 4+    alloca $ \ pOutLen -> do+        r <- c_b64u_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                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+    let maxOutLen = inLen `div` 4 * 3+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_b64u_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    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+    outBuf <- mallocBytes 3+    alloca $ \ pOutLen -> do+        r <- c_b64u_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = b64u_encode_part bs+        Just final = b64u_encode_final rest+    in first `BS.append` final++decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (b64url_decode_final rest))+    (b64url_decode_part bs)
+ src/Codec/Binary/Base85.hs view
@@ -0,0 +1,182 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Base85+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implemented as described at <http://en.wikipedia.org/wiki/Ascii85>.+module Codec.Binary.Base85+   ( b85_encode_part+   , b85_encode_final+   , b85_decode_part+   , b85_decode_final+   , encode+   , decode+   ) where++import qualified Data.ByteString as BS+import Foreign+import Foreign.C.Types+import System.IO.Unsafe as U+import Data.ByteString.Unsafe++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static b85.h b85_enc_part"+    c_b85_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static b85.h b85_enc_final"+    c_b85_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static b85.h b85_dec_part"+    c_b85_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static b85.h b85_dec_final"+    c_b85_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- Encodes as large a part as possible of the indata.+--+-- >>> b85_encode_part $ Data.ByteString.Char8.pack "foobar"+-- ("AoDTs","ar")+--+-- It supports special handling of both all-zero groups and all-space groups.+--+-- >>> b85_encode_part $ Data.ByteString.Char8.pack "    "+-- ("y", "")+-- >>> b85_encode_part $ Data.ByteString.Char8.pack "\0\0\0\0"+-- ("z", "")+b85_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+b85_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 4 * 5+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_b85_enc_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- >>> b85_encode_final $ Data.ByteString.Char8.pack "ar"+-- Just "@<)"+b85_encode_final :: BS.ByteString -> Maybe BS.ByteString+b85_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 5+    alloca $ \ pOutLen -> do+        r <- c_b85_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- Decode as large a portion of the input as possible.+--+-- >>> b85_decode_part $ Data.ByteString.Char8.pack "AoDTs"+-- Right ("foob","")+-- >>> b85_decode_part $ Data.ByteString.Char8.pack "AoDTs@<)"+-- Right ("foob","@<)")+-- >>> b85_decode_part $ Data.ByteString.Char8.pack "@<)"+-- Right ("","@<)")+--+-- At least 512 bytes of data is allocated for the output, but because of the+-- special handling of all-zero and all-space groups it is possible that the+-- space won't be enough.  (To be sure to always fit the output one would have+-- to allocate 5 times the length of the input.  It seemed a good trade-off to+-- sometimes have to call the function more than once instead.)+--+-- >>> either snd snd $ b85_decode_part $ Data.ByteString.Char8.pack $ Prelude.take 129 $ repeat 'y'+-- "y"+b85_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+b85_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = max 512 $ inLen `div` 5 * 4+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_b85_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- >>> b85_decode_final $ Data.ByteString.Char8.pack "@<)"+-- Just "ar"+-- >>> b85_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> b85_decode_final $ Data.ByteString.Char8.pack "AoDTs"+-- Nothing+b85_decode_final :: BS.ByteString -> Maybe BS.ByteString+b85_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 4+    alloca $ \ pOutLen -> do+        r <- c_b85_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Convenience function that combines 'b85_encode_part' and+-- 'b85_encode_final' to encode a complete string.+--+-- >>> encode  $ Data.ByteString.Char8.pack "foob"+-- "AoDTs"+-- >>> encode  $ Data.ByteString.Char8.pack "foobar"+-- "AoDTs@<)"+encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = b85_encode_part bs+        Just final = b85_encode_final rest+    in first `BS.append` final++-- | Convenience function that combines 'b85_decode_part' and+-- 'b85_decode_final' to decode a complete string.+--+-- >>> decode  $ Data.ByteString.Char8.pack "AoDTs"+-- "foob"+-- >>> encode  $ Data.ByteString.Char8.pack "AoDTs@<)"+-- "foobar"+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = let+        iterateDecode bss rem = case b85_decode_part rem of+            Right (d, r) ->+                if BS.null d+                    then Right (BS.concat (reverse bss), r)+                    else iterateDecode (d : bss) r+            Left (d, r) -> Left (BS.concat $ reverse $ d : bss, r)++        handleFinal a@(first, rest) = maybe+            (Left a)+            (\ final -> Right (first `BS.append` final))+            (b85_decode_final rest)++    in either+            Left+            handleFinal+            (iterateDecode [] bs)
+ src/Codec/Binary/QuotedPrintable.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.QuotedPrintable+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implementation of Quoted-Printable based on RFC 2045+-- (<http://tools.ietf.org/html/rfc2045>).+--+-- This encoding encodes /everything/ that is passed in, it will not try to+-- guess the native line ending for your architecture.  In other words, if you+-- are using this to encode text you need to split it into separate lines+-- before encoding.+module Codec.Binary.QuotedPrintable+    ( qp_enc+    , qp_dec+    , encode+    , decode+    ) where++import Data.List+import Foreign+import Foreign.C.Types+import System.IO.Unsafe as U+import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BSU++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static qp.h qp_enc"+    c_qp_enc :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static qp.h qp_dec"+    c_qp_dec :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function allocates enough space to hold twice the size of the indata+-- (or at least 512 bytes) and then encodes as much as possible of the indata.+-- That means there is a risk that the encoded data won't fit and in that case+-- the second part of the pair contains the remainder of the indata.+--+-- >>> qp_enc $ Data.ByteString.Char8.pack "="+-- ("=3D","")+-- >>> snd $ qp_enc $ Data.ByteString.Char8.pack $ Data.List.take 171 $ repeat '='+-- "="+qp_enc :: BS.ByteString -> (BS.ByteString, BS.ByteString)+qp_enc bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutBuf = max 512 (2 * inLen)+    outBuf <- mallocBytes maxOutBuf+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutBuf)+                c_qp_enc (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)+                return (outBs, remBs)++-- | Decoding function.+--+-- >>> qp_dec $ Data.ByteString.Char8.pack "foobar"+-- Right "foobar"+-- >>> qp_dec $ Data.ByteString.Char8.pack "1=20+=201=20=3D=202"+-- Right "1 + 1 = 2"+--+-- The input data is allowed to use lowercase letters in the hexadecimal+-- representation of an octets value, even though the standard says that only+-- uppercase letters may be used:+--+-- >>> qp_dec $ Data.ByteString.Char8.pack "=3D"+-- Right "="+-- >>> qp_dec $ Data.ByteString.Char8.pack "=3d"+-- Right "="+--+-- It also allows the input to encode _all_ octets in the hexadecimal+-- representation:+--+-- >>> qp_dec $ Data.ByteString.Char8.pack "=20!"+-- Right " !"+-- >>> qp_dec $ Data.ByteString.Char8.pack "=20=21"+-- Right " !"+--+-- A @Left@ value is only ever returned on decoding errors.+--+-- >>> qp_dec $ Data.ByteString.Char8.pack "=2"+-- Left ("","=2")+-- >>> qp_dec $ Data.ByteString.Char8.pack "=2g"+-- Left ("","=2g")+qp_dec :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+qp_dec bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes inLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum inLen)+                r <- c_qp_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 r == 0+                    then return $ Right outBs+                    else return $ Left (outBs, remBs)++-- | Convenient function that calls 'qp_enc' repeatedly until the whole input+-- data is encoded.+encode :: BS.ByteString -> BS.ByteString+encode = BS.concat . takeWhile (not . BS.null) . unfoldr (Just . qp_enc)++-- | A synonym for 'qp_dec'.+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode = qp_dec
+ src/Codec/Binary/Uu.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Uu+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Uuencoding is notoriously badly specified.  This implementation aims at+-- being compatible with the GNU Sharutils+-- (<http://www.gnu.org/software/sharutils/>).+--+-- Just like Base64 encoding uuencoding expands blocks of 3 bytes into blocks+-- of 4 bytes.  There is however no well defined ending to a piece of encoded+-- data, instead uuencoded data is commonly transferred linewise where each+-- line is prepended with the length of the data in the line.+--+-- This module currently only deals with the encoding.  Chopping the encoded+-- data into lines, and unchopping lines into encoded data is left as an+-- exercise to the reader.  (Patches are welcome.)+module Codec.Binary.Uu+    ( uu_encode_part+    , uu_encode_final+    , uu_decode_part+    , uu_decode_final+    , encode+    , decode+    ) where++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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static uu.h uu_enc_part"+    c_uu_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static uu.h uu_enc_final"+    c_uu_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static uu.h uu_dec_part"+    c_uu_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static uu.h uu_dec_final"+    c_uu_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function encodes as large a portion of the input as possible and+-- returns the encoded part together with the remaining part.  Enough space is+-- allocated for the encoding to make sure that the remaining part is less than+-- 3 bytes long, which means it can be passed to 'uu_encode_final' as is.+--+-- >>> uu_encode_part $ Data.ByteString.Char8.pack "foo"+-- ("9F]O","")+-- >>> uu_encode_part $ Data.ByteString.Char8.pack "foob"+-- ("9F]O","b")+uu_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+uu_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 3 * 4+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_uu_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- The final block has to have a size less than 3.+--+-- >>> uu_encode_final $ Data.ByteString.Char8.pack "r"+-- Just "<@"+--+-- Trying to pass in too large a block result in failure:+--+-- >>> uu_encode_final $ Data.ByteString.Char8.pack "foo"+-- Nothing+uu_encode_final :: BS.ByteString -> Maybe BS.ByteString+uu_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 4+    alloca $ \ pOutLen -> do+        r <- c_uu_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- Decode as large a portion of the input as possible.  Enough data is+-- allocated for the output to ensure that the remainder is less than 4 bytes+-- in size.  Success result in a @Right@ value:+--+-- >>> uu_decode_part $ Data.ByteString.Char8.pack "9F]O"+-- Right ("foo","")+-- >>> uu_decode_part $ Data.ByteString.Char8.pack "9F]O8F$"+-- Right ("foo","8F$")+--+-- Failures occur on bad input and result in a @Left@ value:+--+-- >>> uu_decode_part $ Data.ByteString.Char8.pack "9F 0"+-- Left ("","9F 0")+uu_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+uu_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 4 * 3+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_uu_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- The final block has to have a size of 0 or 4:+--+-- >>> uu_decode_final $ Data.ByteString.Char8.pack "9F\\"+-- Just "fo"+-- >>> uu_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> uu_decode_final $ Data.ByteString.Char8.pack "9F¬"+-- Nothing+--+-- But it must be the encoding of a block that is less than 3 bytes:+--+-- >>> uu_decode_final $ encode $ Data.ByteString.Char8.pack "foo"+-- Nothing+uu_decode_final :: BS.ByteString -> Maybe BS.ByteString+uu_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 3+    alloca $ \ pOutLen -> do+        r <- c_uu_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Convenience function that combines 'uu_encode_part' and+-- 'uu_encode_final' to encode a complete string.+--+-- >>> encode $ Data.ByteString.Char8.pack "foo"+-- "9F]O"+-- >>> encode $ Data.ByteString.Char8.pack "foobar"+-- "9F]O8F%R"+encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = uu_encode_part bs+        Just final = uu_encode_final rest+    in first `BS.append` final++-- | Convenience function that combines 'uu_decode_part' and+-- 'uu_decode_final' to decode a complete string.+--+-- >>> decode $ Data.ByteString.Char8.pack "9F]O"+-- Right "foo"+-- >>> decode $ Data.ByteString.Char8.pack "9F]O8F%R"+-- Right "foobar"+--+-- Failures when decoding returns the decoded part and the remainder:+--+-- >>> decode $ Data.ByteString.Char8.pack "9F]O8F¬R"+-- Left ("foo","8F\172R")+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (uu_decode_final rest))+    (uu_decode_part bs)
+ src/Codec/Binary/Xx.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Xx+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Xxencoding is obsolete but still included for completeness.  Further+-- information on the encoding can be found at+-- <http://en.wikipedia.org/wiki/Xxencode>.  It should be noted that this+-- implementation performs no padding.+--+-- This encoding is very similar to uuencoding, therefore further information+-- regarding the functions can be found in the documentation of+-- "Codec.Binary.Uu".+module Codec.Binary.Xx+    ( xx_encode_part+    , xx_encode_final+    , xx_decode_part+    , xx_decode_final+    , encode+    , decode+    ) where++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++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static uu.h xx_enc_part"+    c_xx_enc_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static uu.h xx_enc_final"+    c_xx_enc_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++foreign import ccall "static uu.h xx_dec_part"+    c_xx_dec_part :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++foreign import ccall "static uu.h xx_dec_final"+    c_xx_dec_final :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- >>> xx_encode_part $ Data.ByteString.Char8.pack "foo"+-- ("Naxj","")+-- >>> xx_encode_part $ Data.ByteString.Char8.pack "foob"+-- ("Naxj","b")+xx_encode_part :: BS.ByteString -> (BS.ByteString, BS.ByteString)+xx_encode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 3 * 4+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_xx_enc_part (castPtr inBuf) (castEnum inLen) outBuf pOutLen pRemBuf pRemLen+                outLen <- peek pOutLen+                remBuf <- peek pRemBuf+                remLen <- peek pRemLen+                remBs <- BS.packCStringLen (castPtr remBuf, castEnum remLen)+                outBs <- unsafePackCStringFinalizer outBuf (castEnum outLen) (free outBuf)+                return (outBs, remBs)++-- | Encoding function for the final block.+--+-- >>> xx_encode_final $ Data.ByteString.Char8.pack "r"+-- Just "QU"+-- >>> xx_encode_final $ Data.ByteString.Char8.pack "foo"+-- Nothing+xx_encode_final :: BS.ByteString -> Maybe BS.ByteString+xx_encode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 4+    alloca $ \ pOutLen -> do+        r <- c_xx_enc_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++-- | Decoding function.+--+-- >>> xx_decode_part $ Data.ByteString.Char8.pack "Naxj"+-- Right ("foo","")+-- >>> xx_decode_part $ Data.ByteString.Char8.pack "NaxjMa3"+-- Right ("foo","Ma3")+--+-- >>> xx_decode_part $ Data.ByteString.Char8.pack "Na j"+-- Left ("","Na J")+xx_decode_part :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) (BS.ByteString, BS.ByteString)+xx_decode_part bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = inLen `div` 4 * 3+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                r <- c_xx_dec_part (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 <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                if r == 0+                    then return $ Right (outBs, remBs)+                    else return $ Left (outBs, remBs)++-- | Decoding function for the final block.+--+-- >>> xx_decode_final $ Data.ByteString.Char8.pack "Naw"+-- Just "fo"+-- >>> xx_decode_final $ Data.ByteString.Char8.pack ""+-- Just ""+-- >>> xx_decode_final $ Data.ByteString.Char8.pack "Na "+-- Nothing+--+-- >>> xx_decode_final $ encode $ Data.ByteString.Char8.pack "foo"+-- Nothing+xx_decode_final :: BS.ByteString -> Maybe BS.ByteString+xx_decode_final bs = U.unsafePerformIO $ unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    outBuf <- mallocBytes 3+    alloca $ \ pOutLen -> do+        r <- c_xx_dec_final (castPtr inBuf) (castEnum inLen) outBuf pOutLen+        if r == 0+            then do+                outLen <- peek pOutLen+                newOutBuf <- reallocBytes outBuf (castEnum outLen)+                outBs <- unsafePackCStringFinalizer newOutBuf (castEnum outLen) (free newOutBuf)+                return $ Just outBs+            else free outBuf >> return Nothing++encode :: BS.ByteString -> BS.ByteString+encode bs = let+        (first, rest) = xx_encode_part bs+        Just final = xx_encode_final rest+    in first `BS.append` final++decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode bs = either+    Left+    (\ (first, rest) ->+        maybe+            (Left (first, rest))+            (\ fin -> Right (first `BS.append` fin))+            (xx_decode_final rest))+    (xx_decode_part bs)
+ src/Codec/Binary/Yenc.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module: Codec.Binary.Yenc+-- Copyright: (c) 2012 Magnus Therning+-- License: BSD3+--+-- Implementation based on the specification found at+-- <http://yence.sourceforge.net/docs/protocol/version1_3_draft.html>.+module Codec.Binary.Yenc+    ( y_enc+    , y_dec+    , encode+    , decode+    ) where++import qualified Data.ByteString as BS+import Foreign+import Foreign.C.Types+import System.IO.Unsafe as U+import qualified Data.ByteString.Unsafe as BSU+import Data.List++castEnum :: (Enum a, Enum b) => a -> b+castEnum = toEnum . fromEnum++foreign import ccall "static yenc.h y_enc"+    c_y_enc :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO ()++foreign import ccall "static yenc.h y_dec"+    c_y_dec :: Ptr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CSize -> IO CInt++-- | Encoding function.+--+-- This function allocates enough space to hold 20% more than the size of the+-- indata (or at least 512 bytes) and then encodes as much as possible of the+-- indata.  That means there is a risk that the encoded data won't fit and in+-- that case the second part of the pair contains the remainder of the indata.+--+-- >>> y_enc $ Data.ByteString.Char8.pack "foobar"+-- ("\144\153\153\140\139\156","")+-- >>> snd $ y_enc $ Data.ByteString.Char8.pack $ Data.List.take 257 $ repeat '\x13'+-- "\DC3"+y_enc :: BS.ByteString -> (BS.ByteString, BS.ByteString)+y_enc bs = U.unsafePerformIO $ BSU.unsafeUseAsCStringLen bs $ \ (inBuf, inLen) -> do+    let maxOutLen = max 512 (ceiling $ (toRational inLen) * 1.2)+    outBuf <- mallocBytes maxOutLen+    alloca $ \ pOutLen ->+        alloca $ \ pRemBuf ->+            alloca $ \ pRemLen -> do+                poke pOutLen (castEnum maxOutLen)+                c_y_enc (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 outBuf)+                return (outBs, remBs)++-- | Decoding function.+--+-- >>> y_dec $ Data.ByteString.pack [144,153,153,140,139,156]+-- Right "foobar"+-- >>> y_dec $ Data.ByteString.Char8.pack "=}"+-- Right "\DC3"+--+-- A @Left@ value is only ever returned on decoding errors.+--+-- >>> y_dec $ Data.ByteString.Char8.pack "="+-- Left ("","=")+y_dec :: BS.ByteString -> Either (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+                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 outBuf)+                if remLen == 0+                    then return $ Right outBs+                    else return $ Left (outBs, remBs)++-- | Convenient function that calls 'y_enc' repeatedly until the whole input+-- data is encoded.+encode :: BS.ByteString -> BS.ByteString+encode = BS.concat . takeWhile (not . BS.null) . unfoldr (Just . y_enc)++-- | A synonym for 'y_dec'.+decode :: BS.ByteString -> Either (BS.ByteString, BS.ByteString) BS.ByteString+decode = y_dec
+ test-src/Main.hs view
@@ -0,0 +1,278 @@+{-# OPTIONS_GHC -XTemplateHaskell #-}++-- Copyright: (c) Magnus Therning, 2012+-- License: BSD3, found in the LICENSE file++module Main where++import Test.Framework+import Test.Framework.TH+import Test.Framework.Providers.HUnit+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 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])++-- {{{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=")++-- {{{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=")++-- {{{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 "/++/")++-- {{{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 "_--_")++-- {{{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")++-- {{{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")++-- {{{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")++-- {{{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")++-- {{{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])++-- {{{1 tests & main+tests = [$(testGroupGenerator)]++main = defaultMain tests