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))) ; } } } } } }