using System; using System.IO; using System.Security.Cryptography; namespace ScreenConnect; public abstract class BufferStreamBase : UnseekableStream { private CursorBuffer buffer; public int BufferCompletedCount => buffer.CompletedCount; public int BufferRemainingCount => buffer.RemainingCount; protected BufferStreamBase() { buffer = CursorBuffer.Empty; } public void SetBuffer(byte[] buffer, int offset, int count) { this.buffer = CursorBuffer.From(buffer, offset, count); } public void SetBuffer(ArraySegment segment) { buffer = CursorBuffer.From(segment); } protected int Read(ref CursorBuffer destination) { return CursorBuffer.Copy(ref buffer, ref destination); } protected byte ReadOne() { return CursorBuffer.ReadOne(ref buffer); } protected int Write(ref CursorBuffer source) { return CursorBuffer.Copy(ref source, ref buffer); } protected void WriteOne(byte value) { CursorBuffer.WriteOne(ref buffer, value); } protected int WriteAndTransform(ref CursorBuffer source, ICryptoTransform transform) { return CursorBuffer.Transform(ref source, ref buffer, transform); } protected int ReadAndTransform(ref CursorBuffer destination, ICryptoTransform transform) { return CursorBuffer.Transform(ref buffer, ref destination, transform); } public ArraySegment GetBufferFullSegment() { return buffer.FullSegment; } public ArraySegment GetBufferCompletedSegment() { return buffer.GetCompletedSegment(); } protected unsafe void ReadThroughCoder(IMultiCallCoder coder, byte* outputData, int outputNeeded, bool isEndOfBlock) { while (outputNeeded > 0) { int inputTaken; int outputProduced; fixed (byte* backingArray = buffer.BackingArray) { if (coder != null) { CoderExtensions.AssertResult(coder.Process(backingArray + buffer.CurrentOffset, BufferRemainingCount, outputData, outputNeeded, isEndOfBlock ? CoderFlushType.Sync : CoderFlushType.None, out inputTaken, out outputProduced), CoderProcessResult.Success, CoderProcessResult.BufferError); } else { Extensions.CopyMemory(backingArray + buffer.CurrentOffset, outputData, inputTaken = (outputProduced = Math.Min(outputNeeded, BufferRemainingCount))); } } CursorBuffer.Advance(ref buffer, inputTaken); outputData += outputProduced; outputNeeded -= outputProduced; if (BufferRemainingCount == 0 && inputTaken == 0 && outputProduced == 0) { DemandBufferCount(1); } } } protected unsafe void WriteThroughCoder(IMultiCallCoder coder, byte* inputData, int inputCount, bool isEndOfBlock) { do { if (BufferRemainingCount == 0) { DemandBufferCount(1); } int inputTaken; int outputProduced; fixed (byte* backingArray = buffer.BackingArray) { if (coder != null) { CoderExtensions.AssertResult(coder.Process(inputData, inputCount, backingArray + buffer.CurrentOffset, BufferRemainingCount, isEndOfBlock ? CoderFlushType.Sync : CoderFlushType.None, out inputTaken, out outputProduced), CoderProcessResult.Success, CoderProcessResult.BufferError); } else { Extensions.CopyMemory(inputData, backingArray + buffer.CurrentOffset, inputTaken = (outputProduced = Math.Min(inputCount, BufferRemainingCount))); } } CursorBuffer.Advance(ref buffer, outputProduced); inputData += inputTaken; inputCount -= inputTaken; } while (!CoderExtensions.IsCoderFinishedProcessingInput(inputCount, BufferRemainingCount)); } protected unsafe void WriteThroughCoder(ISingleCallCoder coder, byte* inputData, int inputCount, uint* runningInputCount, uint* runningOutputCount) { CoderReadProc readProc = delegate(byte* coderInputData, int coderInputCount) { int num = Math.Min(inputCount, coderInputCount); Extensions.CopyMemory(inputData, coderInputData, num); if (runningInputCount != null) { *runningInputCount += (uint)num; } inputData += num; inputCount -= num; return num; }; CoderWriteProc coderWriteProc = delegate(byte* coderOutputData, int coderOutputCount) { while (coderOutputCount != 0) { DemandBufferCount(1); int num = Math.Min(coderOutputCount, BufferRemainingCount); fixed (byte* backingArray = buffer.BackingArray) { Extensions.CopyMemory(coderOutputData, backingArray + buffer.CurrentOffset, num); } if (runningOutputCount != null) { *runningOutputCount += (uint)num; } coderOutputData += num; coderOutputCount -= num; CursorBuffer.Advance(ref buffer, num); } }; if (coder != null) { coder.Process(readProc, coderWriteProc); } else { coderWriteProc(inputData, inputCount); } } protected abstract void OnNeedsBufferCycled(); public override void Flush() { if (BufferCompletedCount != 0) { OnNeedsBufferCycled(); } } protected bool RequestBufferCount(int count) { if (BufferRemainingCount < count) { OnNeedsBufferCycled(); if (BufferRemainingCount < count) { return false; } } return true; } protected void DemandBufferCount(int count) { if (!RequestBufferCount(count)) { throw new EndOfStreamException(); } } }