Worms2server/src/Syroot.Worms/Core/Team17Compression.cs
2017-04-18 16:08:29 +02:00

80 lines
2.9 KiB
C#

using System.IO;
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
/// graphic file formats.
/// S. http://worms2d.info/Team17_compression.
/// </summary>
internal static class Team17Compression
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Decompresses the data available in the given <paramref name="stream"/> into the provided
/// <paramref name="buffer"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the data from.</param>
/// <param name="buffer">The byte array buffer to write the decompressed data to.</param>
internal static void Decompress(Stream stream, ref byte[] buffer)
{
// TODO: This fails for compressed data in CD:\\Data\Mission\Training0-9.img.
int output = 0; // Offset of next write.
int cmd;
while ((cmd = stream.ReadByte()) != -1)
{
// Read a byte.
if ((cmd & 0x80) == 0)
{
// Command: 1 byte (color)
buffer[output++] = (byte)cmd;
}
else
{
// Arg1 = bits 2-5
int arg1 = (cmd >> 3) & 0xF;
int arg2 = stream.ReadByte();
if (arg2 == -1)
{
return;
}
// Arg2 = bits 6-16
arg2 = ((cmd << 8) | arg2) & 0x7FF;
if (arg1 == 0)
{
// Command: 0x80 0x00
if (arg2 == 0)
{
return;
}
int arg3 = stream.ReadByte();
if (arg3 == -1)
{
return;
}
// Command: 3 bytes
output = CopyData(output, arg2, arg3 + 18, ref buffer);
}
else
{
// Command: 2 bytes
output = CopyData(output, arg2 + 1, arg1 + 2, ref buffer);
}
}
}
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static int CopyData(int offset, int compressedOffset, int count, ref byte[] buffer)
{
for (; count > 0; count--)
{
buffer[offset] = buffer[offset++ - compressedOffset];
}
return offset;
}
}
}