Partially reconstructed decompression algorithm
parent
d29691e0ee
commit
09f7ef180d
|
@ -6,6 +6,8 @@ namespace Resources
|
||||||
{
|
{
|
||||||
public class Compression
|
public class Compression
|
||||||
{
|
{
|
||||||
|
private const int SectionSize = 4096;
|
||||||
|
private static readonly byte[] SomeData = new byte[16] {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
class Header
|
class Header
|
||||||
|
@ -41,7 +43,7 @@ namespace Resources
|
||||||
public Stream Decompress()
|
public Stream Decompress()
|
||||||
{
|
{
|
||||||
var output = new MemoryStream();
|
var output = new MemoryStream();
|
||||||
var buffer = new byte[5120];
|
var sourceBuffer = new byte[SectionSize];
|
||||||
|
|
||||||
var offset = (uint)0;
|
var offset = (uint)0;
|
||||||
|
|
||||||
|
@ -49,33 +51,32 @@ namespace Resources
|
||||||
{
|
{
|
||||||
var header = Header.Read(_reader);
|
var header = Header.Read(_reader);
|
||||||
|
|
||||||
if (header.DecompressedLength == 4096)
|
if (header.DecompressedLength == SectionSize)
|
||||||
{
|
{
|
||||||
Logger.Debug("Compression block header read at offset 0x{0:X}", offset);
|
Logger.Debug("Compression block header read at offset 0x{0:X}", offset);
|
||||||
Logger.Debug("Flags 0x{0:X}, Compressed {1}, Decompressed {2}, LengthSize {3}",
|
Logger.Debug("Flags 0x{0:X}, Compressed {1}, Decompressed {2}, LengthSize {3}",
|
||||||
header.Flags, header.CompressedLength, header.DecompressedLength, header.LengthSize);
|
header.Flags, header.CompressedLength, header.DecompressedLength, header.LengthSize);
|
||||||
|
|
||||||
_reader.Read(buffer, 0, (int)header.CompressedLength - 9);
|
_reader.Read(sourceBuffer, 0, (int)header.CompressedLength - Header.Size);
|
||||||
offset += header.CompressedLength;
|
offset += header.CompressedLength;
|
||||||
|
|
||||||
|
|
||||||
if (header.IsCompressed)
|
if (header.IsCompressed)
|
||||||
{
|
{
|
||||||
// Here should be decompression
|
var decompressed = DecompressBuffer(sourceBuffer);
|
||||||
|
output.Write(decompressed, 0, (int)header.DecompressedLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
output.Write(buffer, 0, (int)header.CompressedLength);
|
output.Write(sourceBuffer, 0, (int)header.CompressedLength - Header.Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var latestBlock = _streamSize - offset;
|
var latestBlock = _streamSize - offset;
|
||||||
Logger.Debug("Latest block read at offset 0x{0:X}, size: {1}", offset, latestBlock);
|
Logger.Debug("Latest block read at offset 0x{0:X}, size: {1}", offset, latestBlock);
|
||||||
|
|
||||||
_reader.Read(buffer, 0, (int)(latestBlock - Header.Size));
|
_reader.Read(sourceBuffer, 0, (int)(latestBlock - Header.Size));
|
||||||
|
|
||||||
output.Write(header.Buffer, 0, Header.Size);
|
output.Write(header.Buffer, 0, Header.Size);
|
||||||
output.Write(buffer, 0, (int)(latestBlock - Header.Size));
|
output.Write(sourceBuffer, 0, (int)(latestBlock - Header.Size));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,5 +85,94 @@ namespace Resources
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] DecompressBuffer(byte[] srcBuffer)
|
||||||
|
{
|
||||||
|
var dstBuffer = new byte[SectionSize];
|
||||||
|
var data = (uint)1;
|
||||||
|
var dstOffset = 0;
|
||||||
|
var srcOffset = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (data == 1)
|
||||||
|
{
|
||||||
|
data = BitConverter.ToUInt32(srcBuffer, srcOffset);
|
||||||
|
srcOffset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var link = BitConverter.ToUInt32(srcBuffer, srcOffset);
|
||||||
|
|
||||||
|
if (data << 31 == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
data = data >> 1;
|
||||||
|
|
||||||
|
uint dupOffset, dupLength;
|
||||||
|
|
||||||
|
if (link << 30 == 0)
|
||||||
|
{
|
||||||
|
dupOffset = (uint)((byte)link >> 2);
|
||||||
|
dupLength = 3;
|
||||||
|
srcOffset++;
|
||||||
|
}
|
||||||
|
else if ((link & 2) == 0)
|
||||||
|
{
|
||||||
|
dupOffset = (uint)((ushort)link >> 2);
|
||||||
|
dupLength = 3;
|
||||||
|
srcOffset += 2;
|
||||||
|
}
|
||||||
|
else if (link << 31 == 0)
|
||||||
|
{
|
||||||
|
dupOffset = (uint)((ushort)link >> 6);
|
||||||
|
dupLength = ((link >> 2) & 0xF) + 3;
|
||||||
|
srcOffset += 2;
|
||||||
|
}
|
||||||
|
else if ((link & 0x7F) == 3)
|
||||||
|
{
|
||||||
|
dupOffset = link >> 15;
|
||||||
|
dupLength = ((link >> 7) & 0xFF) + 3;
|
||||||
|
srcOffset += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dupOffset = (link >> 7) & 0x1FFFF;
|
||||||
|
dupLength = ((link >> 2) & 0x1F) + 2;
|
||||||
|
srcOffset += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Copy(dstBuffer, dstOffset - dupOffset, dstBuffer, dstOffset, dupLength);
|
||||||
|
dstOffset += (int)dupLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstOffset >= SectionSize - 11)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var length = SomeData[data & 0xf];
|
||||||
|
Array.Copy(srcBuffer, srcOffset, dstBuffer, dstOffset, 4);
|
||||||
|
data >>= length;
|
||||||
|
dstOffset += length;
|
||||||
|
srcOffset += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dstOffset <= SectionSize - 1)
|
||||||
|
{
|
||||||
|
if (data == 1)
|
||||||
|
{
|
||||||
|
data = 0x80000000;
|
||||||
|
srcOffset += 4;
|
||||||
|
}
|
||||||
|
data >>= 1;
|
||||||
|
var tmp = srcBuffer[srcOffset];
|
||||||
|
srcOffset++;
|
||||||
|
dstBuffer[dstOffset] = tmp;
|
||||||
|
dstOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return dstBuffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,10 @@ namespace Resources.Image
|
||||||
throw new ArgumentException("Image signature doesn't match.");
|
throw new ArgumentException("Image signature doesn't match.");
|
||||||
|
|
||||||
ReadHeader();
|
ReadHeader();
|
||||||
|
if (_paletteColors > 256)
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Too many palette colors.");
|
||||||
|
|
||||||
if (_paletteColors > 0)
|
if (_paletteColors > 0)
|
||||||
ReadPalette();
|
ReadPalette();
|
||||||
else if (_bitsPerPixel == 16 || _bitsPerPixel == 24 || _bitsPerPixel == 32)
|
else if (_bitsPerPixel == 16 || _bitsPerPixel == 24 || _bitsPerPixel == 32)
|
||||||
|
|
|
@ -43,7 +43,14 @@ namespace Resources
|
||||||
_stream.Seek(realOffset, SeekOrigin.Begin);
|
_stream.Seek(realOffset, SeekOrigin.Begin);
|
||||||
}
|
}
|
||||||
Logger.Debug("Reading image {0}...", i);
|
Logger.Debug("Reading image {0}...", i);
|
||||||
images.Add(new Image.Reader(_stream).Read());
|
try
|
||||||
|
{
|
||||||
|
images.Add(new Image.Reader(_stream).Read());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Logger.Warn("Error on reading image {0}", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,12 @@ namespace WatchFace
|
||||||
using (var stream = File.OpenRead(inputFileName))
|
using (var stream = File.OpenRead(inputFileName))
|
||||||
{
|
{
|
||||||
var decompressedStream = new Compression(stream).Decompress();
|
var decompressedStream = new Compression(stream).Decompress();
|
||||||
|
using (var wStream = File.OpenWrite(Path.Combine(outputDirectory, $"{inputFileName}.res"))) {
|
||||||
|
decompressedStream.CopyTo(wStream);
|
||||||
|
wStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
decompressedStream.Seek(0, SeekOrigin.Begin);
|
||||||
resDescriptor = FileReader.Read(decompressedStream);
|
resDescriptor = FileReader.Read(decompressedStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue