PageRenderTime 45ms CodeModel.GetById 11ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/decoders/binary/yEnc.d

http://github.com/wilkie/djehuty
D | 325 lines | 197 code | 85 blank | 43 comment | 80 complexity | 91baa1e0a4ad4751187e12a9bc1de4af MD5 | raw file
  1/*
  2 * yEnc.d
  3 *
  4 * This file implements the yEnc algorithm.
  5 *
  6 * Author: Dave Wilkinson
  7 *
  8 */
  9
 10module decoders.binary.yEnc;
 11
 12import core.endian;
 13import core.stream;
 14import core.definitions;
 15
 16import decoders.binary.decoder;
 17
 18private {
 19
 20	const auto YENC_STATE_INIT 				= 0;
 21
 22	const auto YENC_STATE_READHEADER 		= 1;
 23	const auto YENC_STATE_READHEADERVALUE 	= 2;
 24	const auto YENC_STATE_READHEADERNAME 	= 3;
 25
 26	const auto YENC_STATE_READLINE_START 	= 4;
 27	const auto YENC_STATE_READLINE 			= 5;
 28
 29	const auto YENC_STATE_READ_ESCAPE 		= 6;
 30
 31	const auto YENC_STATE_READFOOTER 		= 7;
 32
 33}
 34
 35// Section: Codecs/Binary
 36
 37// Description: This represents the yEnc Codec.
 38class yEncDecoder : BinaryDecoder {
 39
 40	StreamData decode(Stream stream, Stream toStream) {
 41		ushort chunk;
 42		char linestr[257];
 43		uint line;
 44		uint size;
 45
 46		ubyte chr;
 47		ubyte linepos = 0;
 48
 49		ubyte headeroption = 0;
 50
 51
 52		for (;;) {
 53
 54			switch (decoderState) {
 55
 56				case YENC_STATE_INIT:
 57
 58					decoderState = YENC_STATE_READHEADER;
 59
 60					if(!stream.read(chunk)) {
 61						return StreamData.Required;
 62					}
 63
 64					if (chunk == ('=' | ('y'<<8))) {
 65						//escape sequence (valid header)
 66
 67						linepos = 0;
 68						decoderState = YENC_STATE_READHEADER;
 69					}
 70					else {
 71						return StreamData.Invalid;
 72					}
 73
 74					continue;
 75
 76				case YENC_STATE_READHEADER:
 77
 78					// read the rest of the line
 79					if(!stream.read(chr)) {
 80						return StreamData.Required;
 81					}
 82
 83					if ((chr == ' ') || (chr == '=')) {
 84						// delimiter
 85						linestr[linepos] = 0;
 86						linepos = 0;
 87
 88						// get the token
 89						if (!(linestr == "line")) {
 90							decoderState = YENC_STATE_READHEADERVALUE;
 91							headeroption = 0;
 92							continue;
 93						}
 94						else if (!(linestr == "size")) {
 95							decoderState = YENC_STATE_READHEADERVALUE;
 96							headeroption = 1;
 97							continue;
 98						}
 99						else if (!(linestr == "name")) {
100							decoderState = YENC_STATE_READHEADERNAME;
101							headeroption = 2;
102							continue;
103						}
104					}
105					else if (chr == '\r') {
106						continue;
107					}
108					else if (chr == '\n') {
109						decoderState = YENC_STATE_READLINE_START;
110						continue;
111					}
112					else {
113						linestr[linepos] = chr;
114						linepos++;
115					}
116
117					continue;
118
119				case YENC_STATE_READHEADERVALUE:
120
121					// ignore whitespace, =, etc until a value is read
122
123
124					// read the rest of the line
125					if(!stream.read(chr)) {
126						return StreamData.Required;
127					}
128
129
130					if ((chr == ' ') || (chr == '=') || (chr == '\n') || (chr == '\r')) {
131						if (linepos == 0) {
132							// ignore this
133							continue;
134						}
135
136						// delimiter
137						linestr[linepos] = 0;
138
139						// get the token
140						if (headeroption == 0) {
141							// TODO: Int to String Functions
142							//line = cast(uint)atoi(cast(StringLiteral8)linestr);
143						} else {
144							// TODO: Int to String Functions
145							//size = cast(uint)atoi(cast(StringLiteral8)linestr);
146						}
147
148						if (chr == '\r') {
149							continue;
150						}
151						else if (chr == '\n') {
152							decoderState = YENC_STATE_READLINE_START;
153							continue;
154						}
155						else {
156							linepos = 0;
157							decoderState = YENC_STATE_READHEADER;
158						}
159
160						continue;
161
162					}
163
164					linestr[linepos] = chr;
165					linepos++;
166
167					continue;
168
169				case YENC_STATE_READHEADERNAME:
170
171					// ignore whitespace, =, etc until a value is read
172
173
174					// read the rest of the line
175					if(!stream.read(chr)) {
176						return StreamData.Required;
177					}
178
179
180					if ((chr == ' ') || (chr == '=') || (chr == '\n') || (chr == '\r')) {
181						if (linepos == 0) {
182							// ignore this
183							continue;
184						}
185
186						// delimiter
187						linestr[linepos] = 0;
188
189						// get the token
190						//if (headeroption == 0)
191						//{
192						//	line = atoi(linestr);
193						//} else {
194						//	size = atoi(linestr);
195						//}
196
197						if (chr == '\r') {
198							continue;
199						}
200						else if (chr == '\n') {
201							decoderState = YENC_STATE_READLINE_START;
202							continue;
203						}
204						else {
205							linepos = 0;
206							decoderState = YENC_STATE_READHEADER;
207						}
208
209						continue;
210
211					}
212
213					linestr[linepos] = chr;
214					linepos++;
215
216					continue;
217
218
219				case YENC_STATE_READLINE_START:
220
221					if(!stream.read(chunk)) {
222						return StreamData.Required;
223					}
224
225					if (chunk == ('=' | ('y'<<8))) {
226						//escape sequence (valid footer)
227
228						linepos = 0;
229						decoderState = YENC_STATE_READFOOTER;
230						continue;
231					}
232					else {
233						// decode these two bytes
234
235						// DECODE!
236						chr = cast(ubyte)(chunk & 0xFF);
237						if (chr == '=') {
238							chr = cast(ubyte)(chunk >> 8);
239							chr -= 64;
240
241							toStream.write(&chr, 1);
242						}
243						else {
244							chr -= 42;
245							toStream.write(&chr, 1);
246							chr = cast(ubyte)(chunk >> 8);
247
248							if (chr == '=')
249							{
250								decoderState = YENC_STATE_READ_ESCAPE;
251								continue;
252							}
253							else
254							{
255								chr -= 42;
256								toStream.write(&chr, 1);
257							}
258						}
259
260						decoderState = YENC_STATE_READLINE;
261					}
262
263					continue;
264
265
266				case YENC_STATE_READLINE:
267
268					// pull a byte, decode it!
269
270					if(!stream.read(chr)) {
271						return StreamData.Required;
272					}
273
274					if (chr == '\r') {
275						// ignore carriage returns
276						continue;
277					}
278
279					if (chr == '\n') {
280						// line feeds... goto next line!
281						// check for accuracy?
282
283						decoderState = YENC_STATE_READLINE_START;
284						continue;
285					}
286
287					if (chr == '=') {
288						decoderState = YENC_STATE_READ_ESCAPE;
289						continue;
290					}
291
292					// decode character
293
294					chr -= 42;
295					toStream.write(&chr, 1);
296
297					continue;
298
299				case YENC_STATE_READ_ESCAPE:
300
301					if(!stream.read(chr)) {
302						return StreamData.Required;
303					}
304
305					// decode character
306
307					chr -= 106;
308					toStream.write(&chr, 1);
309
310					decoderState = YENC_STATE_READLINE;
311					continue;
312
313				case YENC_STATE_READFOOTER:
314
315					return StreamData.Complete;
316
317				default: 
318					break;
319			}
320			break;
321		}
322
323		return StreamData.Invalid;
324	}
325}