1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // BASE64 codec; because i can!
19 module iv
.base64
/*is aliced*/;
23 // ////////////////////////////////////////////////////////////////////////// //
24 mixin(NewExceptionClass
!"Base64Exception");
27 // ////////////////////////////////////////////////////////////////////////// //
28 public static immutable string b64alphabet
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
30 private static immutable ubyte[256] b64dc
= () {
31 ubyte[256] res
= 0xff; // invalid
32 foreach (immutable idx
, immutable char ch
; b64alphabet
) {
33 res
[cast(ubyte)ch
] = cast(ubyte)idx
;
35 res
['='] = 0xfe; // padding
39 res
[127] = 0xf0; // just in case
44 // ////////////////////////////////////////////////////////////////////////// //
45 public void base64Encode(bool padding
=true, RO
, RI
) (auto ref RO ro
, auto ref RI ri
)
46 if (Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: ubyte) &&
47 (Imp
!"std.range.primitives".isOutputRange
!(RO
, char) || Imp
!"std.range.primitives".isOutputRange
!(RO
, ubyte))
53 void encodeChunk() () {
54 if (btspos
== 0) return;
55 ro
.put(b64alphabet
.ptr
[(bts.ptr
[0]&0xfc)>>2]);
57 ro
.put(b64alphabet
.ptr
[(bts.ptr
[0]&0x03)<<4]);
58 static if (padding
) { ro
.put('='); ro
.put('='); }
61 ro
.put(b64alphabet
.ptr
[((bts.ptr
[0]&0x03)<<4)|
((bts.ptr
[1]&0xf0)>>4)]);
63 ro
.put(b64alphabet
.ptr
[(bts.ptr
[1]&0x0f)<<2]);
64 static if (padding
) ro
.put('=');
67 ro
.put(b64alphabet
.ptr
[((bts.ptr
[1]&0x0f)<<2)|
((bts.ptr
[2]&0xc0)>>6)]);
68 ro
.put(b64alphabet
.ptr
[bts.ptr
[2]&0x3f]);
75 ubyte ib
= cast(ubyte)ri
.front
;
77 bts.ptr
[btspos
++] = ib
;
78 if (btspos
== 3) encodeChunk();
80 if (btspos
!= 0) encodeChunk();
83 public OT
[] base64Encode(OT
=ubyte, bool padding
=true, RI
) (auto ref RI ri
)
84 if (!is(RI
: AE
[], AE
) &&
85 Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: ubyte) &&
86 (is(OT
== ubyte) ||
is(OT
== char))
89 static struct OutRange
{
91 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
94 base64Encode
!padding(ro
, ri
);
98 public OT
[] base64Encode(OT
=ubyte, bool padding
=true) (const(void)[] buf
) if (is(OT
== ubyte) ||
is(OT
== char)) {
99 static struct InRange
{
101 pure nothrow @trusted @nogc:
102 @property bool empty () const { pragma(inline
, true); return (data
.length
== 0); }
103 @property ubyte front () const { pragma(inline
, true); return data
.ptr
[0]; }
104 void popFront () { data
= data
[1..$]; }
106 static struct OutRange
{
108 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
110 auto ri
= InRange(cast(const(ubyte)[])buf
);
112 base64Encode
!padding(ro
, ri
);
117 // ////////////////////////////////////////////////////////////////////////// //
118 public void base64Decode(RO
, RI
) (auto ref RO ro
, auto ref RI ri
)
119 if (Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: dchar) &&
120 (Imp
!"std.range.primitives".isOutputRange
!(RO
, char) || Imp
!"std.range.primitives".isOutputRange
!(RO
, ubyte))
123 bool inPadding
= false;
127 void decodeChunk() () {
128 if (btspos
== 0) return;
129 if (btspos
== 1) throw new Base64Exception("incomplete data in base64 decoder");
130 ro
.put(cast(char)((bts.ptr
[0]<<2)|
((bts.ptr
[1]&0x30)>>4))); // 2 and more
131 if (btspos
> 2) ro
.put(cast(char)(((bts.ptr
[1]&0x0f)<<4)|
((bts.ptr
[2]&0x3c)>>2))); // 3 and more
132 if (btspos
> 3) ro
.put(cast(char)(((bts.ptr
[2]&0x03)<<6)|
bts.ptr
[3]));
136 static if (is(typeof(ri
.front
) : char)) {
137 ubyte cb
= b64dc
.ptr
[cast(ubyte)ri
.front
];
140 ubyte cb
= (ccw
>= 0 && ccw
<= 255 ? b64dc
.ptr
[cast(ubyte)ccw
] : 0xff);
142 if (cb
== 0xff) throw new Base64Exception("invalid input char in base64 decoder");
144 if (cb
== 0xf0) continue; // empty
147 if (!inPadding
) { decodeChunk(); inPadding
= true; }
148 if (++btspos
== 4) { inPadding
= false; btspos
= 0; }
152 if (btspos
!= 0) throw new Base64Exception("invalid input char in base64 decoder");
155 bts.ptr
[btspos
++] = cb
;
156 if (btspos
== 4) { decodeChunk(); btspos
= 0; }
159 if (btspos
!= 0 && !inPadding
) decodeChunk(); // assume that it is not padded
162 public OT
[] base64Decode(OT
=ubyte, RI
) (auto ref RI ri
)
163 if (!is(RI
: AE
[], AE
) &&
164 Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: dchar) &&
165 (is(OT
== ubyte) ||
is(OT
== char))
168 static struct OutRange
{
170 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
173 base64Decode(ro
, ri
);
177 public OT
[] base64Decode(OT
=ubyte) (const(void)[] buf
) if (is(OT
== ubyte) ||
is(OT
== char)) {
178 static struct InRange
{
180 pure nothrow @trusted @nogc:
181 @property bool empty () const { pragma(inline
, true); return (data
.length
== 0); }
182 @property ubyte front () const { pragma(inline
, true); return data
.ptr
[0]; }
183 void popFront () { data
= data
[1..$]; }
185 static struct OutRange
{
187 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
189 auto ri
= InRange(cast(const(ubyte)[])buf
);
191 base64Decode(ro
, ri
);
196 // ////////////////////////////////////////////////////////////////////////// //
197 version(iv_base64_test
) {
200 conwriteln(base64Decode
!char("Zm\r9 vY\tmF\ny\n"), "|");
201 conwriteln(base64Decode
!char("Zg=="), "|");
202 conwriteln(base64Decode
!char("Zg"), "|");
203 conwriteln(base64Decode
!char("Zm8="), "|");
204 conwriteln(base64Decode
!char("Zm8"), "|");
205 conwriteln(base64Decode
!char("Zm9v"), "|");
206 conwriteln(base64Decode
!char("Zm9vYg=="), "|");
207 conwriteln(base64Decode
!char("Zm9vYg="), "|");
208 conwriteln(base64Decode
!char("Zm9vYg"), "|");
209 conwriteln(base64Decode
!char("Zm9vYmE="), "|");
210 conwriteln(base64Decode
!char("Zm9vYmE"), "|");
211 conwriteln(base64Decode
!char("Zm9vYmFy"), "|");
212 conwriteln(base64Decode
!char("Zm9vYmFy==="), "|");
213 conwriteln("==================");
214 conwriteln(base64Encode
!char(""));
215 conwriteln(base64Encode
!char("f"));
216 conwriteln(base64Encode
!char("fo"));
217 conwriteln(base64Encode
!char("foo"));
218 conwriteln(base64Encode
!char("foob"));
219 conwriteln(base64Encode
!char("fooba"));
220 conwriteln(base64Encode
!char("foobar"));