2018-11-28 17:18:09 -05:00
|
|
|
using System;
|
|
|
|
|
|
|
|
namespace Ryujinx.HLE.Loaders.Compression
|
|
|
|
{
|
|
|
|
static class BackwardsLz
|
|
|
|
{
|
|
|
|
private class BackwardsReader
|
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
private byte[] _data;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
private int _position;
|
|
|
|
|
|
|
|
public int Position => _position;
|
|
|
|
|
|
|
|
public BackwardsReader(byte[] data, int end)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
_data = data;
|
|
|
|
_position = end;
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
public void SeekCurrent(int offset)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
_position += offset;
|
|
|
|
}
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
public byte ReadByte()
|
|
|
|
{
|
|
|
|
return _data[--_position];
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public short ReadInt16()
|
|
|
|
{
|
|
|
|
return (short)((ReadByte() << 8) | (ReadByte() << 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
public int ReadInt32()
|
|
|
|
{
|
|
|
|
return ((ReadByte() << 24) |
|
|
|
|
(ReadByte() << 16) |
|
|
|
|
(ReadByte() << 8) |
|
|
|
|
(ReadByte() << 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
public static void DecompressInPlace(byte[] buffer, int headerEnd)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
BackwardsReader reader = new BackwardsReader(buffer, headerEnd);
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
int additionalDecLength = reader.ReadInt32();
|
|
|
|
int startOffset = reader.ReadInt32();
|
|
|
|
int compressedLength = reader.ReadInt32();
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
reader.SeekCurrent(12 - startOffset);
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
int decBase = headerEnd - compressedLength;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
int decPos = compressedLength + additionalDecLength;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
byte mask = 0;
|
|
|
|
byte header = 0;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
while (decPos > 0)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2018-12-06 06:16:24 -05:00
|
|
|
if ((mask >>= 1) == 0)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2018-12-06 06:16:24 -05:00
|
|
|
header = reader.ReadByte();
|
|
|
|
mask = 0x80;
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
if ((header & mask) == 0)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
buffer[decBase + --decPos] = reader.ReadByte();
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-06 06:16:24 -05:00
|
|
|
ushort pair = (ushort)reader.ReadInt16();
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
int length = (pair >> 12) + 3;
|
|
|
|
int position = (pair & 0xfff) + 3;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
if (length > decPos)
|
|
|
|
{
|
|
|
|
length = decPos;
|
|
|
|
}
|
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
decPos -= length;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
int dstPos = decBase + decPos;
|
|
|
|
|
2018-12-06 06:16:24 -05:00
|
|
|
if (length <= position)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
int srcPos = dstPos + position;
|
2018-11-28 17:18:09 -05:00
|
|
|
|
2019-01-18 17:26:39 -05:00
|
|
|
Buffer.BlockCopy(buffer, srcPos, buffer, dstPos, length);
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-06 06:16:24 -05:00
|
|
|
for (int offset = 0; offset < length; offset++)
|
2018-11-28 17:18:09 -05:00
|
|
|
{
|
2019-01-18 17:26:39 -05:00
|
|
|
buffer[dstPos + offset] = buffer[dstPos + position + offset];
|
2018-11-28 17:18:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|