Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.base64

@nogc Simple Base64 parsing

License:
Authors:
Harrison Ford
pure @safe ubyte[] decodeBase64(scope const(char)[] data, char plusChar = '+', char slashChar = '/');
Decode a Base64 encoded value, returning the buffer.
pure @safe void decodeBase64(Appender)(scope const(char)[] data, return ref scope Appender appender, char plusChar = '+', char slashChar = '/');
Decode a Base64 encoded value, placing the result onto an Appender.
Examples:
Test decoding of data which has a length which can be cleanly decoded.
{
    enum data = "QUJD";
    assert(data.decodeBase64 == "ABC");
}

{
    enum data = "QQ==";
    assert(data.decodeBase64 == "A");
}

{
    enum data = "YSBiIGMgZCBlIGYgZyBoIGkgaiBrIGwgbSBuIG8gcCBxIHIgcyB0IHUgdiB3IHggeSB6";
    assert(data.decodeBase64 == "a b c d e f g h i j k l m n o p q r s t u v w x y z");
}

{
    enum data = "LCAuIDsgLyBbICcgXSBcID0gLSAwIDkgOCA3IDYgNSA0IDMgMiAxIGAgfiAhIEAgIyAkICUgXiAmICogKCApIF8gKyB8IDogPCA+ID8=";
    assert(data.decodeBase64 == ", . ; / [ ' ] \\ = - 0 9 8 7 6 5 4 3 2 1 ` ~ ! @ # $ % ^ & * ( ) _ + | : < > ?");
}

{
    enum data = "AAA=";
    assert(data.decodeBase64 == "\x00\x00");
}

{
    enum data = "AAAABBCC";
    assert(data.decodeBase64 == "\x00\x00\x00\x04\x10\x82");
}

{
    enum data = "AA==";
    assert(data.decodeBase64 == "\x00");
}

{
    enum data = "AA/=";
    assert(data.decodeBase64 == "\x00\x0f");
}
Examples:
Test decoding invalid data
void testFail(const(char)[] input) @safe pure
{
    bool thrown = false;
    try {
        ubyte[] decoded = input.decodeBase64;
    } catch (Exception t) {
        thrown = true;
    }

    assert(thrown);
}

testFail("===A");
testFail("A=");
testFail("AA=");
testFail("A=AA");
testFail("AA=A");
testFail("AA=A====");
testFail("=AAA");
testFail("AAA=QUJD");
// This fails because we don't allow extra padding (than what is necessary)
testFail("AA======");
// This fails because we don't allow padding before the end of the string (otherwise we'd have a side-channel)
testFail("QU==QUJD");
testFail("QU======QUJD");
// Invalid data that's out of the alphabet
testFail("!@##@@!@");
pure @safe const(char)[] encodeBase64(scope const(ubyte)[] buf, char plusChar = '+', char slashChar = '/');
Encode a ubyte array as Base64, returning the encoded value.
pure @safe void encodeBase64(Appender)(scope const(ubyte)[] input, return ref scope Appender appender, char plusChar = '+', char slashChar = '/');
Encode a ubyte array as Base64, placing the result onto an Appender.
Examples:
Test encoding of data which has a length that can be cleanly encoded.
// 3 bytes
{
    enum data = cast(immutable(ubyte)[])"ABC";
    assert(data.encodeBase64 == "QUJD");
}

// 6 bytes
{
    enum data = cast(immutable(ubyte)[])"ABCDEF";
    assert(data.encodeBase64 == "QUJDREVG");
}

// 9 bytes
{
    enum data = cast(immutable(ubyte)[])"ABCDEFGHI";
    assert(data.encodeBase64 == "QUJDREVGR0hJ");
}

// 12 bytes
{
    enum data = cast(immutable(ubyte)[])"ABCDEFGHIJKL";
    assert(data.encodeBase64 == "QUJDREVGR0hJSktM");
}
Examples:
Test encoding of data which has a length which CANNOT be cleanly encoded. This typically means that there's padding.
// 1 byte 
{
    enum data = cast(immutable(ubyte)[])"A";
    assert(data.encodeBase64 == "QQ==");
}
// 2 bytes
{
    enum data = cast(immutable(ubyte)[])"AB";
    assert(data.encodeBase64 == "QUI=");
}
// 2 bytes
{
    enum data = [0xFF, 0xFF];
    assert(data.encodeBase64 == "//8=");
}
// 4 bytes
{
    enum data = [0xDE, 0xAD, 0xBA, 0xBE];
    assert(data.encodeBase64 == "3q26vg==");
}
// 37 bytes
{
    enum data = cast(immutable(ubyte)[])"A Very Very Very Very Large Test Blob";
    assert(data.encodeBase64 == "QSBWZXJ5IFZlcnkgVmVyeSBWZXJ5IExhcmdlIFRlc3QgQmxvYg==");
}
Examples:
Test nogc encoding
import mir.appender : scopedBuffer;

{
    enum data = cast(immutable(ubyte)[])"A Very Very Very Very Large Test Blob";
    auto appender = scopedBuffer!char();
    data.encodeBase64(appender); 
    assert(appender.data == "QSBWZXJ5IFZlcnkgVmVyeSBWZXJ5IExhcmdlIFRlc3QgQmxvYg==");     
}

{
    enum data = cast(immutable(ubyte)[])"abc123!?$*&()'-=@~";
    auto appender = scopedBuffer!char();
    data.encodeBase64(appender);
    assert(appender.data == "YWJjMTIzIT8kKiYoKSctPUB+");
}
Examples:
Make sure we can decode what we encode.
// Test an example string
{
    enum data = cast(immutable(ubyte)[])"abc123!?$*&()'-=@~";
    assert(data.encodeBase64.decodeBase64 == data);
}
// Test an example from Ion data
{
    enum data = cast(immutable(ubyte)[])"a b c d e f g h i j k l m n o p q r s t u v w x y z";
    assert(data.encodeBase64.decodeBase64 == data);
}