public void CircularBufferStream_TestReadBytes() { CircularBufferStream cbs = new CircularBufferStream(3); byte[] data = new byte[] { 0, 1, 2 }; cbs.Write(data, 0, data.Length); byte[] outData = new byte[5] { 88, 88, 88, 88, 88 }; Assert.AreEqual(3, cbs.Read(outData, 1, 3)); CollectionAssert.AreEqual(new byte[] { 88, 0, 1, 2, 88 }, outData); Assert.AreEqual(0, cbs.BytesAvailable); }
/// <summary> /// Provides a filter for compressing a <see cref="Stream"/> with LZMA. /// </summary> /// <param name="stream">The underlying <see cref="Stream"/> to write the compressed data to.</param> /// <param name="bufferSize">The maximum number of uncompressed bytes to buffer. 32k (the step size of <see cref="SevenZip"/>) is a sensible minimum.</param> /// <remarks> /// This method internally uses multi-threading and a <see cref="CircularBufferStream"/>. /// The <paramref name="stream"/> may be closed with a delay. /// </remarks> private static Stream GetCompressionStream(Stream stream, int bufferSize = 128 * 1024) { var bufferStream = new CircularBufferStream(bufferSize); var encoder = new Encoder(); var consumerThread = new Thread(() => { try { // Write LZMA header encoder.SetCoderProperties( new[] { CoderPropId.DictionarySize, CoderPropId.PosStateBits, CoderPropId.LitContextBits, CoderPropId.LitPosBits, CoderPropId.Algorithm, CoderPropId.NumFastBytes, CoderPropId.MatchFinder, CoderPropId.EndMarker }, new object[] { 1 << 23, 2, 3, 0, 2, 128, "bt4", true }); encoder.WriteCoderProperties(stream); // Write "uncompressed length" header var uncompressedLengthData = BitConverter.GetBytes(TarLzmaExtractor.UnknownSize); if (!BitConverter.IsLittleEndian) { Array.Reverse(uncompressedLengthData); } stream.Write(uncompressedLengthData); encoder.Code( inStream: bufferStream, outStream: stream, inSize: TarLzmaExtractor.UnknownSize, outSize: TarLzmaExtractor.UnknownSize, progress: null); } catch (ObjectDisposedException) { // If the buffer stream is closed too early the user probably just canceled the compression process } finally { stream.Dispose(); } }) { IsBackground = true }; consumerThread.Start(); return(new DisposeWarpperStream(bufferStream, disposeHandler: () => { bufferStream.DoneWriting(); consumerThread.Join(); })); }
public void CircularBufferStream_TestReadPointer() { CircularBufferStream cbs = new CircularBufferStream(3); byte[] data = new byte[] { 0, 1, 2 }; cbs.Write(data, 0, data.Length); byte[] outData = new byte[5] { 88, 88, 88, 88, 88 }; IntPtr outDataPtr = Marshal.AllocHGlobal(outData.Length); Marshal.Copy(outData, 0, outDataPtr, outData.Length); Assert.AreEqual(3, cbs.Read(outDataPtr, outData.Length, 3)); Marshal.Copy(outDataPtr, outData, 0, outData.Length); Marshal.FreeHGlobal(outDataPtr); CollectionAssert.AreEqual(new byte[] { 0, 1, 2, 88, 88 }, outData); Assert.AreEqual(0, cbs.BytesAvailable); }
public void CircularBufferStream_TestRead() { CircularBufferStream cbs = new CircularBufferStream(3); byte[] data = new byte[] { 0, 1, 2 }; cbs.Write(data, 0, data.Length); Assert.AreEqual(3, cbs.BytesAvailable); CollectionAssert.AreEqual(data, cbs.Read()); Assert.AreEqual(0, cbs.BytesAvailable); // Write more data than the buffer capacity data = new byte[] { 0, 1, 2, 3 }; cbs.Write(data, 0, data.Length); // first element should be overwritten - buffer should contain { 1, 2, 3 } Assert.AreEqual(3, cbs.BytesAvailable); CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, cbs.Read()); Assert.AreEqual(0, cbs.BytesAvailable); }
/// <summary> /// Provides a filter for decompressing an LZMA encoded <see cref="Stream"/>. /// </summary> /// <param name="stream">The underlying <see cref="Stream"/> providing the compressed data.</param> /// <param name="bufferSize">The maximum number of uncompressed bytes to buffer. 32k (the step size of <see cref="SevenZip"/>) is a sensible minimum.</param> /// <exception cref="IOException">The <paramref name="stream"/> doesn't start with a valid 5-bit LZMA header.</exception> /// <remarks> /// This method internally uses multi-threading and a <see cref="CircularBufferStream"/>. /// The <paramref name="stream"/> may be closed with a delay. /// </remarks> internal static Stream GetDecompressionStream(Stream stream, int bufferSize = 128 * 1024) { var bufferStream = new CircularBufferStream(bufferSize); var decoder = new Decoder(); // Read LZMA header if (stream.CanSeek) { stream.Position = 0; } try { decoder.SetDecoderProperties(stream.Read(5)); } #region Error handling catch (IOException ex) { // Wrap exception to add context throw new IOException(Resources.ArchiveInvalid, ex); } catch (ApplicationException ex) { // Wrap exception since only certain exception types are allowed throw new IOException(Resources.ArchiveInvalid, ex); } #endregion // Read "uncompressed length" header var uncompressedLengthData = stream.Read(8); if (!BitConverter.IsLittleEndian) { Array.Reverse(uncompressedLengthData); } long uncompressedLength = BitConverter.ToInt64(uncompressedLengthData, startIndex: 0); bufferStream.SetLength((uncompressedLength == UnknownSize) ? (long)(stream.Length * 1.5) : uncompressedLength); var producerThread = new Thread(() => { try { decoder.Code( inStream: stream, outStream: bufferStream, inSize: UnknownSize, outSize: uncompressedLength, progress: null); } catch (ThreadAbortException) {} catch (ObjectDisposedException) { // If the buffer stream is closed too early the user probably just canceled the extraction process } catch (ApplicationException ex) { bufferStream.RelayErrorToReader(new IOException(ex.Message, ex)); } finally { bufferStream.DoneWriting(); } }) { IsBackground = true }; producerThread.Start(); return(new DisposeWarpperStream(bufferStream, disposeHandler: () => { producerThread.Abort(); producerThread.Join(); stream.Dispose(); })); }
protected override void OnHandler(ParameterHandlerInfo info) { Core.Log.Warning("Starting MEMORY STREAMS TEST"); Core.Log.WriteEmptyLine(); Core.Log.InfoBasic("Press Enter to Start RecycleMemoryStream Test."); Console.ReadLine(); var xbuffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; using (Watch.Create("RecycleMemoryStream")) { for (var m = 0; m < 50000; m++) { using (var rms = new RecycleMemoryStream()) { for (var x = 0; x < 1; x++) { for (int i = 0; i < 10000; i++) { rms.Write(xbuffer, 0, xbuffer.Length); } } rms.Position = 0; for (var x = 0; x < 10; x++) { for (int i = 0; i < 2000; i++) { var bt = rms.ReadByte(); } } } } } Core.Log.WriteEmptyLine(); Core.Log.InfoBasic("Press Enter to Start MemoryStream Test."); Console.ReadLine(); using (Watch.Create("MemoryStream")) { for (var m = 0; m < 50000; m++) { using (var rms = new MemoryStream()) { for (var x = 0; x < 1; x++) { for (var i = 0; i < 10000; i++) { rms.Write(xbuffer, 0, xbuffer.Length); } } rms.Position = 0; for (var x = 0; x < 10; x++) { for (var i = 0; i < 2000; i++) { var bt = rms.ReadByte(); } } } } } Core.Log.WriteEmptyLine(); Core.Log.InfoBasic("Press Enter to Start CircularBufferStream Test. Press Enter Again to finish the test."); Console.ReadLine(); using (var cbs = new CircularBufferStream(50)) { var cts = new CancellationTokenSource(); Task.Run(async() => { var i = 0; while (!cts.Token.IsCancellationRequested) { i++; cbs.WriteBytes(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }); if (i % 50 == 0) { Core.Log.InfoMedium("Write {0}", i); } await Task.Delay(1, cts.Token).ConfigureAwait(false); } }); Task.Run(async() => { var i = 0; var buffer = new byte[15]; while (!cts.Token.IsCancellationRequested) { i++; cbs.Read(buffer, 0, 7); if (i % 50 == 0) { Core.Log.InfoMedium("Read {0}", i); } await Task.Delay(1, cts.Token).ConfigureAwait(false); } }); Console.ReadLine(); cts.Cancel(); } Core.Log.WriteEmptyLine(); Core.Log.InfoBasic("Press Enter to Start SharedMemoryStream Test. Press Enter Again to finish the test."); Console.ReadLine(); using (var sharedms = new SharedMemoryStream("test", 2000)) { var cts = new CancellationTokenSource(); Task.Run(async() => { var i = 0; while (!cts.Token.IsCancellationRequested) { i++; sharedms.WriteBytes(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }); if (i % 50 == 0) { Core.Log.InfoMedium("Write {0}", i); } await Task.Delay(1, cts.Token).ConfigureAwait(false); } }); Task.Run(async() => { var i = 0; var buffer = new byte[15]; while (!cts.Token.IsCancellationRequested) { i++; sharedms.Read(buffer, 0, 7); if (i % 50 == 0) { Core.Log.InfoMedium("Read {0}", i); } await Task.Delay(1, cts.Token).ConfigureAwait(false); } }); Console.ReadLine(); } }
/// <summary> /// Provides a filter for decompressing an LZMA encoded <see cref="Stream"/>. /// </summary> /// <param name="stream">The underlying <see cref="Stream"/> providing the compressed data.</param> /// <param name="bufferSize">The maximum number of uncompressed bytes to buffer. 32k (the step size of <see cref="SevenZip"/>) is a sensible minimum.</param> /// <exception cref="IOException">The <paramref name="stream"/> doesn't start with a valid 5-bit LZMA header.</exception> /// <remarks> /// This method internally uses multi-threading and a <see cref="CircularBufferStream"/>. /// The <paramref name="stream"/> may be closed with a delay. /// </remarks> private static Stream GetDecompressionStream(Stream stream, int bufferSize = 128 * 1024) { var bufferStream = new CircularBufferStream(bufferSize); var decoder = new Decoder(); // Read LZMA header if (stream.CanSeek) { stream.Position = 0; } var properties = new byte[5]; if (stream.Read(properties, 0, 5) != 5) { // Stream too short throw new IOException(Resources.ArchiveInvalid); } try { decoder.SetDecoderProperties(properties); } #region Error handling catch (ApplicationException ex) { // Wrap exception since only certain exception types are allowed throw new IOException(Resources.ArchiveInvalid, ex); } #endregion // Detmerine uncompressed length long uncompressedLength = 0; if (BitConverter.IsLittleEndian) { for (int i = 0; i < 8; i++) { int v = stream.ReadByte(); if (v < 0) { throw new IOException(Resources.ArchiveInvalid); } uncompressedLength |= ((long)(byte)v) << (8 * i); } } // If the uncompressed length is unknown, use original size * 1.5 as an estimate unchecked { bufferStream.SetLength(uncompressedLength == -1 ? stream.Length : (long)(uncompressedLength * 1.5)); } // Initialize the producer thread that will deliver uncompressed data var thread = new Thread(() => { try { decoder.Code(stream, bufferStream, stream.Length, uncompressedLength, null); } #region Error handling catch (ThreadAbortException) {} catch (ObjectDisposedException) { // If the buffer stream is closed too early the user probably just canceled the extraction process } catch (ApplicationException ex) { // Wrap exception since only certain exception types are allowed bufferStream.RelayErrorToReader(new IOException(ex.Message, ex)); } #endregion finally { bufferStream.DoneWriting(); } }) { IsBackground = true }; thread.Start(); return(new DisposeWarpperStream(bufferStream, () => { // Stop producer thread when the buffer stream is closed thread.Abort(); thread.Join(); stream.Dispose(); })); }