in csharp/src/ZStdDecompress.cs [1620:1707]
static seq_t DecodeSequenceLong(seqState_t seqState, ZSTD_longOffset_e longOffsets)
{
seq_t seq;
U32 llBits = seqState.stateLL.table[seqState.stateLL.state].nbAdditionalBits;
U32 mlBits = seqState.stateML.table[seqState.stateML.state].nbAdditionalBits;
U32 ofBits = seqState.stateOffb.table[seqState.stateOffb.state].nbAdditionalBits;
U32 totalBits = llBits + mlBits + ofBits;
U32 llBase = seqState.stateLL.table[seqState.stateLL.state].baseValue;
U32 mlBase = seqState.stateML.table[seqState.stateML.state].baseValue;
U32 ofBase = seqState.stateOffb.table[seqState.stateOffb.state].baseValue;
/* sequence */
{
size_t offset;
if (ofBits == 0)
offset = 0;
else
{
//ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
//ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
Debug.Assert(ofBits <= MaxOff);
if (MEM_32bits() && longOffsets != 0)
{
U32 extraBits = ofBits - Math.Min(ofBits, STREAM_ACCUMULATOR_MIN_32 - 1);
offset = ofBase + (ReadBitsFast(seqState.DStream, ofBits - extraBits) << (int)extraBits);
if (MEM_32bits() || extraBits != 0) ReloadDStream(seqState.DStream);
if (extraBits != 0) offset += ReadBitsFast(seqState.DStream, extraBits);
}
else
{
offset = ofBase + ReadBitsFast(seqState.DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
if (MEM_32bits()) ReloadDStream(seqState.DStream);
}
}
if (ofBits <= 1)
{
offset += (llBase == 0 ? (size_t)1 : 0);
if (offset != 0)
{
size_t temp = (offset == 3) ? seqState.prevOffset[0] - 1 : seqState.prevOffset[offset];
temp += temp == 0 ? (size_t)1 : 0; /* 0 is not valid; input is corrupted; force offset to 1 */
if (offset != 1) seqState.prevOffset[2] = seqState.prevOffset[1];
seqState.prevOffset[1] = seqState.prevOffset[0];
seqState.prevOffset[0] = offset = temp;
}
else
{
offset = seqState.prevOffset[0];
}
}
else
{
seqState.prevOffset[2] = seqState.prevOffset[1];
seqState.prevOffset[1] = seqState.prevOffset[0];
seqState.prevOffset[0] = offset;
}
seq.offset = offset;
}
seq.matchLength = mlBase + ((mlBits > 0) ? ReadBitsFast(seqState.DStream, mlBits) : 0); /* <= 16 bits */
if (MEM_32bits() && (mlBits + llBits >= STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32))
ReloadDStream(seqState.DStream);
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64 - (LLFSELog + MLFSELog + OffFSELog)))
ReloadDStream(seqState.DStream);
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
//ZSTD_STATIC_ASSERT(16 + LLFSELog + MLFSELog + OffFSELog < STREAM_ACCUMULATOR_MIN_64);
seq.litLength = llBase + ((llBits > 0) ? ReadBitsFast(seqState.DStream, llBits) : 0); /* <= 16 bits */
if (MEM_32bits())
ReloadDStream(seqState.DStream);
{
size_t pos = seqState.pos + seq.litLength;
BYTE* matchBase = (seq.offset > pos) ? seqState.dictEnd : seqState.prefixStart;
seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
* No consequence though : no memory access will occur, overly large offset will be detected in ExecSequenceLong() */
seqState.pos = pos + seq.matchLength;
}
/* ANS state update */
UpdateFseState(ref seqState.stateLL, seqState.DStream); /* <= 9 bits */
UpdateFseState(ref seqState.stateML, seqState.DStream); /* <= 9 bits */
if (MEM_32bits()) ReloadDStream(seqState.DStream); /* <= 18 bits */
UpdateFseState(ref seqState.stateOffb, seqState.DStream); /* <= 8 bits */
return seq;
}