static seq_t DecodeSequenceLong()

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;
		}