public async Task Extract() { TotalWords = (await mRead(64)).GetValueOrDefault(); FileLength?.Invoke(TotalWords); mMaxHistory = Convert.ToUInt32((await mRead(32)).GetValueOrDefault()); mPresentLength = Convert.ToInt32((await mRead(8)).GetValueOrDefault()); int historyLengthInBits = Log2_WiegleyJ(mMaxHistory - 1) + 1; while (mWordsWritten < TotalWords) { var type = await mRead(1); if (type == null) { throw new EndOfStreamException(); } if (type.Value == 1) { var word = await mRead(8); if (word == null) { throw new EndOfStreamException(); } await mWrite(word.Value, 8); mHistory.AddLast(Convert.ToByte(word.Value)); if (mHistory.Count > mMaxHistory) { mHistory.RemoveFirst(); } mWordsWritten++; WordsWritten?.Invoke(1); } else if (type.Value == 0) { var offset = await mRead(historyLengthInBits); var length = await mRead(mPresentLength); if (offset == null || length == null) { throw new EndOfStreamException(); } if (offset >= mHistory.Count) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (offset < length - 1) { throw new ArgumentOutOfRangeException(nameof(length)); } var pointer = mHistory.Last; for (int i = 0; i < offset.Value; i++) { pointer = pointer.Previous; } for (int i = 0; i < length.Value; i++) { mHistory.AddLast(pointer.Value); await mWrite(pointer.Value, 8); pointer = pointer.Next; if (mHistory.Count > mMaxHistory) { mHistory.RemoveFirst(); } } mWordsWritten += length.Value; WordsWritten?.Invoke(length.Value); } else { throw new ArgumentOutOfRangeException(nameof(type)); } } }