From 840b7e2d8a0bd6bd1382acea516b7e4424d9d9a4 Mon Sep 17 00:00:00 2001 From: gmipf Date: Mon, 19 Oct 2026 15:40:57 +0200 Subject: [PATCH] Dispose the streams of a ReadOnlyCompositeStream (#6) Disposing a ReadOnlyCompositeStream did not dispose the streams it reads from, so files opened only for the composite stayed open until their streams were finalized. WiseOverlayHeader.OpenFile in SabreTools.Serialization opens a Wise installer and all of its parts this way. Co-authored-by: Claude Opus 5.5 --- .../ReadOnlyCompositeStreamTests.cs | 18 ++++++++++++++++++ SabreTools.IO/ReadOnlyCompositeStream.cs | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/SabreTools.IO.Test/ReadOnlyCompositeStreamTests.cs b/SabreTools.IO.Test/ReadOnlyCompositeStreamTests.cs index 34efcd1..29eafd2 100644 --- a/SabreTools.IO.Test/ReadOnlyCompositeStreamTests.cs +++ b/SabreTools.IO.Test/ReadOnlyCompositeStreamTests.cs @@ -158,6 +158,24 @@ namespace SabreTools.IO.Test #endregion + #region Dispose + + [Fact] + public void Dispose_DisposesStreams() + { + var first = new MemoryStream(new byte[128]); + var second = new MemoryStream(new byte[128]); + var stream = new ReadOnlyCompositeStream(first); + stream.AddStream(second); + + stream.Dispose(); + + Assert.False(first.CanRead); + Assert.False(second.CanRead); + } + + #endregion + #region Unimplemented [Fact] diff --git a/SabreTools.IO/ReadOnlyCompositeStream.cs b/SabreTools.IO/ReadOnlyCompositeStream.cs index 15c0250..36ae064 100644 --- a/SabreTools.IO/ReadOnlyCompositeStream.cs +++ b/SabreTools.IO/ReadOnlyCompositeStream.cs @@ -163,6 +163,20 @@ namespace SabreTools.IO #region Stream Implementations + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + foreach (var stream in _streams) + { + stream.Dispose(); + } + } + + base.Dispose(disposing); + } + /// public override void Flush() => throw new NotImplementedException();