using Fr.BahaBulle.Tools.Common; using Fr.BahaBulle.Tools.Parser; using Fr.BahaBulle.Tools.TraceLog; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; namespace Fr.BahaBulle.Compression.Valis { internal static class cValis { private struct st_param { public int length; public int offset; } public static bool ValisDecompression(List param) { Parser parser = Parser.INSTANCE; if (param.Count != 2) { Trace.WriteLine(string.Format("Number of parameters incorrect - 2 waited ; got {0}", param.Count)); return false; } Parser.stStream source = default(Parser.stStream); long source_adress = 0; Parser.stStream destination = default(Parser.stStream); object obj; foreach (Parser.stParam arg in param) { if (arg.name == "source") { obj = parser.GetParam(arg.param, "file"); if (obj == null) { Trace.WriteLine("Parameter file not found"); return false; } else source = (Parser.stStream)obj; obj = parser.GetParam(arg.param, "adress", "long"); if (obj != null) source_adress = (long)obj; else source_adress = 0; } else if (arg.name == "dest") { obj = parser.GetParam(arg.param, "file", null, true); if (obj == null) destination = parser.NewStream(arg.param["file"], true); else destination = (Parser.stStream)obj; } else { Trace.WriteLine(string.Format("Incorrect option - source, dest, pointer ; get {0}", arg.name)); return false; } } source.file.Position = source_adress; if (!Decomp(source, destination)) return false; if (!string.IsNullOrEmpty(destination.filename)) parser.WriteStream(destination); return true; } public static bool ValisCompression(List param) { Parser parser = Parser.INSTANCE; if (param.Count != 2) { Trace.WriteLine(string.Format("Number of parameters incorrect - 2 waited ; got {0}", param.Count)); return false; } Parser.stStream source = default(Parser.stStream); Parser.stStream destination = default(Parser.stStream); object obj; foreach (Parser.stParam arg in param) { if (arg.name == "source") { obj = parser.GetParam(arg.param, "file"); if (obj == null) { Trace.WriteLine("Parameter file not found"); return false; } else source = (Parser.stStream)obj; } else if (arg.name == "dest") { obj = parser.GetParam(arg.param, "file", null, true); if (obj == null) destination = parser.NewStream(arg.param["file"], true); else destination = (Parser.stStream)obj; } else { Trace.WriteLine(string.Format("Incorrect option - source, dest, pointer ; get {0}", arg.name)); return false; } } if (!Comp(source, destination)) return false; return true; } #region Private methods /// /// Initialise the buffer /// /// private static byte[] InitBuffer(int size = 0x1000) { byte[] buffer = new byte[size]; int pos = 0; byte value = 0x00; for (int i = 0; i < 0x100; i++) { for (int j = 0; j < 13; j++) { buffer[pos++] = value; } value++; } value = 0x00; for (int i = 0; i < 0x100; i++) { buffer[pos++] = value++; } value = 0xFF; for (int i = 0; i < 0x100; i++) { buffer[pos++] = value--; } for (int i = 0; i < 0x80; i++) { buffer[pos++] = 0x00; } for (int i = 0; i < 0x80; i++) { buffer[pos++] = 0x20; } return buffer; } /// /// Find the greater LZ compression from a position /// /// Array of bytes where look for RLE compression /// Current position in the array /// private static st_param FindLZInBuffer(byte[] a_bytes, int pos, int size_buffer, int len_max) { st_param param; int dict = 0; int pos_result = 0; int len_result = 0; if (pos > 0x1000) dict = pos - 0xFFF; while (dict < pos) { int len = 0; while (pos + len < a_bytes.Length && a_bytes[dict + len] == a_bytes[pos + len] && (len < len_max)) len++; if (len >= len_result) { pos_result = dict; len_result = len; } dict++; } param.length = len_result; param.offset = pos_result; return param; } /// /// Decompress a stream /// /// Stream to decompress /// Destination stream /// private static bool Decomp(Parser.stStream Source, Parser.stStream Destination) { int pos = 0xFEE; int curr_pos = 0; byte[] bytes = new byte[0x1000]; byte one_byte; UInt16 two_bytes; LogTrace trace = LogTrace.INSTANCE; try { using (BinaryReader br = new BinaryReader(Source.file, Encoding.Default, true)) { UInt32 size_in = br.ReadUInt32().ToBigEndian32(); UInt32 size_out = br.ReadUInt32().ToBigEndian32(); bytes = InitBuffer(); if (trace.TSwitch.TraceVerbose) { using (BinaryWriter bw = new BinaryWriter(File.Open("buffer.bin", FileMode.Create))) { bw.Write(bytes); } } Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format("Size IN {0}\nSize OUT {1}", size_in, size_out)); while (curr_pos < size_out) { byte header = br.ReadByte(); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format("header {0:X08} : {1:X02}", br.BaseStream.Position - 1, header)); for (int i = 0; i < 8; i++) { if ((header & 1) == 1) { one_byte = br.ReadByte(); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" {0} - Ecrit {1:X08} : {2:X02}", i, Destination.file.Position, one_byte)); Destination.file.WriteByte(one_byte); curr_pos++; bytes[pos] = one_byte; pos = (pos + 1) & 0xFFF; } else { two_bytes = br.ReadUInt16(); int nb = ((two_bytes >> 8) & 0x0F) + 3; int pos_lz = ((two_bytes & 0xF000) >> 4) | (two_bytes & 0xFF); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" {0} - LZ : {1:X04}", i, two_bytes)); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" nb : 0x{0:X02} ({1})", nb, nb)); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" Pos : 0x{0:X04} ({1})", pos_lz, pos_lz)); Trace.WriteIf(trace.TSwitch.TraceVerbose, string.Format(" Ecrit {0:X08} : ", Destination.file.Position)); for (int j = 0; j < nb; j++) { Destination.file.WriteByte(bytes[pos_lz]); curr_pos++; bytes[pos] = bytes[pos_lz]; Trace.WriteIf(trace.TSwitch.TraceVerbose, string.Format("{0:X02} ", bytes[pos_lz])); pos = (pos + 1) & 0xFFF; pos_lz = (pos_lz + 1) & 0xFFF; } Trace.WriteLineIf(trace.TSwitch.TraceVerbose, ""); } header >>= 1; if (curr_pos >= size_out) break; } Trace.WriteLineIf(trace.TSwitch.TraceVerbose, ""); } } return true; } catch (Exception ex) { Trace.WriteLine(string.Format("(EE) {0}", ex.Message)); return false; } } /// /// Compress a stream /// /// Stream to compress /// Destination stream /// private static bool Comp(Parser.stStream Source, Parser.stStream Destination) { st_param param_lz; int size_out = (int)Source.file.Length; int pos_temp = 0; int pos = 0xFEE; int curr_pos = pos; byte[] b_size_out = BitConverter.GetBytes(size_out.ToBigEndian32()); byte[] temp = new byte[24]; int buffer_size = 0x1000; LogTrace trace = LogTrace.INSTANCE; try { Source.file.Position = 0; Destination.file.Position = 0; Destination.file.Write(b_size_out, 0, 4); Destination.file.Write(b_size_out, 0, 4); byte[] bytes = InitBuffer(pos + size_out); Source.file.Read(bytes, pos, size_out); while (curr_pos < size_out + pos) { byte header = 0; for (int i = 0; i < 8; i++) { if (curr_pos >= size_out + pos) break; Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format("{0} - Pos : {1:X}", i, curr_pos - pos)); param_lz = FindLZInBuffer(bytes, curr_pos, buffer_size, 0x12); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" nb LZ : {0:000}", param_lz.length)); if (param_lz.length < 3) { Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" -> Byte : {0:X02}", bytes[curr_pos])); temp[pos_temp++] = bytes[curr_pos]; header |= (byte)(1 << i); curr_pos++; } else { Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" POS_LZ : {0:X04}", param_lz.offset)); Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format(" -> LZ : {0:X02}{1:X02}", (byte)(((param_lz.offset & 0xF00) >> 4) | ((param_lz.length - 3) & 0x0F)), (byte)(param_lz.offset & 0xFF))); temp[pos_temp++] = (byte)(param_lz.offset & 0xFF); temp[pos_temp++] = (byte)(((param_lz.offset & 0xF00) >> 4) | ((param_lz.length - 3) & 0x0F)); curr_pos += param_lz.length; } } Trace.WriteLineIf(trace.TSwitch.TraceVerbose, string.Format("Header : {0:X02}\n", header)); Destination.file.WriteByte(header); Destination.file.Write(temp, 0, pos_temp); pos_temp = 0; } byte[] b_size_in = BitConverter.GetBytes((int)((Destination.file.Length - 8).ToBigEndian32())); Destination.file.Position = 0; Destination.file.Write(b_size_in, 0, 4); return true; } catch (Exception ex) { Trace.WriteLine(string.Format("(EE) {0}", ex.Message)); return false; } } #endregion } }