From 3f583916719eeef598d10a5d4e14ef14f008243b Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 11 May 2021 07:36:37 -0700 Subject: Merge Dtf --- .../WixToolset.Dtf.Compression/DuplicateStream.cs | 212 +++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs (limited to 'src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs') diff --git a/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs b/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs new file mode 100644 index 00000000..50e62e73 --- /dev/null +++ b/src/dtf/WixToolset.Dtf.Compression/DuplicateStream.cs @@ -0,0 +1,212 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.Compression +{ + using System; + using System.IO; + + /// + /// Duplicates a source stream by maintaining a separate position. + /// + /// + /// WARNING: duplicate streams are not thread-safe with respect to each other or the original stream. + /// If multiple threads use duplicate copies of the same stream, they must synchronize for any operations. + /// + public class DuplicateStream : Stream + { + private Stream source; + private long position; + + /// + /// Creates a new duplicate of a stream. + /// + /// source of the duplicate + public DuplicateStream(Stream source) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + + this.source = DuplicateStream.OriginalStream(source); + } + + /// + /// Gets the original stream that was used to create the duplicate. + /// + public Stream Source + { + get + { + return this.source; + } + } + + /// + /// Gets a value indicating whether the source stream supports reading. + /// + /// true if the stream supports reading; otherwise, false. + public override bool CanRead + { + get + { + return this.source.CanRead; + } + } + + /// + /// Gets a value indicating whether the source stream supports writing. + /// + /// true if the stream supports writing; otherwise, false. + public override bool CanWrite + { + get + { + return this.source.CanWrite; + } + } + + /// + /// Gets a value indicating whether the source stream supports seeking. + /// + /// true if the stream supports seeking; otherwise, false. + public override bool CanSeek + { + get + { + return this.source.CanSeek; + } + } + + /// + /// Gets the length of the source stream. + /// + public override long Length + { + get + { + return this.source.Length; + } + } + + /// + /// Gets or sets the position of the current stream, + /// ignoring the position of the source stream. + /// + public override long Position + { + get + { + return this.position; + } + + set + { + this.position = value; + } + } + + /// + /// Retrieves the original stream from a possible duplicate stream. + /// + /// Possible duplicate stream. + /// If the stream is a DuplicateStream, returns + /// the duplicate's source; otherwise returns the same stream. + public static Stream OriginalStream(Stream stream) + { + DuplicateStream dupStream = stream as DuplicateStream; + return dupStream != null ? dupStream.Source : stream; + } + + /// + /// Flushes the source stream. + /// + public override void Flush() + { + this.source.Flush(); + } + + /// + /// Sets the length of the source stream. + /// + /// The desired length of the stream in bytes. + public override void SetLength(long value) + { + this.source.SetLength(value); + } + + /// + /// Closes the underlying stream, effectively closing ALL duplicates. + /// + public override void Close() + { + this.source.Close(); + } + + /// + /// Reads from the source stream while maintaining a separate position + /// and not impacting the source stream's position. + /// + /// An array of bytes. When this method returns, the buffer + /// contains the specified byte array with the values between offset and + /// (offset + count - 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in buffer at which to begin + /// storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The total number of bytes read into the buffer. This can be less + /// than the number of bytes requested if that many bytes are not currently available, + /// or zero (0) if the end of the stream has been reached. + public override int Read(byte[] buffer, int offset, int count) + { + long saveSourcePosition = this.source.Position; + this.source.Position = this.position; + int read = this.source.Read(buffer, offset, count); + this.position = this.source.Position; + this.source.Position = saveSourcePosition; + return read; + } + + /// + /// Writes to the source stream while maintaining a separate position + /// and not impacting the source stream's position. + /// + /// An array of bytes. This method copies count + /// bytes from buffer to the current stream. + /// The zero-based byte offset in buffer at which + /// to begin copying bytes to the current stream. + /// The number of bytes to be written to the + /// current stream. + public override void Write(byte[] buffer, int offset, int count) + { + long saveSourcePosition = this.source.Position; + this.source.Position = this.position; + this.source.Write(buffer, offset, count); + this.position = this.source.Position; + this.source.Position = saveSourcePosition; + } + + /// + /// Changes the position of this stream without impacting the + /// source stream's position. + /// + /// A byte offset relative to the origin parameter. + /// A value of type SeekOrigin indicating the reference + /// point used to obtain the new position. + /// The new position within the current stream. + public override long Seek(long offset, SeekOrigin origin) + { + long originPosition = 0; + if (origin == SeekOrigin.Current) + { + originPosition = this.position; + } + else if (origin == SeekOrigin.End) + { + originPosition = this.Length; + } + + this.position = originPosition + offset; + return this.position; + } + } +} -- cgit v1.2.3-55-g6feb