1 module more.base64; 2 3 immutable encode64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 4 auto formatBase64(T, size_t StackSize = 100)(const(T)[] data) if(T.sizeof == 1) 5 { 6 static struct Formatter 7 { 8 const(T)[] data; 9 void toString(scope void delegate(const(char)[]) sink) const 10 { 11 ubyte stackIndex = 0; 12 size_t dataIndex = 0; 13 char[StackSize] stackBuffer; 14 15 for(; dataIndex + 2 < data.length; dataIndex += 3) 16 { 17 stackBuffer[stackIndex++] = encode64[ (data[dataIndex + 0] >> 2 ) ]; 18 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 0] << 4 | data[dataIndex + 1] >> 4) ]; 19 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 1] << 2 | data[dataIndex + 2] >> 6) ]; 20 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 2] ) ]; 21 if(stackIndex + 3 >= stackBuffer.length) 22 { 23 sink(stackBuffer[0..stackIndex]); 24 stackIndex = 0; 25 } 26 } 27 28 if(dataIndex < data.length) 29 { 30 stackBuffer[stackIndex++] = encode64[ (data[dataIndex + 0] >> 2 ) ]; 31 if(dataIndex + 1 >= data.length) 32 { 33 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 0] << 4 ) ]; 34 stackBuffer[stackIndex++] = '='; 35 stackBuffer[stackIndex++] = '='; 36 } 37 else 38 { 39 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 0] << 4 | data[dataIndex + 1] >> 4) ]; 40 stackBuffer[stackIndex++] = encode64[ 0x3F & (data[dataIndex + 1] << 2 ) ]; 41 stackBuffer[stackIndex++] = '='; 42 } 43 } 44 sink(stackBuffer[0..stackIndex]); 45 } 46 } 47 return Formatter(data); 48 } 49 unittest 50 { 51 import more.test; 52 mixin(scopedTest!"base64"); 53 54 import std.format : format; 55 assert(format("%s", formatBase64("")) == ""); 56 assert(format("%s", formatBase64("f")) == "Zg=="); 57 assert(format("%s", formatBase64("fo")) == "Zm8="); 58 assert(format("%s", formatBase64("foo")) == "Zm9v"); 59 assert(format("%s", formatBase64("foob")) == "Zm9vYg=="); 60 assert(format("%s", formatBase64("fooba")) == "Zm9vYmE="); 61 assert(format("%s", formatBase64("foobar")) == "Zm9vYmFy"); 62 }