using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
/*
Copyright (C) 2001,2002 Stef Van Dessel
Based on the "C" implementation of bnews-utils
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
namespace be.usenet.bnews.utils
{
///
/// A port of the C Decoder/Encoder implementation
///
class Engine
{
// assume blocksize = 40 for now
const int DATASIZE = 40;
const int CODESIZE = 41;
private bool debug = false;
public byte[] Decode (byte[] input, int offset)
{
ulong[] temp = new ulong[7];
byte [] output = new byte[40];
int i, j;
temp[0] = (ulong) (input[offset + CODESIZE - 1] - 0x20);
for (i = 1; i < 7; i++)
temp[i] = 0x00;
for (i = 0; i < DATASIZE; i++) {
for (j = 0; j < (i / 6 + 1); j++)
temp[j] *= 0xe0;
temp[0] += (ulong) (input[offset + DATASIZE - 1 - i] - 0x20);
for (j = 0; j < ((i + 1) / 6); j++) {
temp[j + 1] += (temp[j] >> 48);
temp[j] &= 0x0000ffffffffffff;
}
}
for (i = 0; i < DATASIZE; i++)
output[i] = (byte) ((temp[i / 6] >> (8 * (i % 6))) & 0xff);
return output;
}
public byte[] Decode (byte[] input)
{
return Decode(input, 0);
}
public void Debug(bool value) {
this.debug = value;
}
public byte[] Encode (byte[] input) {
return Encode(input, 0);
}
~Engine() {
// Console.WriteLine("Engine Destructed");
}
public byte[] Encode (byte[] input, int offset) {
int i, j;
ulong [] temp = new ulong[7];
byte[] output = new byte[CODESIZE];
for (i = 0; i < 6; i++)
temp[i] = (ulong) 0x00;
for (i = 0; i < DATASIZE; i++) {
temp[i / 7] += ((ulong) input[offset + i] << (8 * (i % 7)));
}
for (i = DATASIZE; i >= 0; i--) {
for (j = i / 7; j > 0; j--) {
temp[j - 1] += (temp[j] % 0xe0) << 56;
temp[j] /= 0xe0;
}
output[DATASIZE - i] = (byte) ((temp[0] % 0xe0) + 0x20);
temp[0] /= 0xe0;
}
return output;
}
public string PrettyPrint (byte[] input) {
return PrettyPrint(input, 0, input.Length);
}
public string PrettyPrint (byte[] input, int offset, int length) {
StringBuilder output =new StringBuilder();
for (int i=offset ; i < offset + length ; i++) {
output.Append(String.Format("{0,3}:{1,3:X} ", i, input[i]));
if (((i + 1) % 10) == 0) {
output.Append("\n");
}
}
output.Append("\n");
return output.ToString();
}
}
class BinaryLineReader
{
private int start = 0;
private int offset = 0;
private int end = 0;
private static int hugebuffer = 16 * 1024;
private static int readbuffer = 8192;
private byte[] input = new byte[hugebuffer];
private Stream stream;
private BinaryReader br;
public BinaryLineReader(Stream s)
{
this.stream = s;
br = new BinaryReader(this.stream, System.Text.Encoding.ASCII);
}
~BinaryLineReader() {
// Console.WriteLine("BinaryLineReader Destructed");
}
public byte [] ReadLine () {
Stream s = this.stream;
byte[] output = null;
do {
end = Array.IndexOf(input, (byte) '\n', offset);
if (end == -1 ) {
if (start > (hugebuffer - readbuffer)) {
Array.Copy( input, offset, input, 0, start - offset);
Array.Clear(input, start - offset, input.Length - (start - offset));
start = start - offset;
offset = 0;
}
int read = br.Read(input, start, readbuffer);
// Console.WriteLine("read {0} bytes", read);
if (read == 0) {
end = 0;
} else {
start += read;
}
} else {
output = new byte[end - offset];
Array.Copy(input, offset, output, 0, end - offset);
end++;
if (input[end] == (byte) '\r') {
end++;
}
offset = end;
}
} while (end < 0);
return output;
}
}
class Application
{
///
/// A stupid app switcher so i don't have to compile it twice or more times
///
static void Main(string[] args) {
if (args.Length > 0) {
string [] newargs = new String[args.Length - 1];
Array.Copy( args, 1,newargs, 0, args.Length - 1);
switch(args[0]) {
case "encode":
Encoder(newargs);
break;
case "decode":
Decoder(newargs);
break;
case "test":
Test(newargs);
break;
case "ulong":
Ulong(newargs);
break;
case "linereader":
LineReader(newargs);
break;
default:
Console.WriteLine("Unknown option: " + args[0]);
break;
}
}
}
static void Ulong(string[] args) {
int i, j;
ulong [] temp = new ulong[7];
int offset = 0;
byte[] input = new byte[40];
for (i=0 ; i < input.Length ; i++) {
input[i] = (byte) 0x01;
}
byte[] output = new byte[41];
for (i = 0; i < 6; i++)
temp[i] = (ulong) 0x00;
for (i = 0; i < 40; i++) {
Console.WriteLine("round = {0}, temp[{1}] = {2:X}", i, i / 7, temp[i / 7]);
Console.WriteLine("broken up: {0:X}, {1}", (ulong) input[offset + i], 8 * (i % 7));
Console.WriteLine("round = {0}, {1:X}", i, ((ulong) input[offset + i] << 8 * (i % 7)));
temp[i / 7] += ((ulong) input[offset + i] << (8 * (i % 7)));
Console.WriteLine("round = {0}, temp[{1}] = {2:X}", i, i / 7, temp[i / 7]);
}
}
static void LineReader(string[] args) {
Stream istream = new FileStream("out", FileMode.Open);
BinaryLineReader si = new BinaryLineReader(istream);
byte[] line = null;
Engine ea = new Engine();
while ((line = si.ReadLine()) != null) {
Console.WriteLine(ea.PrettyPrint(line));
Console.WriteLine("Length: {0}", line.Length);
}
istream.Close();
}
static void Decoder(string[] args) {
string infile = null;
if (args[0] != null) {
infile = args[0];
} else {
infile = "out";
}
Stream istream = new FileStream(args[0], FileMode.Open);
BinaryLineReader si = new BinaryLineReader(istream);
byte[] line = null;
line = si.ReadLine();
// figure out filename + size here.
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string header = enc.GetString(line);
string bpstheader = "<.+)\\]\\s*Size=(?\\d+)\\s*!BPST>>";
Regex r = new Regex(bpstheader);
Match m = r.Match(header);
if (m.Success)
{
// Console.WriteLine("Header matches!!");
// Console.WriteLine("filename = " + m.Groups[1].Value);
// Console.WriteLine("size = " + m.Groups[2].Value);
} else {
throw(new Exception ("not a valid encoded file!"));
}
// int filesize = Convert.ToInt32(m.Groups["size"].Value);
// Stream ostream = new FileStream(m.Groups["file"].Value, FileMode.Create);
int filesize = Convert.ToInt32(m.Groups[2].Value);
Stream ostream = new FileStream(m.Groups[1].Value, FileMode.Create);
int written = 0;
Engine ea = new Engine();
while ((line = si.ReadLine()) != null) {
switch (line.Length % 41) {
case 0:
break;
case 40:
byte[] line2 = new byte[line.Length + 1];
line2[0] = (byte) '.';
Array.Copy(line, 0, line2, 1, line.Length);
line = line2;
break;
default:
Console.WriteLine("Found a bad line");
throw (new Exception("Bad Line"));
break;
}
for (int i = 0; i < line.Length; i += 41) {
byte[] output = ea.Decode(line, i);
if ((filesize - written) < 40) {
ostream.Write(output, 0, filesize - written);
written += filesize - written;
} else {
ostream.Write(output, 0, 40);
written += 40;
}
}
}
istream.Close();
ostream.Close();
}
static void Encoder(string[] args) {
string infile = null;
if (args.Length > 0) {
infile = args[0];
} else {
infile = "in";
}
Stream i = new FileStream(infile, FileMode.Open);
string outfile = null;
if (args.Length > 1) {
outfile = args[1];
} else {
outfile = infile + ".bn";
}
Stream o = new FileStream(outfile, FileMode.Create);
byte[] lf = {(byte) '\n'};
Engine ea = new Engine();
int read;
int written = 0, linelength = 0;
do {
byte[] line = new byte[40];
read = i.Read(line, 0, 40);
byte[] output = ea.Encode(line);
o.Write(output, 0, output.Length);
linelength += output.Length;
written += output.Length;
if (linelength > 240) {
o.Write(lf, 0, 1);
written++;
linelength = 0;
}
} while (read == 40);
// Add trailing newline
if (linelength != 0) {
o.Write(lf, 0, 1);
written++;
}
i.Close();
o.Close();
}
static void Test(string[] args)
{
byte[] inarray = new byte[40];
byte[] outarray = null;
byte[] revarray = null ;
int i, j;
int repeat = 1;
if (args.Length > 0) {
repeat = Convert.ToInt32(args[0]);
}
Random r = new Random();
Engine ea = new Engine();
for (j=0; j < repeat; j++) {
for (i=0 ; i < inarray.Length ; i++) {
// inarray[i] = (byte) r.Next(256);
inarray[i] = (byte) 0x01;
// inarray[i] = (byte) 0xff;
}
// System.Console.WriteLine("Now encoding");
// System.Console.WriteLine("Now decoding");
// ea.Debug(true);
outarray = ea.Encode(inarray);
revarray = ea.Decode(outarray);
if (inarray.Length != revarray.Length) {
throw(new Exception("In and Out Arrays differ in length !!!!!"));
}
for (i=0 ; i < inarray.Length ; i++) {
if (inarray[i] != revarray[i]) {
System.Console.Write(ea.PrettyPrint(inarray));
System.Console.Write(ea.PrettyPrint(outarray));
System.Console.Write(ea.PrettyPrint(revarray));
throw(new Exception(String.Format("In and Out differ at position {0} during run {1} !!!!!", i, j))) ;
}
}
}
}
}
}