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<Parser.stParam> 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<Parser.stParam> 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
|
|
|
|
/// <summary>
|
|
/// Initialise the buffer
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find the greater LZ compression from a position
|
|
/// </summary>
|
|
/// <param name="a_bytes">Array of bytes where look for RLE compression</param>
|
|
/// <param name="pos">Current position in the array</param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decompress a stream
|
|
/// </summary>
|
|
/// <param name="Source">Stream to decompress</param>
|
|
/// <param name="Destination">Destination stream</param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compress a stream
|
|
/// </summary>
|
|
/// <param name="Source">Stream to compress</param>
|
|
/// <param name="Destination">Destination stream</param>
|
|
/// <returns></returns>
|
|
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
|
|
}
|
|
}
|