egra: agg mini cosmetix
[iv.d.git] / a85ct.d
blobac16d8bb14037ac45ad0d5e0a701c28fae98dcb5
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 // ASCII85 codec
18 module iv.a85ct /*is aliced*/;
19 import iv.alice;
22 // very slow and enifficient ascii85 decoder
23 string decodeAscii85(T) (const(T)[] src) {
24 static immutable uint[5] pow85 = [85*85*85*85u, 85*85*85u, 85*85u, 85u, 1u];
25 auto data = cast(const(ubyte)[])src;
26 uint tuple = 0;
27 int count = 0;
28 string res = "";
30 void decodeTuple (int bytes) @safe nothrow {
31 while (bytes-- > 0) {
32 res ~= (tuple>>24)&0xff;
33 tuple <<= 8;
37 foreach (immutable b; data) {
38 if (b <= 32 || b > 126) continue; // skip blanks
39 if (b == 'z') {
40 // zero tuple
41 if (count != 0) return null; // alas
42 res ~= "\0\0\0\0";
43 } else {
44 if (b < '!' || b > 'u') return null; // alas
45 tuple += (b-'!')*pow85[count++];
46 if (count == 5) {
47 decodeTuple(4);
48 tuple = 0;
49 count = 0;
53 // write last (possibly incomplete) tuple
54 if (count > 1) {
55 tuple += pow85[--count];
56 decodeTuple(count);
58 return res;
62 string encodeAscii85(T) (const(T)[] src, int width=76) {
63 auto data = cast(const(ubyte)[])src;
64 uint tuple = 0;
65 int count = 0, pos = 0;
66 string res;
68 void encodeTuple () @safe nothrow {
69 int tmp = 5;
70 ubyte[5] buf;
71 usize bpos = 0;
72 do {
73 buf[bpos++] = tuple%85;
74 tuple /= 85;
75 } while (--tmp > 0);
76 tmp = count;
77 do {
78 if (width > 0 && pos >= width) { res ~= '\n'; pos = 0; }
79 res ~= cast(char)(buf[--bpos]+'!');
80 ++pos;
81 } while (tmp-- > 0);
84 foreach (immutable b; data) {
85 switch (count++) {
86 case 0: tuple |= b<<24; break;
87 case 1: tuple |= b<<16; break;
88 case 2: tuple |= b<<8; break;
89 case 3:
90 tuple |= b;
91 if (tuple == 0) {
92 // special case
93 if (width > 0 && pos >= width) { res ~= '\n'; pos = 0; }
94 res ~= 'z';
95 ++pos;
96 } else {
97 encodeTuple();
99 tuple = 0;
100 count = 0;
101 break;
102 default: assert(0);
105 if (count > 0) encodeTuple();
106 return res;
110 // for mixin
111 template a85enc(string s) {
112 private static enum qstr(string s) = s.stringof;
113 enum a85enc = qstr!(encodeAscii85(s, 0));
117 // fox mixin
118 template a85dec(string s) {
119 private static enum qstr(string s) = s.stringof;
120 enum a85dec = qstr!(decodeAscii85(s));
124 version(none) {
125 enum e = encodeAscii85("One, two, Freddy's coming for you");
126 enum s = decodeAscii85(`:Ms_p+EVgG/0IE&ARo=s-Z^D?Df'3+B-:f)EZfXGFT`);
128 void main () {
129 import iv.writer;
130 writeln(s);
131 writeln(decodeAscii85(e) == s);