有關LZF算法的相關解析文檔比較少,但是Apple對LZF的開源,可以讓我們對該算法進行一個簡單的解析。LZFSE 基於 Lempel-Ziv ,並使用了有限狀態熵編碼。LZF采用類似lz77和lzss的混合編碼。使用3種“起始標記”來代表每段輸出的數據串。
接下來看一下開源的LZF算法的實現源碼。
1.定義的全局字段:
private readonly long[] _hashTable = new long[Hsize];
private const uint Hlog = 14;
private const uint Hsize = (1 << 14);
private const uint MaxLit = (1 << 5);
private const uint MaxOff = (1 << 13);
private const uint MaxRef = ((1 << 8) + (1 << 3));
2.使用LibLZF算法壓縮數據:
/// <summary>
/// 使用LibLZF算法壓縮數據
/// </summary>
/// <param name="input">需要壓縮的數據</param>
/// <param name="inputLength">要壓縮的數據的長度</param>
/// <param name="output">引用將包含壓縮數據的緩沖區</param>
/// <param name="outputLength">壓縮緩沖區的長度(應大於輸入緩沖區)</param>
/// <returns>輸出緩沖區中壓縮歸檔的大小</returns>
public int Compress(byte[] input, int inputLength, byte[] output, int outputLength)
{
Array.Clear(_hashTable, 0, (int)Hsize);
uint iidx = 0;
uint oidx = 0;
var hval = (uint)(((input[iidx]) << 8) | input[iidx + 1]);
var lit = 0;
for (; ; )
{
if (iidx < inputLength - 2)
{
hval = (hval << 8) | input[iidx + 2];
long hslot = ((hval ^ (hval << 5)) >> (int)(((3 * 8 - Hlog)) - hval * 5) & (Hsize - 1));
var reference = _hashTable[hslot];
_hashTable[hslot] = iidx;
long off;
if ((off = iidx - reference - 1) < MaxOff
&& iidx + 4 < inputLength
&& reference > 0
&& input[reference + 0] == input[iidx + 0]
&& input[reference + 1] == input[iidx + 1]
&& input[reference + 2] == input[iidx + 2]
)
{
uint len = 2;
var maxlen = (uint)inputLength - iidx - len;
maxlen = maxlen > MaxRef ? MaxRef : maxlen;
if (oidx + lit + 1 + 3 >= outputLength)
return 0;
do
len++;
while (len < maxlen && input[reference + len] == input[iidx + len]);
if (lit != 0)
{
output[oidx++] = (byte)(lit - 1);
lit = -lit;
do
output[oidx++] = input[iidx + lit];
while ((++lit) != 0);
}
len -= 2;
iidx++;
if (len < 7)
{
output[oidx++] = (byte)((off >> 8) + (len << 5));
}
else
{
output[oidx++] = (byte)((off >> 8) + (7 << 5));
output[oidx++] = (byte)(len - 7);
}
output[oidx++] = (byte)off;
iidx += len - 1;
hval = (uint)(((input[iidx]) << 8) | input[iidx + 1]);
hval = (hval << 8) | input[iidx + 2];
_hashTable[((hval ^ (hval << 5)) >> (int)(((3 * 8 - Hlog)) - hval * 5) & (Hsize - 1))] = iidx;
iidx++;
hval = (hval << 8) | input[iidx + 2];
_hashTable[((hval ^ (hval << 5)) >> (int)(((3 * 8 - Hlog)) - hval * 5) & (Hsize - 1))] = iidx;
iidx++;
continue;
}
}
else if (iidx == inputLength)
break;
lit++;
iidx++;
if (lit != MaxLit) continue;
if (oidx + 1 + MaxLit >= outputLength)
return 0;
output[oidx++] = (byte)(MaxLit - 1);
lit = -lit;
do
output[oidx++] = input[iidx + lit];
while ((++lit) != 0);
}
if (lit == 0) return (int)oidx;
if (oidx + lit + 1 >= outputLength)
return 0;
output[oidx++] = (byte)(lit - 1);
lit = -lit;
do
output[oidx++] = input[iidx + lit];
while ((++lit) != 0);
return (int)oidx;
}
3.
/// <summary>
/// 使用LibLZF算法解壓縮數據
/// </summary>
/// <param name="input">參考數據進行解壓縮</param>
/// <param name="inputLength">要解壓縮的數據的長度</param>
/// <param name="output">引用包含解壓縮數據的緩沖區</param>
/// <param name="outputLength">輸出緩沖區中壓縮歸檔的大小</param>
/// <returns>返回解壓縮大小</returns>
public int Decompress(byte[] input, int inputLength, byte[] output, int outputLength)
{
uint iidx = 0;
uint oidx = 0;
do
{
uint ctrl = input[iidx++];
if (ctrl < (1 << 5))
{
ctrl++;
if (oidx + ctrl > outputLength)
{
return 0;
}
do
output[oidx++] = input[iidx++];
while ((--ctrl) != 0);
}
else
{
var len = ctrl >> 5;
var reference = (int)(oidx - ((ctrl & 0x1f) << 8) - 1);
if (len == 7)
len += input[iidx++];
reference -= input[iidx++];
if (oidx + len + 2 > outputLength)
{
return 0;
}
if (reference < 0)
{
return 0;
}
output[oidx++] = output[reference++];
output[oidx++] = output[reference++];
do
output[oidx++] = output[reference++];
while ((--len) != 0);
}
}
while (iidx < inputLength);
return (int)oidx;
}
以上是LZF算法的代碼。