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, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // BASE64 codec; because i can!
18 module iv
.base64
/*is aliced*/;
22 // ////////////////////////////////////////////////////////////////////////// //
23 mixin(NewExceptionClass
!"Base64Exception");
26 // ////////////////////////////////////////////////////////////////////////// //
27 public static immutable string b64alphabet
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 private static immutable ubyte[256] b64dc
= () {
30 ubyte[256] res
= 0xff; // invalid
31 foreach (immutable idx
, immutable char ch
; b64alphabet
) {
32 res
[cast(ubyte)ch
] = cast(ubyte)idx
;
34 res
['='] = 0xfe; // padding
38 res
[127] = 0xf0; // just in case
43 // ////////////////////////////////////////////////////////////////////////// //
44 public void base64Encode(bool padding
=true, RO
, RI
) (auto ref RO ro
, auto ref RI ri
)
45 if (Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: ubyte) &&
46 (Imp
!"std.range.primitives".isOutputRange
!(RO
, char) || Imp
!"std.range.primitives".isOutputRange
!(RO
, ubyte))
52 void encodeChunk() () {
53 if (btspos
== 0) return;
54 ro
.put(b64alphabet
.ptr
[(bts.ptr
[0]&0xfc)>>2]);
56 ro
.put(b64alphabet
.ptr
[(bts.ptr
[0]&0x03)<<4]);
57 static if (padding
) { ro
.put('='); ro
.put('='); }
60 ro
.put(b64alphabet
.ptr
[((bts.ptr
[0]&0x03)<<4)|
((bts.ptr
[1]&0xf0)>>4)]);
62 ro
.put(b64alphabet
.ptr
[(bts.ptr
[1]&0x0f)<<2]);
63 static if (padding
) ro
.put('=');
66 ro
.put(b64alphabet
.ptr
[((bts.ptr
[1]&0x0f)<<2)|
((bts.ptr
[2]&0xc0)>>6)]);
67 ro
.put(b64alphabet
.ptr
[bts.ptr
[2]&0x3f]);
74 ubyte ib
= cast(ubyte)ri
.front
;
76 bts.ptr
[btspos
++] = ib
;
77 if (btspos
== 3) encodeChunk();
79 if (btspos
!= 0) encodeChunk();
82 public OT
[] base64Encode(OT
=ubyte, bool padding
=true, RI
) (auto ref RI ri
)
83 if (!is(RI
: AE
[], AE
) &&
84 Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: ubyte) &&
85 (is(OT
== ubyte) ||
is(OT
== char))
88 static struct OutRange
{
90 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
93 base64Encode
!padding(ro
, ri
);
97 public OT
[] base64Encode(OT
=ubyte, bool padding
=true) (const(void)[] buf
) if (is(OT
== ubyte) ||
is(OT
== char)) {
98 static struct InRange
{
100 pure nothrow @trusted @nogc:
101 @property bool empty () const { pragma(inline
, true); return (data
.length
== 0); }
102 @property ubyte front () const { pragma(inline
, true); return data
.ptr
[0]; }
103 void popFront () { data
= data
[1..$]; }
105 static struct OutRange
{
107 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
109 auto ri
= InRange(cast(const(ubyte)[])buf
);
111 base64Encode
!padding(ro
, ri
);
116 // ////////////////////////////////////////////////////////////////////////// //
117 public void base64Decode(RO
, RI
) (auto ref RO ro
, auto ref RI ri
)
118 if (Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: dchar) &&
119 (Imp
!"std.range.primitives".isOutputRange
!(RO
, char) || Imp
!"std.range.primitives".isOutputRange
!(RO
, ubyte))
122 bool inPadding
= false;
126 void decodeChunk() () {
127 if (btspos
== 0) return;
128 if (btspos
== 1) throw new Base64Exception("incomplete data in base64 decoder");
129 ro
.put(cast(char)((bts.ptr
[0]<<2)|
((bts.ptr
[1]&0x30)>>4))); // 2 and more
130 if (btspos
> 2) ro
.put(cast(char)(((bts.ptr
[1]&0x0f)<<4)|
((bts.ptr
[2]&0x3c)>>2))); // 3 and more
131 if (btspos
> 3) ro
.put(cast(char)(((bts.ptr
[2]&0x03)<<6)|
bts.ptr
[3]));
135 static if (is(typeof(ri
.front
) : char)) {
136 ubyte cb
= b64dc
.ptr
[cast(ubyte)ri
.front
];
139 ubyte cb
= (ccw
>= 0 && ccw
<= 255 ? b64dc
.ptr
[cast(ubyte)ccw
] : 0xff);
141 if (cb
== 0xff) throw new Base64Exception("invalid input char in base64 decoder");
143 if (cb
== 0xf0) continue; // empty
146 if (!inPadding
) { decodeChunk(); inPadding
= true; }
147 if (++btspos
== 4) { inPadding
= false; btspos
= 0; }
151 if (btspos
!= 0) throw new Base64Exception("invalid input char in base64 decoder");
154 bts.ptr
[btspos
++] = cb
;
155 if (btspos
== 4) { decodeChunk(); btspos
= 0; }
158 if (btspos
!= 0 && !inPadding
) decodeChunk(); // assume that it is not padded
161 public OT
[] base64Decode(OT
=ubyte, RI
) (auto ref RI ri
)
162 if (!is(RI
: AE
[], AE
) &&
163 Imp
!"std.range.primitives".isInputRange
!RI
&& is(Imp
!"std.range.primitives".ElementEncodingType
!RI
: dchar) &&
164 (is(OT
== ubyte) ||
is(OT
== char))
167 static struct OutRange
{
169 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
172 base64Decode(ro
, ri
);
176 public OT
[] base64Decode(OT
=ubyte) (const(void)[] buf
) if (is(OT
== ubyte) ||
is(OT
== char)) {
177 static struct InRange
{
179 pure nothrow @trusted @nogc:
180 @property bool empty () const { pragma(inline
, true); return (data
.length
== 0); }
181 @property ubyte front () const { pragma(inline
, true); return data
.ptr
[0]; }
182 void popFront () { data
= data
[1..$]; }
184 static struct OutRange
{
186 void put (const(OT
)[] b
...) nothrow @trusted { if (b
.length
) res
~= b
[]; }
188 auto ri
= InRange(cast(const(ubyte)[])buf
);
190 base64Decode(ro
, ri
);
195 // ////////////////////////////////////////////////////////////////////////// //
196 version(iv_base64_test
) {
199 conwriteln(base64Decode
!char("Zm\r9 vY\tmF\ny\n"), "|");
200 conwriteln(base64Decode
!char("Zg=="), "|");
201 conwriteln(base64Decode
!char("Zg"), "|");
202 conwriteln(base64Decode
!char("Zm8="), "|");
203 conwriteln(base64Decode
!char("Zm8"), "|");
204 conwriteln(base64Decode
!char("Zm9v"), "|");
205 conwriteln(base64Decode
!char("Zm9vYg=="), "|");
206 conwriteln(base64Decode
!char("Zm9vYg="), "|");
207 conwriteln(base64Decode
!char("Zm9vYg"), "|");
208 conwriteln(base64Decode
!char("Zm9vYmE="), "|");
209 conwriteln(base64Decode
!char("Zm9vYmE"), "|");
210 conwriteln(base64Decode
!char("Zm9vYmFy"), "|");
211 conwriteln(base64Decode
!char("Zm9vYmFy==="), "|");
212 conwriteln("==================");
213 conwriteln(base64Encode
!char(""));
214 conwriteln(base64Encode
!char("f"));
215 conwriteln(base64Encode
!char("fo"));
216 conwriteln(base64Encode
!char("foo"));
217 conwriteln(base64Encode
!char("foob"));
218 conwriteln(base64Encode
!char("fooba"));
219 conwriteln(base64Encode
!char("foobar"));