in src/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs [579:770]
private void GetAndMoveToFrontDecode()
{
byte[] yy = new byte[256];
int nextSym;
int limitLast = BZip2Constants.BaseBlockSize * blockSize100k;
origPtr = BsGetIntVS(24);
RecvDecodingTables();
int EOB = nInUse + 1;
int groupNo = -1;
int groupPos = 0;
/*--
Setting up the unzftab entries here is not strictly
necessary, but it does save having to do it later
in a separate pass, and so saves a block's worth of
cache misses.
--*/
for (int i = 0; i <= 255; i++)
{
unzftab[i] = 0;
}
for (int i = 0; i <= 255; i++)
{
yy[i] = (byte)i;
}
last = -1;
if (groupPos == 0)
{
groupNo++;
groupPos = BZip2Constants.GroupSize;
}
groupPos--;
int zt = selector[groupNo];
int zn = minLens[zt];
int zvec = BsR(zn);
int zj;
while (zvec > limit[zt][zn])
{
if (zn > 20)
{ // the longest code
throw new BZip2Exception("Bzip data error");
}
zn++;
while (bsLive < 1)
{
FillBuffer();
}
zj = (bsBuff >> (bsLive - 1)) & 1;
bsLive--;
zvec = (zvec << 1) | zj;
}
if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize)
{
throw new BZip2Exception("Bzip data error");
}
nextSym = perm[zt][zvec - baseArray[zt][zn]];
while (true)
{
if (nextSym == EOB)
{
break;
}
if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB)
{
int s = -1;
int n = 1;
do
{
if (nextSym == BZip2Constants.RunA)
{
s += (0 + 1) * n;
}
else if (nextSym == BZip2Constants.RunB)
{
s += (1 + 1) * n;
}
n <<= 1;
if (groupPos == 0)
{
groupNo++;
groupPos = BZip2Constants.GroupSize;
}
groupPos--;
zt = selector[groupNo];
zn = minLens[zt];
zvec = BsR(zn);
while (zvec > limit[zt][zn])
{
zn++;
while (bsLive < 1)
{
FillBuffer();
}
zj = (bsBuff >> (bsLive - 1)) & 1;
bsLive--;
zvec = (zvec << 1) | zj;
}
nextSym = perm[zt][zvec - baseArray[zt][zn]];
} while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB);
s++;
byte ch = seqToUnseq[yy[0]];
unzftab[ch] += s;
while (s > 0)
{
last++;
ll8[last] = ch;
s--;
}
if (last >= limitLast)
{
BlockOverrun();
}
continue;
}
else
{
last++;
if (last >= limitLast)
{
BlockOverrun();
}
byte tmp = yy[nextSym - 1];
unzftab[seqToUnseq[tmp]]++;
ll8[last] = seqToUnseq[tmp];
var j = nextSym - 1;
#if VECTORIZE_MEMORY_MOVE
// This is vectorized memory move. Going from the back, we're taking chunks of array
// and write them at the new location shifted by one. Since chunks are VectorSize long,
// at the end we have to move "tail" (or head actually) of the array using a plain loop.
// If System.Numerics.Vector API is not available, the plain loop is used to do the whole copying.
while(j >= VectorSize)
{
var arrayPart = new System.Numerics.Vector<byte>(yy, j - VectorSize);
arrayPart.CopyTo(yy, j - VectorSize + 1);
j -= VectorSize;
}
#endif // VECTORIZE_MEMORY_MOVE
while(j > 0)
{
yy[j] = yy[--j];
}
yy[0] = tmp;
if (groupPos == 0)
{
groupNo++;
groupPos = BZip2Constants.GroupSize;
}
groupPos--;
zt = selector[groupNo];
zn = minLens[zt];
zvec = BsR(zn);
while (zvec > limit[zt][zn])
{
zn++;
while (bsLive < 1)
{
FillBuffer();
}
zj = (bsBuff >> (bsLive - 1)) & 1;
bsLive--;
zvec = (zvec << 1) | zj;
}
nextSym = perm[zt][zvec - baseArray[zt][zn]];
continue;
}
}
}