zymosis: cosmetix
[iv.d.git] / ascii85.d
blob660628bdd91e6f3641eb6baedaa7b18207872027
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 // ASCII85 codec
19 module iv.ascii85 /*is aliced*/;
21 import std.range;
22 import std.traits;
23 import iv.alice;
26 /// returns input range
27 auto ascii85Decoder(RI) (auto ref RI src)
28 if (isInputRange!RI &&
29 (isSomeChar!(ElementType!RI)) ||
30 is(ElementType!RI : ubyte) ||
31 is(ElementType!RI : byte))
33 static struct A85D {
34 private:
35 static immutable uint[5] pow85 = [85*85*85*85u, 85*85*85u, 85*85u, 85u, 1u];
36 uint btuple = 0;
37 int count = 0;
38 ubyte curCh = 0;
39 static if (isInfinite!RI) {
40 enum bool empty = false;
41 } else {
42 bool isEmpty = false;
44 RI rng = void;
46 public:
47 this() (auto ref RI sr) {
48 if (sr.empty) {
49 static if (!isInfinite!RI) isEmpty = true;
50 rng = rng.init;
51 } else {
52 rng = sr;
53 popFront; // populate curCh
57 static if (!isInfinite!RI) {
58 @property bool empty () const pure nothrow @nogc { return isEmpty; }
60 @property ubyte front () const pure nothrow @nogc { return curCh; }
62 static if (isForwardRange!RI) {
63 @property auto save() () {
64 auto res = this;
65 if (!empty) res.rng = rng.save();
66 return res;
70 // template to allow autodeducing attributes
71 void popFront() () {
72 static if (!isInfinite!RI) {
73 if (isEmpty) { curCh = 0; return; }
75 if (count == 0) {
76 // read more chars
77 btuple = 0;
78 while (count != 5) {
79 if (rng.empty) break;
80 uint b = cast(uint)rng.front;
81 rng.popFront;
82 if (count == 0 && b == 'z') {
83 // 4 zeroes
84 count = 5;
85 } else if (count == 0 && b == 'y') {
86 // 4 spaces
87 count = 5;
88 btuple = 0x20202020;
89 } else if (b >= '!' && b <= 'u') {
90 btuple += (b-'!')*pow85[count++];
93 if (count < 2) {
94 static if (isInfinite!RI) {
95 assert(0);
96 } else {
97 isEmpty = true;
98 curCh = 0;
99 return;
102 if (count != 5) {
103 // we have some bytes ready
104 btuple += pow85[--count];
105 } else {
106 // we have 4 bytes ready
107 count = 4;
110 assert(count > 0);
111 curCh = (btuple>>24)&0xff;
112 btuple <<= 8;
113 --count;
116 return A85D(src);
120 version(test_ascii85)
121 unittest {
122 import std.array;
123 import std.utf : byChar;
125 immutable e = `:Ms_p+EVgG/0IE&ARo=s-Z^D?Df'3+B-:f)EZfXGFT`;
126 immutable s = cast(string)array(ascii85Decoder(e.byChar));
127 //import iv.writer; writeln(s);
128 assert(s == "One, two, Freddy's coming for you");
131 immutable e =
132 ":Ms_p+EVgG/0IE&ARo=s-Z^D?Df'3+B-:f)EZfXGFU\n"~
133 "D)]Eb/f5+D,P7E\\&>\"ATW$*EZf1:@r!34Dfp(CA8cC\n"~
134 ",$:\\`QALnsFBm;0OB6%Ei+CQC&Eckl+AncKB$<(MZA\n"~
135 "Ss%AASGdjF=\\P)Df0H$+EMX5Gp%6K+DbJ.AM+<bBl7\n"~
136 "K5+EV14/0I]!G%G\\:F)5E!E$/S%@;0U3/hRJ";
137 immutable s = cast(string)array(ascii85Decoder(e.byChar));
138 //import iv.writer; writeln(s);
139 assert(s ==
140 "One, two, Freddy's coming for you\n"~
141 "Three, four, Better lock your door\n"~
142 "Five, six, grab a crucifix.\n"~
143 "Seven, eight, Gonna stay up late.\n"~
144 "Nine, ten, Never sleep again...\n");
149 /// returns input range
150 auto ascii85Encoder(RI) (auto ref RI src)
151 if (isInputRange!RI &&
152 (is(ElementType!RI : char) ||
153 is(ElementType!RI : ubyte) ||
154 is(ElementType!RI : byte)))
156 static struct A85E {
157 private:
158 usize bpos = 0;
159 int count = 0;
160 ubyte[5] buf;
161 static if (isInfinite!RI) {
162 enum bool empty = false;
163 } else {
164 bool isEmpty = false;
166 RI rng = void;
168 public:
169 this() (auto ref RI sr) {
170 if (sr.empty) {
171 static if (!isInfinite!RI) isEmpty = true;
172 rng = rng.init;
173 } else {
174 rng = sr;
175 popFront; // populate curCh
179 static if (!isInfinite!RI) {
180 @property bool empty () const pure nothrow @nogc { return isEmpty; }
181 @property char front () const pure nothrow @nogc { return (isEmpty ? 0 : cast(char)buf[bpos]); }
182 } else {
183 @property char front () const pure nothrow @nogc { return cast(char)buf[bpos]; }
186 static if (isForwardRange!RI) {
187 @property auto save() () {
188 auto res = this;
189 if (!empty) res.rng = rng.save();
190 return res;
194 // template to allow autodeducing attributes
195 void popFront() () {
196 static if (!isInfinite!RI) {
197 if (isEmpty) return;
199 if (count > 0) {
200 --bpos;
201 --count;
202 return;
204 // read at most 4 bytes and encode 'em
205 count = 0;
206 uint btuple = 0;
207 while (count < 4) {
208 if (rng.empty) break;
209 auto b = cast(uint)rng.front;
210 rng.popFront;
211 btuple |= b<<((3-count)*8);
212 ++count;
214 if (count < 1) {
215 static if (isInfinite!RI) {
216 assert(0);
217 } else {
218 isEmpty = true;
219 return;
222 if (count == 4 && btuple == 0) {
223 // special case
224 bpos = 1;
225 buf[0] = 'z';
226 } else {
227 // encode tuple
228 for (bpos = 0; bpos < 5; ++bpos) {
229 buf[bpos] = btuple%85+'!';
230 btuple /= 85;
232 --bpos; // current char
236 return A85E(src);
240 version(test_ascii85)
241 unittest {
242 import std.array;
243 import std.utf : byChar;
245 immutable s = "One, two, Freddy's coming for you";
246 immutable e = cast(string)array(ascii85Encoder(s.byChar));
247 assert(e == `:Ms_p+EVgG/0IE&ARo=s-Z^D?Df'3+B-:f)EZfXGFT`);
248 //import iv.writer; writeln(e);
251 immutable s =
252 "One, two, Freddy's coming for you\n"~
253 "Three, four, Better lock your door\n"~
254 "Five, six, grab a crucifix.\n"~
255 "Seven, eight, Gonna stay up late.\n"~
256 "Nine, ten, Never sleep again...\n";
257 immutable e = cast(string)array(ascii85Encoder(s.byChar));
258 assert(e ==
259 ":Ms_p+EVgG/0IE&ARo=s-Z^D?Df'3+B-:f)EZfXGFU"~
260 "D)]Eb/f5+D,P7E\\&>\"ATW$*EZf1:@r!34Dfp(CA8cC"~
261 ",$:\\`QALnsFBm;0OB6%Ei+CQC&Eckl+AncKB$<(MZA"~
262 "Ss%AASGdjF=\\P)Df0H$+EMX5Gp%6K+DbJ.AM+<bBl7"~
263 "K5+EV14/0I]!G%G\\:F)5E!E$/S%@;0U3/hRJ");
264 //import iv.writer; writeln(e);