123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
|
/*******************************************************************************
copyright: Copyright (c) 2010 Ulrik Mikaelsson. All rights reserved
license: BSD style: $(LICENSE)
author: Ulrik Mikaelsson
standards: rfc3548, rfc4648
*******************************************************************************/
/*******************************************************************************
This module is used to decode and encode base32 char[] arrays.
Example:
---
char[] blah = "Hello there, my name is Jeff.";
scope encodebuf = new char[allocateEncodeSize(cast(ubyte[])blah)];
char[] encoded = encode(cast(ubyte[])blah, encodebuf);
scope decodebuf = new ubyte[encoded.length];
if (cast(char[])decode(encoded, decodebuf) == "Hello there, my name is Jeff.")
Stdout("yay").newline;
---
Since v1.0
*******************************************************************************/
module tango.util.encode.Base32;
/*******************************************************************************
calculates and returns the size needed to encode the length of the
array passed.
Params:
data = An array that will be encoded
*******************************************************************************/
size_t allocateEncodeSize(const(ubyte[]) data)
{
return allocateEncodeSize(data.length);
}
/*******************************************************************************
calculates and returns the size needed to encode the length passed.
Params:
length = Number of bytes to be encoded
*******************************************************************************/
size_t allocateEncodeSize(size_t length)
{
auto inputbits = length * 8;
auto inputquantas = (inputbits + 39) / 40; // Round upwards
return inputquantas * 8;
}
/*******************************************************************************
encodes data and returns as an ASCII base32 string.
Params:
data = what is to be encoded
buff = buffer large enough to hold encoded data
pad = Whether to pad ascii output with '='-chars
Example:
---
char[512] encodebuf;
char[] myEncodedString = encode(cast(ubyte[])"Hello, how are you today?", encodebuf);
Stdout(myEncodedString).newline; // JBSWY3DPFQQGQ33XEBQXEZJAPFXXKIDUN5SGC6J7
---
*******************************************************************************/
char[] encode(const(ubyte[]) data, char[] buff, bool pad=true)
in
{
assert(data);
assert(buff.length >= allocateEncodeSize(data));
}
body
{
uint i = 0;
ushort remainder; // Carries overflow bits to next char
byte remainlen; // Tracks bits in remainder
foreach (ubyte j; data)
{
remainder = cast(ushort)((remainder<<8) | j);
remainlen += 8;
do {
remainlen -= 5;
buff[i++] = _encodeTable[(remainder>>remainlen)&0b11111];
} while (remainlen > 5);
}
if (remainlen)
buff[i++] = _encodeTable[(remainder<<(5-remainlen))&0b11111];
if (pad) {
for (ubyte padCount= cast(ubyte) (-i%8);padCount > 0; padCount--)
buff[i++] = base32_PAD;
}
return buff[0..i];
}
/*******************************************************************************
encodes data and returns as an ASCII base32 string.
Params:
data = what is to be encoded
pad = whether to pad output with '='-chars
Example:
---
char[] myEncodedString = encode(cast(ubyte[])"Hello, how are you today?");
Stdout(myEncodedString).newline; // JBSWY3DPFQQGQ33XEBQXEZJAPFXXKIDUN5SGC6J7
---
*******************************************************************************/
char[] encode(const(ubyte[]) data, bool pad=true)
in
{
assert(data);
}
body
{
auto rtn = new char[allocateEncodeSize(data)];
return encode(data, rtn, pad);
}
/*******************************************************************************
decodes an ASCII base32 string and returns it as ubyte[] data. Pre-allocates
the size of the array.
This decoder will ignore non-base32 characters. So:
SGVsbG8sIGhvd
yBhcmUgeW91IH
RvZGF5Pw==
Is valid.
Params:
data = what is to be decoded
Example:
---
char[] myDecodedString = cast(char[])decode("JBSWY3DPFQQGQ33XEBQXEZJAPFXXKIDUN5SGC6J7");
Stdout(myDecodeString).newline; // Hello, how are you today?
---
*******************************************************************************/
ubyte[] decode(const(char[]) data)
in
{
assert(data);
}
body
{
auto rtn = new ubyte[data.length];
return decode(data, rtn);
}
/*******************************************************************************
decodes an ASCII base32 string and returns it as ubyte[] data.
This decoder will ignore non-base32 characters. So:
SGVsbG8sIGhvd
yBhcmUgeW91IH
RvZGF5Pw==
Is valid.
Params:
data = what is to be decoded
buff = a big enough array to hold the decoded data
Example:
---
ubyte[512] decodebuf;
char[] myDecodedString = cast(char[])decode("JBSWY3DPFQQGQ33XEBQXEZJAPFXXKIDUN5SGC6J7", decodebuf);
Stdout(myDecodeString).newline; // Hello, how are you today?
---
*******************************************************************************/
ubyte[] decode(const(char[]) data, ubyte[] buff)
in
{
assert(data);
}
body
{
ushort remainder;
byte remainlen;
size_t oIndex;
foreach (c; data)
{
auto dec = _decodeTable[c];
if (dec & 0b1000_0000)
continue;
remainder = cast(ushort)((remainder<<5) | dec);
for (remainlen += 5; remainlen >= 8; remainlen -= 8)
buff[oIndex++] = cast(ubyte) (remainder >> (remainlen-8));
}
return buff[0..oIndex];
}
debug (UnitTest)
{
unittest
{
immutable immutable(char)[][] testBytes = [
"",
"foo",
"foob",
"fooba",
"foobar",
"Hello, how are you today?",
];
immutable immutable(char)[][] testChars = [
"",
"MZXW6===",
"MZXW6YQ=",
"MZXW6YTB",
"MZXW6YTBOI======",
"JBSWY3DPFQQGQ33XEBQXEZJAPFXXKIDUN5SGC6J7",
];
for (uint i; i < testBytes.length; i++) {
auto resultChars = encode(cast(ubyte[])testBytes[i]);
assert(resultChars == testChars[i],
testBytes[i]~": ("~resultChars~") != ("~testChars[i]~")");
auto resultBytes = decode(testChars[i]);
assert(resultBytes == cast(ubyte[])testBytes[i],
testChars[i]~": ("~cast(char[])resultBytes~") != ("~testBytes[i]~")");
}
}
}
private:
/*
Static immutable tables used for fast lookups to
encode and decode data.
*/
immutable ubyte base32_PAD = '=';
immutable char[] _encodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
immutable ubyte[] _decodeTable = [
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0x1A,0x1B, 0x1C,0x1D,0x1E,0x1F, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,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,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
];
|