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 +27/−0
- Setup.hs +22/−0
- csrc/b16.c +75/−0
- csrc/b16.h +17/−0
- csrc/b32.c +245/−0
- csrc/b32.h +21/−0
- csrc/b32hex.c +245/−0
- csrc/b32hex.h +21/−0
- csrc/b64.c +165/−0
- csrc/b64.h +21/−0
- csrc/b64url.c +165/−0
- csrc/b64url.h +21/−0
- csrc/b85.c +236/−0
- csrc/b85.h +21/−0
- csrc/qp.c +91/−0
- csrc/qp.h +17/−0
- csrc/uu.c +166/−0
- csrc/uu.h +21/−0
- csrc/xx.c +167/−0
- csrc/xx.h +21/−0
- csrc/yenc.c +66/−0
- csrc/yenc.h +17/−0
- sandi.cabal +71/−0
- src/Codec/Binary/Base16.hs +96/−0
- src/Codec/Binary/Base32.hs +192/−0
- src/Codec/Binary/Base32Hex.hs +176/−0
- src/Codec/Binary/Base64.hs +192/−0
- src/Codec/Binary/Base64Url.hs +123/−0
- src/Codec/Binary/Base85.hs +182/−0
- src/Codec/Binary/QuotedPrintable.hs +121/−0
- src/Codec/Binary/Uu.hs +198/−0
- src/Codec/Binary/Xx.hs +155/−0
- src/Codec/Binary/Yenc.hs +97/−0
- test-src/Main.hs +278/−0
+ 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