// 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.Zip { using System; using System.IO; /// /// Used to trick a DeflateStream into reading from or writing to /// a series of (chunked) streams instead of a single steream. /// internal class ConcatStream : Stream { private Stream source; private long position; private long length; private Action nextStreamHandler; public ConcatStream(Action nextStreamHandler) { if (nextStreamHandler == null) { throw new ArgumentNullException("nextStreamHandler"); } this.nextStreamHandler = nextStreamHandler; this.length = Int64.MaxValue; } public Stream Source { get { return this.source; } set { this.source = value; } } public override bool CanRead { get { return true; } } public override bool CanWrite { get { return true; } } public override bool CanSeek { get { return false; } } public override long Length { get { return this.length; } } public override long Position { get { return this.position; } set { throw new NotSupportedException(); } } public override int Read(byte[] buffer, int offset, int count) { if (this.source == null) { this.nextStreamHandler(this); } count = (int) Math.Min(count, this.length - this.position); int bytesRemaining = count; while (bytesRemaining > 0) { if (this.source == null) { throw new InvalidOperationException(); } int partialCount = (int) Math.Min(bytesRemaining, this.source.Length - this.source.Position); if (partialCount == 0) { this.nextStreamHandler(this); continue; } partialCount = this.source.Read( buffer, offset + count - bytesRemaining, partialCount); bytesRemaining -= partialCount; this.position += partialCount; } return count; } public override void Write(byte[] buffer, int offset, int count) { if (this.source == null) { this.nextStreamHandler(this); } int bytesRemaining = count; while (bytesRemaining > 0) { if (this.source == null) { throw new InvalidOperationException(); } int partialCount = (int) Math.Min(bytesRemaining, Math.Max(0, this.length - this.source.Position)); if (partialCount == 0) { this.nextStreamHandler(this); continue; } this.source.Write( buffer, offset + count - bytesRemaining, partialCount); bytesRemaining -= partialCount; this.position += partialCount; } } public override void Flush() { if (this.source != null) { this.source.Flush(); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { this.length = value; } public override void Close() { if (this.source != null) { this.source.Close(); } } } }