public void WriteEntry_FromUnseekableStream_AdvanceDataStream_WriteFromThatPosition() { using MemoryStream source = GetTarMemoryStream(CompressionMethod.Uncompressed, TestTarFormat.ustar, "file"); using WrappedStream unseekable = new WrappedStream(source, canRead: true, canWrite: true, canSeek: false); using MemoryStream destination = new MemoryStream(); using (TarReader reader = new TarReader(unseekable)) { TarEntry entry = reader.GetNextEntry(); Assert.NotNull(entry); Assert.NotNull(entry.DataStream); entry.DataStream.ReadByte(); // Advance one byte, now the expected string would be "ello file" using (TarWriter writer = new TarWriter(destination, TarEntryFormat.Ustar, leaveOpen: true)) { writer.WriteEntry(entry); } } destination.Seek(0, SeekOrigin.Begin); using (TarReader reader = new TarReader(destination)) { TarEntry entry = reader.GetNextEntry(); Assert.NotNull(entry); Assert.NotNull(entry.DataStream); using (StreamReader streamReader = new StreamReader(entry.DataStream, leaveOpen: true)) { string contents = streamReader.ReadLine(); Assert.Equal("ello file", contents); } } }
public static void CreateNormal_VerifyDataDescriptor() { using var memoryStream = new MemoryStream(); // We need an non-seekable stream so the data descriptor bit is turned on when saving var wrappedStream = new WrappedStream(memoryStream, true, true, false, null); // Creation will go through the path that sets the data descriptor bit when the stream is unseekable using (var archive = new ZipArchive(wrappedStream, ZipArchiveMode.Create)) { CreateEntry(archive, "A", "xxx"); CreateEntry(archive, "B", "yyy"); } AssertDataDescriptor(memoryStream, true); // Update should flip the data descriptor bit to zero on save using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Update)) { ZipArchiveEntry entry = archive.Entries[0]; using Stream entryStream = entry.Open(); StreamReader reader = new StreamReader(entryStream); string content = reader.ReadToEnd(); // Append a string to this entry entryStream.Seek(0, SeekOrigin.End); StreamWriter writer = new StreamWriter(entryStream); writer.Write("zzz"); writer.Flush(); } AssertDataDescriptor(memoryStream, false); }
/// <summary> /// Wraps a generic stream into a block stream using the specified transformer and blocksize. /// </summary> /// <remarks>The wrapped stream must be writable and seekable</remarks> /// <param name="wrappedStream">Stream to wrap</param> /// <param name="transformer">The block transformer to use</param> /// <param name="blockSize">Block size to use</param> public BlockWriteOnceStream(Stream wrappedStream, IBlockTransformer transformer, short blockSize = BLOCK_SIZE) : base(wrappedStream, transformer, blockSize) { currentBlock = new byte[BlockSize]; WrappedStream.Seek(0, SeekOrigin.Begin); wrappedStream.SetLength(0); }
protected virtual void Dispose(bool disposing, CloseExState closeState) { // All calls below should already be idempotent. try { if (disposing) { ICloseEx icloseEx = WrappedStream as ICloseEx; if (icloseEx != null) { icloseEx.CloseEx(closeState); } else { WrappedStream.Close(); } } } finally { base.Dispose(disposing); } }
public override int Read(byte[] buffer, int offset, int count) { int startOffset = (int)(_position % _blockSize); if (startOffset == 0 && (count % _blockSize == 0 || _position + count == Length)) { // Aligned read - pass through to underlying stream. WrappedStream.Position = _position; int numRead = WrappedStream.Read(buffer, offset, count); _position += numRead; return(numRead); } long startPos = MathUtilities.RoundDown(_position, _blockSize); long endPos = MathUtilities.RoundUp(_position + count, _blockSize); if (endPos - startPos > int.MaxValue) { throw new IOException("Oversized read, after alignment"); } byte[] tempBuffer = new byte[endPos - startPos]; WrappedStream.Position = startPos; int read = WrappedStream.Read(tempBuffer, 0, tempBuffer.Length); int available = Math.Min(count, read - startOffset); Array.Copy(tempBuffer, startOffset, buffer, offset, available); _position += available; return(available); }
public void Constructors_UnwritableStream_Throws() { using MemoryStream archiveStream = new MemoryStream(); using WrappedStream wrappedStream = new WrappedStream(archiveStream, canRead: true, canWrite: false, canSeek: false); Assert.Throws <IOException>(() => new TarWriter(wrappedStream)); Assert.Throws <IOException>(() => new TarWriter(wrappedStream, TarEntryFormat.V7)); }
public override int EndRead(IAsyncResult asyncResult) { int result = WrappedStream.EndRead(asyncResult); m_Position += result; return(result); }
public async void Write_To_UnseekableStream_Async() { await using (MemoryStream inner = new MemoryStream()) { await using (WrappedStream wrapped = new WrappedStream(inner, canRead: true, canWrite: true, canSeek: false)) { await using (TarWriter writer = new TarWriter(wrapped, TarEntryFormat.Pax, leaveOpen: true)) { PaxTarEntry paxEntry = new PaxTarEntry(TarEntryType.RegularFile, "file.txt"); await writer.WriteEntryAsync(paxEntry); } // The final records should get written, and the length should not be set because position cannot be read inner.Seek(0, SeekOrigin.Begin); // Rewind the base stream (wrapped cannot be rewound) await using (TarReader reader = new TarReader(wrapped)) { TarEntry entry = await reader.GetNextEntryAsync(); Assert.Equal(TarEntryFormat.Pax, entry.Format); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); Assert.Null(await reader.GetNextEntryAsync()); } } } }
public override int Read(byte[] buffer, int offset, int count) { try { if (Interlocked.Increment(ref m_ReadNesting) != 1) { throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "Read", "read")); } if (m_HeadEOF) { return(WrappedStream.Read(buffer, offset, count)); } else { int result = m_HeadStream.Read(buffer, offset, count); m_HeadLength += result; if (result == 0 && count != 0) { m_HeadEOF = true; m_HeadStream.Close(); result = WrappedStream.Read(buffer, offset, count); } return(result); } } finally { Interlocked.Decrement(ref m_ReadNesting); } }
private byte[] LoadData(int blockIndex) { ThrowIfDisposed(); if (m_blocks !.Count <= blockIndex) { m_blocks.AddRange(new byte[blockIndex - m_blocks.Count + 1][]); } var blockData = m_blocks[blockIndex]; if (blockData is null) { WrappedStream.Position = blockIndex * c_blockSize; blockData = new byte[c_blockSize]; var bytesRead = WrappedStream.ReadBlock(blockData, 0, blockData.Length); if (bytesRead != c_blockSize) { Array.Resize(ref blockData, bytesRead); } m_blocks[blockIndex] = blockData; } return(blockData); }
private async Task <byte[]> LoadDataAsync(int blockIndex) { ThrowIfDisposed(); if (m_blocks !.Count <= blockIndex) { m_blocks.AddRange(new byte[blockIndex - m_blocks.Count + 1][]); } var blockData = m_blocks[blockIndex]; if (blockData is null) { WrappedStream.Position = blockIndex * c_blockSize; blockData = new byte[c_blockSize]; var bytesRead = await WrappedStream.ReadBlockAsync(blockData, 0, blockData.Length).ConfigureAwait(false); if (bytesRead != c_blockSize) { Array.Resize(ref blockData, bytesRead); } m_blocks[blockIndex] = blockData; } return(blockData); }
public void Constructor_ConversionFromUstar_From_UnseekableTarReader(TarEntryFormat writerFormat) { using MemoryStream source = GetTarMemoryStream(CompressionMethod.Uncompressed, TestTarFormat.ustar, "file"); using WrappedStream wrappedSource = new WrappedStream(source, canRead: true, canWrite: false, canSeek: false); using TarReader sourceReader = new TarReader(wrappedSource, leaveOpen: true); UstarTarEntry ustarEntry = sourceReader.GetNextEntry(copyData: false) as UstarTarEntry; V7TarEntry v7Entry = new V7TarEntry(other: ustarEntry); // Convert, and avoid advancing wrappedSource position using MemoryStream destination = new MemoryStream(); using (TarWriter writer = new TarWriter(destination, writerFormat, leaveOpen: true)) { writer.WriteEntry(v7Entry); // Write DataStream exactly where the wrappedSource position was left } destination.Position = 0; // Rewind using (TarReader destinationReader = new TarReader(destination, leaveOpen: false)) { V7TarEntry resultEntry = destinationReader.GetNextEntry() as V7TarEntry; Assert.NotNull(resultEntry); using (StreamReader streamReader = new StreamReader(resultEntry.DataStream)) { Assert.Equal("Hello file", streamReader.ReadToEnd()); } } }
public override int EndRead(IAsyncResult asyncResult) { if (Interlocked.Decrement(ref m_ReadNesting) != 0) { Interlocked.Increment(ref m_ReadNesting); throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndRead")); } if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } InnerAsyncResult myResult = asyncResult as InnerAsyncResult; if (myResult == null) { // We are just passing IO down, although m_HeadEOF should be always true here. GlobalLog.Assert(m_HeadEOF, "CombinedReadStream::EndRead|m_HeadEOF is false and asyncResult is not of InnerAsyncResult type {0).", asyncResult.GetType().FullName); return(m_HeadEOF? WrappedStream.EndRead(asyncResult): m_HeadStream.EndRead(asyncResult)); } // this is our wrapped AsyncResult myResult.InternalWaitForCompletion(); // Exception? if (myResult.Result is Exception) { throw (Exception)(myResult.Result); } // Report the count read return((int)myResult.Result); }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { if (m_Position + offset > m_Offset + m_Size) { throw new NotSupportedException(SR.GetString(SR.net_cache_unsupported_partial_stream)); } return(WrappedStream.BeginWrite(buffer, offset, count, callback, state)); }
private void DoOperation(ModifyStream modifyStream, ModifyBuffer modifyBuffer, int count) { int startOffset = (int)(_position % _blockSize); if (startOffset == 0 && (count % _blockSize == 0 || _position + count == Length)) { WrappedStream.Position = _position; modifyStream(WrappedStream, 0, count); _position += count; return; } long unalignedEnd = _position + count; long alignedPos = MathUtilities.RoundDown(_position, _blockSize); if (startOffset != 0) { WrappedStream.Position = alignedPos; WrappedStream.Read(_alignmentBuffer, 0, _blockSize); modifyBuffer(_alignmentBuffer, startOffset, 0, Math.Min(count, _blockSize - startOffset)); WrappedStream.Position = alignedPos; WrappedStream.Write(_alignmentBuffer, 0, _blockSize); } alignedPos = MathUtilities.RoundUp(_position, _blockSize); if (alignedPos >= unalignedEnd) { _position = unalignedEnd; return; } int passthroughLength = (int)MathUtilities.RoundDown(_position + count - alignedPos, _blockSize); if (passthroughLength > 0) { WrappedStream.Position = alignedPos; modifyStream(WrappedStream, (int)(alignedPos - _position), passthroughLength); } alignedPos += passthroughLength; if (alignedPos >= unalignedEnd) { _position = unalignedEnd; return; } WrappedStream.Position = alignedPos; WrappedStream.Read(_alignmentBuffer, 0, _blockSize); modifyBuffer(_alignmentBuffer, 0, (int)(alignedPos - _position), (int)Math.Min(count - (alignedPos - _position), unalignedEnd - alignedPos)); WrappedStream.Position = alignedPos; WrappedStream.Write(_alignmentBuffer, 0, _blockSize); _position = unalignedEnd; }
public static async Task TestStreamingRead(string zipFile, string zipFolder) { using (var stream = await StreamHelpers.CreateTempCopyStream(zfile(zipFile))) { Stream wrapped = new WrappedStream(stream, true, false, false, null); IsZipSameAsDir(wrapped, zfolder(zipFolder), ZipArchiveMode.Read, false, false); Assert.False(wrapped.CanRead, "Wrapped stream should be closed at this point"); //check that it was closed } }
private static async Task TestStreamingRead(String zipFile, String directory) { using (var stream = await StreamHelpers.CreateTempCopyStream(zipFile)) { Stream wrapped = new WrappedStream(stream, true, false, false, null); ZipTest.IsZipSameAsDir(wrapped, directory, ZipArchiveMode.Read, false, false); Assert.False(wrapped.CanRead, "Wrapped stream should be closed at this point"); //check that it was closed } }
public override void Write(byte[] buffer, int offset, int count) { if (m_Position + count > m_Offset + m_Size) { throw new NotSupportedException(SR.GetString(SR.net_cache_unsupported_partial_stream)); } WrappedStream.Write(buffer, offset, count); m_Position += count; }
public override int EndRead(IAsyncResult asyncResult) { if (Interlocked.Decrement(ref m_ReadNesting) != 0) { Interlocked.Increment(ref m_ReadNesting); throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndRead")); } if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } InnerAsyncResult myResult = asyncResult as InnerAsyncResult; if (myResult == null) { // We are just passing IO down, although the shadow stream should be dead for now. GlobalLog.Assert(m_ShadowStreamIsDead, "ForwardingReadStream::EndRead|m_ShadowStreamIsDead is false and asyncResult is not of InnerAsyncResult type {0}.", asyncResult.GetType().FullName); int bytes = WrappedStream.EndRead(asyncResult); if (bytes == 0) { m_SeenReadEOF = true; } } // this is our wrapped AsyncResult bool suceess = false; try { myResult.InternalWaitForCompletion(); // Exception? if (myResult.Result is Exception) { throw (Exception)(myResult.Result); } suceess = true; } finally { if (!suceess && !m_ShadowStreamIsDead) { m_ShadowStreamIsDead = true; if (m_ShadowStream is ICloseEx) { ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent); } else { m_ShadowStream.Close(); } } } // Report the read count return((int)myResult.Result); }
public async Task UnreadableStream_Throws_Async() { using (MemoryStream archive = new MemoryStream()) { using (WrappedStream unreadable = new WrappedStream(archive, canRead: false, canWrite: true, canSeek: true)) { await Assert.ThrowsAsync <IOException>(() => TarFile.ExtractToDirectoryAsync(unreadable, destinationDirectoryName: "path", overwriteFiles: false)); } } }
[Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)] // Jenkins fails with unicode characters [JENKINS-12610] public static async Task CreateNormal_Unicode(string folder, bool seekable) { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, seekable, null); await CreateFromDir(zfolder(folder), testStream, ZipArchiveMode.Create); IsZipSameAsDir(s, zfolder(folder), ZipArchiveMode.Read, requireExplicit: true, checkTimes: true); } }
public static async Task testCreate(String folder, bool seekable) { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, seekable, null); await ZipTest.CreateFromDir(ZipTest.zfolder(folder), testStream, ZipArchiveMode.Create); ZipTest.IsZipSameAsDir(s, ZipTest.zfolder(folder), ZipArchiveMode.Read, false, false); } }
public static async Task CreateNormal_Unicode_Seekable() { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, true, null); await CreateFromDir(zfolder("unicode"), testStream, ZipArchiveMode.Create); IsZipSameAsDir(s, zfolder("unicode"), ZipArchiveMode.Read, requireExplicit: true, checkTimes: true); } }
public static async Task CreateNormal_Seekable(string folder, bool useSpansForWriting, bool writeInChunks) { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, true, null); await CreateFromDir(zfolder(folder), testStream, ZipArchiveMode.Create, useSpansForWriting, writeInChunks); IsZipSameAsDir(s, zfolder(folder), ZipArchiveMode.Read, requireExplicit: true, checkTimes: true); } }
[Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)] // Jenkins fails with unicode characters [JENKINS-12610] public static async Task CreateNormal_Unicode(string folder, bool seekable) { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, seekable, null); await ZipTest.CreateFromDir(ZipTest.zfolder(folder), testStream, ZipArchiveMode.Create); ZipTest.IsZipSameAsDir(s, ZipTest.zfolder(folder), ZipArchiveMode.Read, false, false); } }
public async Task UnwritableStream_Throws_Async() { await using (MemoryStream archiveStream = new MemoryStream()) { await using (WrappedStream unwritable = new WrappedStream(archiveStream, canRead: true, canWrite: false, canSeek: true)) { await Assert.ThrowsAsync <IOException>(() => TarFile.CreateFromDirectoryAsync(sourceDirectoryName: "path", destination: unwritable, includeBaseDirectory: false)); } } }
[Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)] // Jenkins fails with unicode characters [JENKINS-12610] public static async Task CreateNormal_Unicode(string folder, bool seekable) { using (var s = new MemoryStream()) { var testStream = new WrappedStream(s, false, true, seekable, null); await CreateFromDir(zfolder(folder), testStream, ZipArchiveMode.Create); IsZipSameAsDir(s, zfolder(folder), ZipArchiveMode.Read, false, false); } }
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { if (m_Position >= m_Offset + m_Size) { count = 0; } else if (m_Position + count > m_Offset + m_Size) { count = (int)(m_Offset + m_Size - m_Position); } return(WrappedStream.BeginRead(buffer, offset, count, callback, state)); }
public async Task JsonRpcClosesStreamAfterDisconnectedEvent() { var server = new Server(); var streams = Nerdbank.FullDuplexStream.CreateStreams(); var clientStream = streams.Item2; // Use wrapped stream to see when the stream is closed and disposed. var serverStream = new WrappedStream(streams.Item1); // Subscribe to disconnected event on the server stream var serverStreamDisconnected = new TaskCompletionSource <object?>(); serverStream.Disconnected += (sender, args) => serverStreamDisconnected.SetResult(null); using (JsonRpc serverRpc = JsonRpc.Attach(serverStream, server)) { // Subscribe to disconnected event on json rpc var disconnectedEventFired = new TaskCompletionSource <JsonRpcDisconnectedEventArgs>(); object?disconnectedEventSender = null; serverRpc.Disconnected += (object?sender, JsonRpcDisconnectedEventArgs e) => { // The stream must not be disposed when the Disconnected even fires Assert.True(serverStream.IsConnected); disconnectedEventSender = sender; disconnectedEventFired.SetResult(e); }; // Send a bad json to the server byte[] badJson = Encoding.UTF8.GetBytes("Content-Length: 1\r\n\r\n{"); await clientStream.WriteAsync(badJson, 0, badJson.Length); // The server must fire disonnected event because bad json must make it disconnect JsonRpcDisconnectedEventArgs args = await disconnectedEventFired.Task.WithCancellation(this.TimeoutToken); Assert.Same(serverRpc, disconnectedEventSender); Assert.NotNull(args); Assert.NotNull(args.Description); Assert.Equal(DisconnectedReason.ParseError, args.Reason); #pragma warning disable CS0618 // Type or member is obsolete Assert.Null(args.LastMessage); #pragma warning restore CS0618 // Type or member is obsolete Assert.NotNull(args.Exception); // Server must dispose the stream now await serverStreamDisconnected.Task.WithCancellation(this.TimeoutToken); Assert.True(serverStream.Disposed); Assert.False(serverStream.IsEndReached); } }
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { try { if (Interlocked.Increment(ref m_ReadNesting) != 1) { throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "BeginRead", "read")); } if (m_ReadCallback == null) { m_ReadCallback = new AsyncCallback(ReadCallback); } if (m_HeadEOF) { return(WrappedStream.BeginRead(buffer, offset, count, callback, state)); } else { InnerAsyncResult userResult = new InnerAsyncResult(state, callback, buffer, offset, count); IAsyncResult ar = m_HeadStream.BeginRead(buffer, offset, count, m_ReadCallback, userResult); if (!ar.CompletedSynchronously) { return(userResult); } int bytes = m_HeadStream.EndRead(ar); m_HeadLength += bytes; //check on EOF condition if (bytes == 0 && userResult.Count != 0) { //Got a first stream EOF m_HeadEOF = true; m_HeadStream.Close(); return(WrappedStream.BeginRead(buffer, offset, count, callback, state)); } else { // just complete user IO userResult.Buffer = null; userResult.InvokeCallback(count); return(userResult); } } } catch { Interlocked.Decrement(ref m_ReadNesting); throw; } }
private void ReadCallback(IAsyncResult transportResult) { GlobalLog.Assert(transportResult.AsyncState is InnerAsyncResult, "InnerAsyncResult::ReadCallback|The state expected to be of type InnerAsyncResult, received {0}.", transportResult.GetType().FullName); if (transportResult.CompletedSynchronously) { return; } InnerAsyncResult userResult = transportResult.AsyncState as InnerAsyncResult; try { // Complete transport IO, in this callback that is always the head stream int count; if (!m_HeadEOF) { count = m_HeadStream.EndRead(transportResult); m_HeadLength += count; } else { count = WrappedStream.EndRead(transportResult); } //check on EOF condition if (!m_HeadEOF && count == 0 && userResult.Count != 0) { //Got a first stream EOF m_HeadEOF = true; m_HeadStream.Close(); IAsyncResult ar = WrappedStream.BeginRead(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult); if (!ar.CompletedSynchronously) { return; } count = WrappedStream.EndRead(ar); } // just complete user IO userResult.Buffer = null; userResult.InvokeCallback(count); } catch (Exception e) { //ASYNC: try to ignore even serious exceptions (nothing to loose?) if (userResult.InternalPeekCompleted) { throw; } userResult.InvokeCallback(e); } }
public async Task GetNextEntry_UnseekableArchive_ReplaceDataStream_ExcludeFromDisposing_Async(bool copyData) { await using (MemoryStream archive = new MemoryStream()) { await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt"); entry1.DataStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(entry1.DataStream, leaveOpen: true)) { streamWriter.WriteLine("Hello world!"); } entry1.DataStream.Seek(0, SeekOrigin.Begin); // Rewind to ensure it gets written from the beginning await writer.WriteEntryAsync(entry1); UstarTarEntry entry2 = new UstarTarEntry(TarEntryType.Directory, "dir"); await writer.WriteEntryAsync(entry2); } archive.Seek(0, SeekOrigin.Begin); await using (WrappedStream wrapped = new WrappedStream(archive, canRead: true, canWrite: false, canSeek: false)) { UstarTarEntry entry; Stream oldStream; await using (TarReader reader = new TarReader(wrapped)) // Unseekable { entry = await reader.GetNextEntryAsync(copyData) as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); oldStream = entry.DataStream; entry.DataStream = new MemoryStream(); // Substitution, setter should dispose the previous stream using (StreamWriter streamWriter = new StreamWriter(entry.DataStream, leaveOpen: true)) { streamWriter.WriteLine("Substituted"); } } // Disposing reader should not dispose the substituted DataStream Assert.Throws <ObjectDisposedException>(() => oldStream.Read(new byte[1])); entry.DataStream.Seek(0, SeekOrigin.Begin); using (StreamReader streamReader = new StreamReader(entry.DataStream)) { Assert.Equal("Substituted", streamReader.ReadLine()); } } } }
public void SetUp() { source = new MemoryStream(30); for (int i = 0; i < source.Capacity; i++) { source.WriteByte(0x55); } source.Position = wrappedStartPosition; ws = new WrappedStream(source, wrappedSize); }