mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 15:44:00 +08:00
(EriFormat): implemented huffman decompression.
This commit is contained in:
parent
68493ede0f
commit
5d2d620153
@ -208,10 +208,15 @@ namespace GameRes.Formats.Entis
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
E R I S A - L i b r a r y
|
||||
-----------------------------------------------------------------------------
|
||||
Copyright (C) 2002-2004 Leshade Entis, Entis-soft. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
internal class EriReader
|
||||
{
|
||||
EriMetaData m_info;
|
||||
Color[] m_palette;
|
||||
byte[] m_output;
|
||||
ERISADecodeContext m_context;
|
||||
int m_dst;
|
||||
@ -241,6 +246,8 @@ namespace GameRes.Formats.Entis
|
||||
sbyte[] m_ptrArrangeBuf;
|
||||
int[] m_pArrangeTable = new int[4];
|
||||
|
||||
HuffmanTree m_pHuffmanTree;
|
||||
|
||||
PtrProcedure[] m_pfnColorOperation;
|
||||
|
||||
public byte[] Data { get { return m_output; } }
|
||||
@ -283,11 +290,16 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
private void InitializeLossless ()
|
||||
{
|
||||
if (EriCode.RunlengthHuffman == m_info.Architecture
|
||||
|| EriCode.Nemesis == m_info.Architecture)
|
||||
switch (m_info.Architecture)
|
||||
{
|
||||
case EriCode.Nemesis:
|
||||
throw new NotSupportedException ("Not supported ERI compression");
|
||||
if (EriCode.RunlengthGamma != m_info.Architecture)
|
||||
case EriCode.RunlengthHuffman:
|
||||
case EriCode.RunlengthGamma:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidFormatException();
|
||||
}
|
||||
if (0 == m_info.BlockingDegree)
|
||||
throw new InvalidFormatException();
|
||||
|
||||
@ -325,18 +337,21 @@ namespace GameRes.Formats.Entis
|
||||
InitializeArrangeTable();
|
||||
if (0x00020200 == m_info.Version)
|
||||
{
|
||||
/*
|
||||
if (EriCode.RunlengthHuffman == m_info.Architecture)
|
||||
{
|
||||
m_pHuffmanTree = new ERINA_HUFFMAN_TREE ;
|
||||
m_pHuffmanTree = new HuffmanTree();
|
||||
}
|
||||
/*
|
||||
else if (EriCode.Nemesis == m_info.Architecture)
|
||||
{
|
||||
m_pProbERISA = new ERISA_PROB_MODEL ;
|
||||
}
|
||||
*/
|
||||
}
|
||||
m_context = new RLEDecodeContext (0x10000);
|
||||
if (EriCode.RunlengthHuffman == m_info.Architecture)
|
||||
m_context = new HuffmanDecodeContext (0x10000);
|
||||
else
|
||||
m_context = new RLEDecodeContext (0x10000);
|
||||
}
|
||||
|
||||
int[] m_ptrTable;
|
||||
@ -403,13 +418,6 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
uint stride = ((m_info.Width * (uint)m_info.BPP / 8u) + 0x03u) & ~0x03u;
|
||||
uint image_bytes = stride * m_info.Height;
|
||||
int dwPaletteLength = 0;
|
||||
if (m_info.BPP <= 8)
|
||||
{
|
||||
dwPaletteLength = 1 << m_info.BPP;
|
||||
}
|
||||
if (0 != dwPaletteLength)
|
||||
m_palette = new Color[dwPaletteLength];
|
||||
m_output = new byte[image_bytes];
|
||||
m_dwBytesPerLine = (int)stride;
|
||||
m_dwClippedPixel = 0;
|
||||
@ -467,12 +475,7 @@ namespace GameRes.Formats.Entis
|
||||
if (null == pfnRestoreFunc)
|
||||
throw new InvalidFormatException();
|
||||
/*
|
||||
if (EriCode.RunlengthHuffman == m_info.Architecture)
|
||||
{
|
||||
Debug.Assert (m_pHuffmanTree != null);
|
||||
m_pHuffmanTree.Initialize();
|
||||
}
|
||||
else if (EriCode.Nemesis == m_info.Architecture)
|
||||
if (EriCode.Nemesis == m_info.Architecture)
|
||||
{
|
||||
Debug.Assert (m_pProbERISA != null);
|
||||
m_pProbERISA.Initialize();
|
||||
@ -490,13 +493,11 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
m_ptrOperations[i] = (byte)(context.GetNBits(4) | 0xC0);
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
Debug.Assert (EriCode.RunlengthHuffman == m_info.Architecture);
|
||||
m_ptrOperations[i] = (byte) context.GetHuffmanCode (m_pHuffmanTree);
|
||||
m_ptrOperations[i] = (byte)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (context.GetABit() != 0)
|
||||
@ -509,11 +510,11 @@ namespace GameRes.Formats.Entis
|
||||
context.InitGammaContext();
|
||||
}
|
||||
}
|
||||
/*
|
||||
else if (EriCode.RunlengthHuffman == m_info.Architecture)
|
||||
{
|
||||
context.PrepareToDecodeERINACode();
|
||||
(context as HuffmanDecodeContext).PrepareToDecodeERINACode();
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
Debug.Assert (EriCode.Nemesis == m_info.Architecture);
|
||||
@ -544,11 +545,7 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
for (int nPosX = 0; nPosX < (int)m_nWidthBlocks; ++nPosX)
|
||||
{
|
||||
m_nDstWidth = m_nBlockSize;
|
||||
if ((int)m_nDstWidth > nLeftWidth)
|
||||
{
|
||||
m_nDstWidth = (uint)nLeftWidth;
|
||||
}
|
||||
m_nDstWidth = Math.Min (m_nBlockSize, (uint)nLeftWidth);
|
||||
|
||||
uint dwOperationCode;
|
||||
if (m_nChannelCount >= 3)
|
||||
@ -557,15 +554,15 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
dwOperationCode = m_ptrOperations[ptrNextOperation++];
|
||||
}
|
||||
else if (m_info.Architecture == EriCode.RunlengthHuffman)
|
||||
{
|
||||
dwOperationCode = (uint)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree);
|
||||
}
|
||||
/*
|
||||
else if (m_info.Architecture == EriCode.Nemesis)
|
||||
{
|
||||
dwOperationCode = context.DecodeERISACode (m_pProbERISA);
|
||||
}
|
||||
else if (m_info.Architecture == EriCode.RunlengthHuffman)
|
||||
{
|
||||
dwOperationCode = context.GetHuffmanCode (m_pHuffmanTree);
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
@ -693,7 +690,10 @@ namespace GameRes.Formats.Entis
|
||||
Format = PixelFormats.Bgr555;
|
||||
return RestoreRGB16;
|
||||
case 8:
|
||||
Format = PixelFormats.Gray8;
|
||||
if (null == Palette)
|
||||
Format = PixelFormats.Gray8;
|
||||
else
|
||||
Format = PixelFormats.Indexed8;
|
||||
return RestoreGray8;
|
||||
}
|
||||
return null;
|
||||
@ -915,10 +915,286 @@ namespace GameRes.Formats.Entis
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Erina
|
||||
{
|
||||
public const int CodeFlag = int.MinValue;
|
||||
public const int HuffmanEscape = 0x7FFFFFFF;
|
||||
public const int HuffmanNull = 0x8000;
|
||||
public const int HuffmanMax = 0x4000;
|
||||
public const int HuffmanRoot = 0x200;
|
||||
};
|
||||
|
||||
internal class HuffmanNode
|
||||
{
|
||||
public ushort Weight;
|
||||
public ushort Parent;
|
||||
public int ChildCode;
|
||||
|
||||
public void CopyFrom (HuffmanNode other)
|
||||
{
|
||||
this.Weight = other.Weight;
|
||||
this.Parent = other.Parent;
|
||||
this.ChildCode = other.ChildCode;
|
||||
}
|
||||
}
|
||||
|
||||
internal class HuffmanTree
|
||||
{
|
||||
public HuffmanNode[] m_hnTree = new HuffmanNode[0x201];
|
||||
public int[] m_iSymLookup = new int[0x100];
|
||||
public int m_iEscape;
|
||||
public int m_iTreePointer;
|
||||
|
||||
public HuffmanTree ()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void Initialize ()
|
||||
{
|
||||
for (int i = 0; i < 0x201; i++)
|
||||
{
|
||||
m_hnTree[i] = new HuffmanNode();
|
||||
}
|
||||
for (int i = 0; i < 0x100; i++)
|
||||
{
|
||||
m_iSymLookup[i] = (int)Erina.HuffmanNull;
|
||||
}
|
||||
m_iEscape = (int)Erina.HuffmanNull;
|
||||
m_iTreePointer = (int)Erina.HuffmanRoot;
|
||||
m_hnTree[Erina.HuffmanRoot].Weight = 0;
|
||||
m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull;
|
||||
m_hnTree[Erina.HuffmanRoot].ChildCode = Erina.HuffmanNull;
|
||||
}
|
||||
|
||||
public void IncreaseOccuredCount (int iEntry)
|
||||
{
|
||||
m_hnTree[iEntry].Weight++;
|
||||
Normalize (iEntry);
|
||||
if (m_hnTree[Erina.HuffmanRoot].Weight >= Erina.HuffmanMax)
|
||||
{
|
||||
HalfAndRebuild();
|
||||
}
|
||||
}
|
||||
|
||||
private void RecountOccuredCount (int iParent)
|
||||
{
|
||||
int iChild = m_hnTree[iParent].ChildCode;
|
||||
m_hnTree[iParent].Weight = (ushort)(m_hnTree[iChild].Weight + m_hnTree[iChild + 1].Weight);
|
||||
}
|
||||
|
||||
private void Normalize (int iEntry)
|
||||
{
|
||||
while (iEntry < Erina.HuffmanRoot)
|
||||
{
|
||||
int iSwap = iEntry + 1;
|
||||
ushort weight = m_hnTree[iEntry].Weight;
|
||||
while (iSwap < Erina.HuffmanRoot)
|
||||
{
|
||||
if (m_hnTree[iSwap].Weight >= weight)
|
||||
break;
|
||||
++iSwap;
|
||||
}
|
||||
if (iEntry == --iSwap)
|
||||
{
|
||||
iEntry = m_hnTree[iEntry].Parent;
|
||||
RecountOccuredCount (iEntry);
|
||||
continue;
|
||||
}
|
||||
int iChild, nCode;
|
||||
if (0 == (m_hnTree[iEntry].ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
iChild = m_hnTree[iEntry].ChildCode;
|
||||
m_hnTree[iChild].Parent = (ushort)iSwap;
|
||||
m_hnTree[iChild + 1].Parent = (ushort)iSwap;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCode = m_hnTree[iEntry].ChildCode & ~Erina.CodeFlag;
|
||||
if (nCode != Erina.HuffmanEscape)
|
||||
m_iSymLookup[nCode & 0xFF] = iSwap;
|
||||
else
|
||||
m_iEscape = iSwap;
|
||||
}
|
||||
if (0 == (m_hnTree[iSwap].ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
iChild = m_hnTree[iSwap].ChildCode;
|
||||
m_hnTree[iChild].Parent = (ushort)iEntry;
|
||||
m_hnTree[iChild+1].Parent = (ushort)iEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCode = m_hnTree[iSwap].ChildCode & ~Erina.CodeFlag;
|
||||
if (nCode != Erina.HuffmanEscape)
|
||||
m_iSymLookup[nCode & 0xFF] = iEntry;
|
||||
else
|
||||
m_iEscape = iEntry;
|
||||
}
|
||||
var node = m_hnTree[iSwap]; // XXX
|
||||
ushort iEntryParent = m_hnTree[iEntry].Parent;
|
||||
ushort iSwapParent = m_hnTree[iSwap].Parent;
|
||||
|
||||
m_hnTree[iSwap] = m_hnTree[iEntry];
|
||||
m_hnTree[iEntry] = node;
|
||||
m_hnTree[iSwap].Parent = iSwapParent;
|
||||
m_hnTree[iEntry].Parent = iEntryParent;
|
||||
|
||||
RecountOccuredCount (iSwapParent);
|
||||
iEntry = iSwapParent;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddNewEntry (int nNewCode)
|
||||
{
|
||||
if (m_iTreePointer > 0)
|
||||
{
|
||||
m_iTreePointer -= 2;
|
||||
int i = m_iTreePointer;
|
||||
var phnNew = m_hnTree[i];
|
||||
phnNew.Weight = 1;
|
||||
phnNew.ChildCode = Erina.CodeFlag | nNewCode;
|
||||
m_iSymLookup[nNewCode & 0xFF] = i ;
|
||||
|
||||
var phnRoot = m_hnTree[Erina.HuffmanRoot];
|
||||
if (phnRoot.ChildCode != Erina.HuffmanNull)
|
||||
{
|
||||
var phnParent = m_hnTree[i + 2];
|
||||
var phnChild = m_hnTree[i + 1];
|
||||
phnChild.CopyFrom (phnParent); // m_hnTree[i + 1] = m_hnTree[i + 2];
|
||||
|
||||
if (0 != (phnChild.ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
int nCode = phnChild.ChildCode & ~Erina.CodeFlag;
|
||||
if (nCode != Erina.HuffmanEscape)
|
||||
m_iSymLookup[nCode & 0xFF] = i + 1;
|
||||
else
|
||||
m_iEscape = i + 1;
|
||||
}
|
||||
phnParent.Weight = (ushort)(phnNew.Weight + phnChild.Weight);
|
||||
phnParent.Parent = phnChild.Parent;
|
||||
phnParent.ChildCode = i;
|
||||
|
||||
phnNew.Parent = phnChild.Parent = (ushort)(i + 2);
|
||||
Normalize (i + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
phnNew.Parent = Erina.HuffmanRoot;
|
||||
m_iEscape = i + 1;
|
||||
var phnEscape = m_hnTree[m_iEscape];
|
||||
phnEscape.Weight = 1;
|
||||
phnEscape.Parent = Erina.HuffmanRoot;
|
||||
phnEscape.ChildCode = Erina.CodeFlag | Erina.HuffmanEscape;
|
||||
|
||||
phnRoot.Weight = 2;
|
||||
phnRoot.ChildCode = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = m_iTreePointer;
|
||||
var phnEntry = m_hnTree[i];
|
||||
if (phnEntry.ChildCode == (Erina.CodeFlag | Erina.HuffmanEscape))
|
||||
{
|
||||
phnEntry = m_hnTree[i + 1];
|
||||
}
|
||||
phnEntry.ChildCode = Erina.CodeFlag | nNewCode;
|
||||
}
|
||||
}
|
||||
|
||||
private void HalfAndRebuild ()
|
||||
{
|
||||
int i;
|
||||
int iNextEntry = Erina.HuffmanRoot;
|
||||
for (i = Erina.HuffmanRoot - 1; i >= m_iTreePointer; i--)
|
||||
{
|
||||
if (0 != (m_hnTree[i].ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
m_hnTree[i].Weight = (ushort)((m_hnTree[i].Weight + 1) >> 1);
|
||||
m_hnTree[iNextEntry--].CopyFrom (m_hnTree[i]);
|
||||
}
|
||||
}
|
||||
++iNextEntry;
|
||||
|
||||
int iChild, nCode;
|
||||
i = m_iTreePointer;
|
||||
for (;;)
|
||||
{
|
||||
m_hnTree[i].CopyFrom (m_hnTree[iNextEntry]);
|
||||
m_hnTree[i + 1].CopyFrom (m_hnTree[iNextEntry + 1]);
|
||||
iNextEntry += 2;
|
||||
var phnChild1 = m_hnTree[i];
|
||||
var phnChild2 = m_hnTree[i + 1];
|
||||
|
||||
if (0 == (phnChild1.ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
iChild = phnChild1.ChildCode;
|
||||
m_hnTree[iChild].Parent = (ushort)i;
|
||||
m_hnTree[iChild + 1].Parent = (ushort)i;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCode = phnChild1.ChildCode & ~Erina.CodeFlag;
|
||||
if (Erina.HuffmanEscape == nCode)
|
||||
m_iEscape = i;
|
||||
else
|
||||
m_iSymLookup[nCode & 0xFF] = i;
|
||||
}
|
||||
if (0 == (phnChild2.ChildCode & Erina.CodeFlag))
|
||||
{
|
||||
iChild = phnChild2.ChildCode;
|
||||
m_hnTree[iChild].Parent = (ushort)(i + 1);
|
||||
m_hnTree[iChild + 1].Parent = (ushort)(i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nCode = phnChild2.ChildCode & ~Erina.CodeFlag;
|
||||
if (Erina.HuffmanEscape == nCode)
|
||||
m_iEscape = i + 1;
|
||||
else
|
||||
m_iSymLookup[nCode & 0xFF] = i + 1;
|
||||
}
|
||||
ushort weight = (ushort)(phnChild1.Weight + phnChild2.Weight);
|
||||
|
||||
if (iNextEntry <= Erina.HuffmanRoot)
|
||||
{
|
||||
int j = iNextEntry;
|
||||
for (;;)
|
||||
{
|
||||
if (weight <= m_hnTree[j].Weight)
|
||||
{
|
||||
m_hnTree[j - 1].Weight = weight;
|
||||
m_hnTree[j - 1].ChildCode = i;
|
||||
break;
|
||||
}
|
||||
m_hnTree[j - 1].CopyFrom (m_hnTree[j]);
|
||||
if (++j > Erina.HuffmanRoot)
|
||||
{
|
||||
m_hnTree[Erina.HuffmanRoot].Weight = weight;
|
||||
m_hnTree[Erina.HuffmanRoot].ChildCode = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
--iNextEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hnTree[Erina.HuffmanRoot].Weight = weight;
|
||||
m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull;
|
||||
m_hnTree[Erina.HuffmanRoot].ChildCode = i;
|
||||
phnChild1.Parent = Erina.HuffmanRoot;
|
||||
phnChild2.Parent = Erina.HuffmanRoot;
|
||||
break;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class RLEDecodeContext : ERISADecodeContext
|
||||
{
|
||||
int m_flgZero;
|
||||
uint m_nLength;
|
||||
protected int m_flgZero;
|
||||
protected uint m_nLength;
|
||||
|
||||
public RLEDecodeContext (uint nBufferingSize) : base (nBufferingSize)
|
||||
{
|
||||
@ -996,15 +1272,14 @@ namespace GameRes.Formats.Entis
|
||||
}
|
||||
}
|
||||
|
||||
int GetGammaCode()
|
||||
protected int GetGammaCode()
|
||||
{
|
||||
if (!PrefetchBuffer())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint dwIntBuf;
|
||||
m_nIntBufCount--;
|
||||
dwIntBuf = m_dwIntBuffer;
|
||||
uint dwIntBuf = m_dwIntBuffer;
|
||||
m_dwIntBuffer <<= 1;
|
||||
if (0 == (dwIntBuf & 0x80000000))
|
||||
{
|
||||
@ -1015,7 +1290,7 @@ namespace GameRes.Formats.Entis
|
||||
return 0;
|
||||
}
|
||||
int nCode = 0;
|
||||
if ((0 != (~m_dwIntBuffer & 0x55000000)) && (m_nIntBufCount >= 8) )
|
||||
if ((0 != (~m_dwIntBuffer & 0x55000000)) && (m_nIntBufCount >= 8))
|
||||
{
|
||||
uint i = (m_dwIntBuffer >> 24) << 1;
|
||||
nCode = nGammaCodeLookup[i];
|
||||
@ -1103,4 +1378,181 @@ namespace GameRes.Formats.Entis
|
||||
15, 6, 15, 6, 15, 6, 15, 6, 30, 8, 0xff, 0xff, 31, 8, 0xff, 0xff
|
||||
};
|
||||
}
|
||||
|
||||
internal class HuffmanDecodeContext : RLEDecodeContext
|
||||
{
|
||||
int m_dwERINAFlags;
|
||||
HuffmanTree m_pLastHuffmanTree;
|
||||
HuffmanTree[] m_ppHuffmanTree;
|
||||
|
||||
// ERINAEncodingFlag
|
||||
public const int efERINAOrder0 = 0x0000;
|
||||
public const int efERINAOrder1 = 0x0001;
|
||||
|
||||
public HuffmanDecodeContext (uint nBufferingSize) : base (nBufferingSize)
|
||||
{
|
||||
}
|
||||
|
||||
public void PrepareToDecodeERINACode (int flags = efERINAOrder1)
|
||||
{
|
||||
int i;
|
||||
if (null == m_ppHuffmanTree)
|
||||
{
|
||||
m_ppHuffmanTree = new HuffmanTree[0x101];
|
||||
}
|
||||
m_dwERINAFlags = flags;
|
||||
m_nLength = 0;
|
||||
if (efERINAOrder0 == flags)
|
||||
{
|
||||
m_ppHuffmanTree[0] = new HuffmanTree();
|
||||
m_ppHuffmanTree[0x100] = new HuffmanTree();
|
||||
for (i = 1; i < 0x100; i++)
|
||||
{
|
||||
m_ppHuffmanTree[i] = m_ppHuffmanTree[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 0x101; i++)
|
||||
{
|
||||
m_ppHuffmanTree[i] = new HuffmanTree();
|
||||
}
|
||||
}
|
||||
m_pLastHuffmanTree = m_ppHuffmanTree[0];
|
||||
}
|
||||
|
||||
public override uint DecodeBytes (Array ptrDst, uint nCount)
|
||||
{
|
||||
return DecodeErinaCodeBytes (ptrDst as sbyte[], nCount);
|
||||
}
|
||||
|
||||
public uint DecodeErinaCodeBytes (sbyte[] ptrDst, uint nCount)
|
||||
{
|
||||
var tree = m_pLastHuffmanTree;
|
||||
int symbol, length;
|
||||
uint i = 0;
|
||||
if (m_nLength > 0)
|
||||
{
|
||||
length = (int)Math.Min (m_nLength, nCount);
|
||||
m_nLength -= (uint)length;
|
||||
do
|
||||
{
|
||||
ptrDst[i++] = 0;
|
||||
}
|
||||
while (0 != --length);
|
||||
}
|
||||
while (i < nCount)
|
||||
{
|
||||
symbol = GetHuffmanCode (tree);
|
||||
if (Erina.HuffmanEscape == symbol)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ptrDst[i++] = (sbyte)symbol;
|
||||
|
||||
if (0 == symbol)
|
||||
{
|
||||
length = GetLengthHuffman (m_ppHuffmanTree[0x100]);
|
||||
if (Erina.HuffmanEscape == length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (0 != --length)
|
||||
{
|
||||
m_nLength = (uint)length;
|
||||
if (i + length > nCount)
|
||||
{
|
||||
length = (int)(nCount - i);
|
||||
}
|
||||
m_nLength -= (uint)length;
|
||||
while (length > 0)
|
||||
{
|
||||
ptrDst[i++] = 0;
|
||||
--length;
|
||||
}
|
||||
}
|
||||
}
|
||||
tree = m_ppHuffmanTree[symbol & 0xFF];
|
||||
}
|
||||
m_pLastHuffmanTree = tree;
|
||||
return i;
|
||||
}
|
||||
|
||||
private int GetLengthHuffman (HuffmanTree tree)
|
||||
{
|
||||
int nCode;
|
||||
if (tree.m_iEscape != Erina.HuffmanNull)
|
||||
{
|
||||
int iEntry = Erina.HuffmanRoot;
|
||||
int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode;
|
||||
do
|
||||
{
|
||||
if (!PrefetchBuffer())
|
||||
{
|
||||
return Erina.HuffmanEscape;
|
||||
}
|
||||
iEntry = iChild + (int)(m_dwIntBuffer >> 31);
|
||||
iChild = tree.m_hnTree[iEntry].ChildCode;
|
||||
m_dwIntBuffer <<= 1;
|
||||
--m_nIntBufCount;
|
||||
}
|
||||
while (0 == (iChild & Erina.CodeFlag));
|
||||
|
||||
if ((m_dwERINAFlags != efERINAOrder0) ||
|
||||
(tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1))
|
||||
{
|
||||
tree.IncreaseOccuredCount (iEntry);
|
||||
}
|
||||
nCode = iChild & ~Erina.CodeFlag;
|
||||
if (nCode != Erina.HuffmanEscape)
|
||||
{
|
||||
return nCode ;
|
||||
}
|
||||
}
|
||||
nCode = GetGammaCode();
|
||||
if (-1 == nCode)
|
||||
{
|
||||
return Erina.HuffmanEscape;
|
||||
}
|
||||
tree.AddNewEntry (nCode);
|
||||
return nCode;
|
||||
}
|
||||
|
||||
public int GetHuffmanCode (HuffmanTree tree)
|
||||
{
|
||||
int nCode;
|
||||
if (tree.m_iEscape != Erina.HuffmanNull)
|
||||
{
|
||||
int iEntry = Erina.HuffmanRoot;
|
||||
int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode;
|
||||
do
|
||||
{
|
||||
if (!PrefetchBuffer())
|
||||
{
|
||||
return Erina.HuffmanEscape;
|
||||
}
|
||||
iEntry = iChild + (int)(m_dwIntBuffer >> 31);
|
||||
iChild = tree.m_hnTree[iEntry].ChildCode;
|
||||
m_dwIntBuffer <<= 1;
|
||||
--m_nIntBufCount;
|
||||
}
|
||||
while (0 == (iChild & Erina.CodeFlag));
|
||||
|
||||
if ((m_dwERINAFlags != efERINAOrder0) ||
|
||||
(tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1))
|
||||
{
|
||||
tree.IncreaseOccuredCount (iEntry);
|
||||
}
|
||||
nCode = iChild & ~Erina.CodeFlag;
|
||||
if (nCode != Erina.HuffmanEscape)
|
||||
{
|
||||
return nCode;
|
||||
}
|
||||
}
|
||||
nCode = (int)GetNBits (8);
|
||||
tree.AddNewEntry (nCode);
|
||||
|
||||
return nCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.5.53")]
|
||||
[assembly: AssemblyFileVersion ("1.0.5.53")]
|
||||
[assembly: AssemblyVersion ("1.0.5.54")]
|
||||
[assembly: AssemblyFileVersion ("1.0.5.54")]
|
||||
|
Loading…
Reference in New Issue
Block a user