Initial commit
This commit is contained in:
commit
0f86b0434b
38 changed files with 2370 additions and 0 deletions
114
LibDgf/Aqualead/AlLzDecoder.cs
Normal file
114
LibDgf/Aqualead/AlLzDecoder.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LibDgf.Aqualead
|
||||
{
|
||||
public class AlLzDecoder
|
||||
{
|
||||
uint bitBuffer;
|
||||
int numBitsRemaining;
|
||||
BinaryReader br;
|
||||
|
||||
public byte[] Decode(Stream inStream)
|
||||
{
|
||||
br = new BinaryReader(inStream);
|
||||
numBitsRemaining = 0;
|
||||
|
||||
if (new string(br.ReadChars(4)) != "ALLZ")
|
||||
throw new InvalidDataException("Not an Aqualead LZ compressed file.");
|
||||
byte version = br.ReadByte();
|
||||
if (version > 1)
|
||||
throw new InvalidDataException("Version too new.");
|
||||
|
||||
byte minLookbackLengthBits = br.ReadByte();
|
||||
byte minLookbackPosBits = br.ReadByte();
|
||||
byte minLiteralLengthBits = br.ReadByte();
|
||||
uint decompressedLength = br.ReadUInt32();
|
||||
|
||||
byte[] output = new byte[decompressedLength];
|
||||
int outPos = 0;
|
||||
|
||||
if (version == 0) ReadBits(1); // Consume literal bit if v0
|
||||
bool hasLiteral = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (hasLiteral)
|
||||
{
|
||||
if (outPos >= decompressedLength) break;
|
||||
int literalLength = (int)ReadEncodedNum(minLiteralLengthBits) + 1;
|
||||
if (inStream.Read(output, outPos, literalLength) != literalLength)
|
||||
throw new IOException("Could not read all bytes requested.");
|
||||
outPos += literalLength;
|
||||
//Console.WriteLine("Did literal");
|
||||
}
|
||||
|
||||
if (outPos >= decompressedLength) break;
|
||||
int lookbackPos = (int)ReadEncodedNum(minLookbackPosBits) + 1;
|
||||
int lookbackLength = (int)ReadEncodedNum(minLookbackLengthBits) + 3;
|
||||
|
||||
for (int i = 0; i < lookbackLength; ++i)
|
||||
{
|
||||
output[outPos] = output[outPos - lookbackPos];
|
||||
++outPos;
|
||||
}
|
||||
//Console.WriteLine("Did lookback");
|
||||
|
||||
if (outPos >= decompressedLength) break;
|
||||
hasLiteral = ReadBits(1) == 0;
|
||||
//Console.WriteLine("Has literal: " + hasLiteral);
|
||||
}
|
||||
|
||||
br = null;
|
||||
return output;
|
||||
}
|
||||
|
||||
uint ReadEncodedNum(int minNumBits)
|
||||
{
|
||||
int numExtBits = CountBits();
|
||||
uint num = ReadBits(minNumBits);
|
||||
if (numExtBits > 0)
|
||||
{
|
||||
// Length encoding
|
||||
// e e e e 0 | xxxx | yy
|
||||
// Number of es indicate exponent and number of bits for mantissa
|
||||
// Subsequently, ((2 ^ count(e)) - 1 + xxxx) | yy
|
||||
num |= (uint)(ReadBits(numExtBits) + (1 << numExtBits) - 1) << minNumBits;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void EnsureBits(int numBits)
|
||||
{
|
||||
while (numBitsRemaining < numBits)
|
||||
{
|
||||
if (numBitsRemaining + 8 > 32) throw new ArgumentOutOfRangeException(nameof(numBits));
|
||||
bitBuffer |= (uint)br.ReadByte() << numBitsRemaining;
|
||||
numBitsRemaining += 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint ReadBits(int numBits)
|
||||
{
|
||||
EnsureBits(numBits);
|
||||
uint output = (uint)(bitBuffer & ((1 << numBits) - 1));
|
||||
bitBuffer >>= numBits;
|
||||
numBitsRemaining -= numBits;
|
||||
return output;
|
||||
}
|
||||
|
||||
int CountBits()
|
||||
{
|
||||
int i = 0;
|
||||
while (ReadBits(1) != 0) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
void WriteBits()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue