in csharp/src/EntropyCommon.cs [198:269]
public static size_t ReadStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, void* src, size_t srcSize)
{
U32 weightTotal;
BYTE* ip = (BYTE*)src;
size_t iSize;
size_t oSize;
if (srcSize == 0) return ERROR(Error.srcSize_wrong);
iSize = ip[0];
/* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
if (iSize >= 128)
{ /* special header */
oSize = iSize - 127;
iSize = ((oSize + 1) / 2);
if (iSize + 1 > srcSize) return ERROR(Error.srcSize_wrong);
if (oSize >= hwSize) return ERROR(Error.corruption_detected);
ip += 1;
{
U32 n;
for (n = 0; n < oSize; n += 2)
{
huffWeight[n] = (BYTE)(ip[n / 2] >> 4);
huffWeight[n + 1] = (BYTE)(ip[n / 2] & 15);
}
}
}
else
{ /* header compressed with FSE (normal case) */
FSE_DTable* fseWorkspace = stackalloc FSE_DTable[Fse.FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
if (iSize + 1 > srcSize) return ERROR(Error.srcSize_wrong);
oSize = FseDecompress.FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
if (IsError(oSize)) return oSize;
}
/* collect weight stats */
memset(rankStats, 0, (Huf.HUF_TABLELOG_MAX + 1) * sizeof(U32));
weightTotal = 0;
{
U32 n; for (n = 0; n < oSize; n++)
{
if (huffWeight[n] >= Huf.HUF_TABLELOG_MAX) return ERROR(Error.corruption_detected);
rankStats[huffWeight[n]]++;
weightTotal += ((U32)1 << huffWeight[n]) >> 1;
}
}
if (weightTotal == 0) return ERROR(Error.corruption_detected);
/* get last non-null symbol weight (implied, total must be 2^n) */
{
U32 tableLog = BitStream.BIT_highbit32(weightTotal) + 1;
if (tableLog > Huf.HUF_TABLELOG_MAX) return ERROR(Error.corruption_detected);
*tableLogPtr = tableLog;
/* determine last weight */
{
U32 total = (U32)1 << (int)tableLog;
U32 rest = total - weightTotal;
U32 verif = (U32)1 << (int)BitStream.BIT_highbit32(rest);
U32 lastWeight = BitStream.BIT_highbit32(rest) + 1;
if (verif != rest) return ERROR(Error.corruption_detected); /* last value must be a clean power of 2 */
huffWeight[oSize] = (BYTE)lastWeight;
rankStats[lastWeight]++;
}
}
/* check tree construction validity */
if ((rankStats[1] < 2) || ((rankStats[1] & 1) != 0)) return ERROR(Error.corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
/* results */
*nbSymbolsPtr = (U32)(oSize + 1);
return iSize + 1;
}