static void ApplyParameters(CodecBase codec, string parameterText) { var type = codec.GetType(); var props = Utility.GetPropertiesWith <CodecParameterAttribute>(type).ToList(); parameterText = parameterText.Trim(new char[] { ':' }); var phrases = parameterText.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); foreach (var phrase in phrases) { var tokens = phrase.Split(new[] { '=' }); uint value; if (tokens.Length != 2 || !UInt32.TryParse(tokens[1], out value)) { Console.WriteLine($"Error! unknown parameter {phrase}"); continue; } var property = props.FirstOrDefault(p => { var attr = p.GetCustomAttribute(typeof(CodecParameterAttribute)) as CodecParameterAttribute; return(attr != null && attr.SymbolName == tokens[0]); } ); if (property == null) { Console.WriteLine($"Error! unknown parameter {phrase}"); continue; } property.SetValue(codec, value); Console.WriteLine($"Codec {codec.GetType().Name.Replace("Codec","")} parameter {property.Name} set to {value}"); } }
public static void Optimize(byte [] data) { var entropy = CodecBase.ComputeShannonEntropy(data); var ratio = entropy / 8.0; Console.WriteLine($"Shannon entropy {entropy:F3} -> ratio {ratio:F3}"); //var codec = new LZCLCodec(); //codec.Options |= LZCLCodec.OptionFlags.DumpOptimize; //codec.OutputWriter = Console.Out; //codec.Optimize(data); }
// items to show (when relevant): // codec, success, uncompressed size, compressed size, compression ratio, compression ticks, decompression ticks, filesize, filename private void DumpResult(Result result, CodecBase codec, string filename) { var length = 0L; if (File.Exists(filename)) { var fi = new FileInfo(filename); length = fi.Length; } var codecName = codec.CodecName;//GetType().Name; Write($"{codecName,10}, {result.Success, 5}, {result.UncompressedLength,8}, {result.CompressedLength,8}, {result.Ratio:F3}, "); Write($"{result.CompressionTicks,10}, {result.DecompressionTicks,10}, "); Write($"{length,10}, {filename}, "); WriteLine(); }
/// <summary> /// Test data round-trip. /// Gather info about it and return in result /// </summary> /// <param name="request"></param> /// <param name="codec"></param> /// <param name="data"></param> /// <returns></returns> Result TestDataRoundtrip(Request request, CodecBase codec, byte [] data) { var result = new Result(); var timer = new Stopwatch(); timer.Start(); var compressed = codec.Compress(data); timer.Stop(); result.CompressionTicks = timer.ElapsedTicks; result.CompressedLength = compressed?.Length ?? 0; result.UncompressedLength = data.Length; result.Success = true; // assume succeeded if (request.Decompress) { timer.Reset(); byte[] decompressed; if (request.UseExternalDecompressor) { byte canary = (byte)(data.Length ^ 0x5A); // check survives var decompressedCanary = new byte[data.Length + 1]; decompressedCanary[decompressedCanary.Length - 1] = canary; if (codec.GetType() == typeof(HuffmanCodec) && compressed != null) { timer.Start(); NativeMethods.DecompressHuffman(compressed, compressed.Length, decompressedCanary, decompressedCanary.Length - 1); timer.Stop(); } else if (codec.GetType() == typeof(Lz77Codec) && compressed != null) { timer.Start(); NativeMethods.DecompressLZ77(compressed, compressed.Length, decompressedCanary, decompressedCanary.Length - 1); timer.Stop(); } else if (codec.GetType() == typeof(ArithmeticCodec) && compressed != null) { timer.Start(); NativeMethods.DecompressArithmetic(compressed, compressed.Length, decompressedCanary, decompressedCanary.Length - 1); timer.Stop(); } else if (codec.GetType() == typeof(LzclCodec) && compressed != null) { timer.Start(); NativeMethods.DecompressLZCL(compressed, compressed.Length, decompressedCanary, decompressedCanary.Length - 1); timer.Stop(); } if (decompressedCanary[decompressedCanary.Length - 1] != canary) { throw new Exception("Decompression canary overwritten!"); } // must shrink decompressed to proper size for compare decompressed = new byte[data.Length]; Array.Copy(decompressedCanary, decompressed, decompressed.Length); } else { timer.Start(); decompressed = codec.Decompress(compressed); timer.Stop(); } result.DecompressionTicks = timer.ElapsedTicks; result.Success = CodecBase.CompareBytes(data, decompressed); } return(result); }
static int PerformCommand(Options opts) { if (opts.Testing) { DoTesting(); return(1); } // create list of codecs var codecs = new List <CodecBase>(); for (var i = 0; i < opts.CodecIndices.Count; ++i) { var ci = opts.CodecIndices[i]; CodecBase codec = null; switch (CodecNames[ci]) { case "Arithmetic": codec = new ArithmeticCodec(); break; case "Huffman": codec = new HuffmanCodec(); break; case "Lz77": codec = new Lz77Codec(); break; case "Lzcl": codec = new LzclCodec(); break; default: Console.Error.WriteLine($"Unknown codec {CodecNames[ci]}"); break; } ApplyParameters(codec, opts.CodecParameters[i]); if (codec != null) { codecs.Add(codec); } } if (!codecs.Any()) { Console.Error.WriteLine("No codec(s) specified"); return(-2); } if (opts.Verbose) { foreach (var c in codecs) { c.OutputWriter = Console.Out; // todo - flags? } } // if has input file and output file then do that if (!String.IsNullOrEmpty(opts.Inputfile) && !String.IsNullOrEmpty(opts.Outputfile)) { if (!File.Exists(opts.Inputfile)) { Console.Error.WriteLine($"File {opts.Inputfile} does not exist"); Environment.Exit(-3); } // do first codec only var data = File.ReadAllBytes(opts.Inputfile); var watch = System.Diagnostics.Stopwatch.StartNew(); var output = opts.Decompress ? codecs[0].Decompress(data) : codecs[0].Compress(data); var headerMsg = $"File {opts.Inputfile} compressed from {data.Length} to {output.Length} for {(double)output.Length/data.Length:F3} ratio"; if (codecs[0] is Lz77Codec) { var lz77 = codecs[0] as Lz77Codec; var bufSize = Math.Max(lz77.MaximumDistance, lz77.MaximumLength) + 1; headerMsg += $" LZ77 bufsize {bufSize}"; } if (codecs[0] is LzclCodec) { var lzcl = codecs[0] as LzclCodec; var bufSize = Math.Max(lzcl.MaximumDistance, lzcl.MaximumLength) + 1; headerMsg += $" LZCL bufsize {bufSize}"; } OutputData(opts.Outputfile, output, OutputFormats[opts.OutputFormatIndex], headerMsg); watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; var actionText = opts.Decompress ? "decompressed" : "compressed"; Console.WriteLine( $"{Path.GetFileName(opts.Inputfile)} ({data.Length} bytes) {actionText} to {opts.Outputfile} ({output.Length} bytes)."); if (!opts.Decompress) { Console.WriteLine($"Compression ratio {100 - (100.0 * output.Length / data.Length):F1}%"); } Console.WriteLine($"Elapsed time: {elapsedMs}ms"); return(1); } // if has only input file - do some testing if (!String.IsNullOrEmpty(opts.Inputfile)) { //public string Inputfile { get; set; } = ""; //public bool RecurseDirectories { get; set; } = false; //public int OutputFormatIndex { get; set; } = -1; //public bool Decompress { get; set; } = false; var test = new Testing(); var request = new Testing.Request { Codecs = codecs, Filename = "*.*", Path = opts.Inputfile, RecurseFiles = opts.RecurseDirectories, // Decompress = false, // UseExternalDecompressor = true, ShowOnlyErrors = false, TrapErrors = true }; test.DoTest(request); return(1); } Console.Error.WriteLine("Nothing to do"); return(-4); }