C# classes to decode yEnc and UuEncode encoded Usenet binaries
//
// Simple Usenet article decoders; includes classes to decode
// either yEnc or UuEncoded binaries. In either case you
// instantiate the appropriate class passing it the stream
// you want output written to, and then feed it the input lines
// via the DecodeLine method.
//
// by Steve Tibbett
//
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text;
using System.IO;
namespace NntpLib
{
public abstract class ArticleDecoder
{
protected Stream outStream = null;
public ArticleDecoder(Stream OutputStream)
{
outStream = OutputStream;
}
public abstract bool DecodeLine(string line);
}
public class YencDecoder : ArticleDecoder
{
bool inBody = false;
bool inCode = false;
string beginLine;
public YencDecoder(Stream OutputStream, string BeginLine) : base(OutputStream)
{
this.beginLine = BeginLine;
}
/// <summary>
/// Returns true when we're done (we've found the
/// encoded block, and completed decoding it)
/// </summary>
public override bool DecodeLine(string line)
{
if (!inBody)
{
if (line.StartsWith("=ybegin "))
{
inBody = true;
return false;
};
}
if (line.StartsWith("=yend "))
{
// Done
return true;
}
if (!inCode)
{
if (line.StartsWith("=ypart "))
inCode = true;
return false;
};
byte[] lineBytes = Encoding.UTF8.GetBytes(line);
byte[] outBytes = new byte[lineBytes.Length];
int outByte = 0;
for (int i=0; i<lineBytes.Length; i++)
{
lineBytes[i] = (byte)((lineBytes[i] + 42) & 0xff);
char ch = (char)lineBytes[i];
if (ch == '=')
{
i++;
outBytes[outByte++] = (byte)((lineBytes[i]+64)&0xff);
} else
{
outBytes[outByte++] = lineBytes[i];
};
};
outStream.Write(outBytes, 0, outByte);
return false;
}
}
/// <summary>
/// Summary description for Article.
/// </summary>
public class UuDecoder : ArticleDecoder
{
bool inBody = false;
bool inCode = false;
string beginLine;
public UuDecoder(Stream OutputStream, string BeginLine) : base(OutputStream)
{
beginLine = BeginLine;
}
public static byte[] uuDecode(string sBuffer)
{
// Create an output array
byte[] outBuffer = new byte[(sBuffer.Length-1)/4*3];
int outIdx = 0;
// Get the string as an array of ASCII bytes
byte[] asciiBytes = Encoding.ASCII.GetBytes(sBuffer);
for (int i=0; i<asciiBytes.Length; i++)
asciiBytes[i] = (byte)((asciiBytes[i]-0x20) & 0x3f);
// Convert each block fo 4 input bytes into 3
// output bytes
for (int i = 1; i <= (asciiBytes.Length-1); i += 4)
{
outBuffer[outIdx++] = (byte)(asciiBytes[i] << 2 | asciiBytes[i+1] >> 4);
outBuffer[outIdx++] = (byte)(asciiBytes[i+1] << 4 | asciiBytes[i+2] >> 2);
outBuffer[outIdx++] = (byte)(asciiBytes[i+2] << 6 | asciiBytes[i+3]);
}
return outBuffer;
}
/// <summary>
/// Returns true when we're done (we've found the
/// encoded block, and completed decoding it)
/// </summary>
public override bool DecodeLine(string line)
{
if (line.Length == 0 && !inBody)
{
inBody = true;
return false;
};
if (inBody && line.StartsWith("begin"))
{
inCode = true;
return false;
};
if (inCode)
{
if (line.Length < 5)
return true;
byte[] data = uuDecode(line);
outStream.Write(data, 0, data.Length);
};
return false;
}
}
}