From 8d39156d37d675bc35223ef1583d51b563b3849d Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Wed, 1 Jan 2025 13:32:47 +0100 Subject: [PATCH] Fix partial reads on compressed data --- MatFileHandler.Tests/MatFileReaderTests.cs | 2 +- .../PartialReadMatTestDataFactory.cs | 35 ++++++++ MatFileHandler.Tests/PartialReadStream.cs | 84 +++++++++++++++++++ MatFileHandler/DataElementReader.cs | 3 +- 4 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 MatFileHandler.Tests/PartialReadMatTestDataFactory.cs create mode 100644 MatFileHandler.Tests/PartialReadStream.cs diff --git a/MatFileHandler.Tests/MatFileReaderTests.cs b/MatFileHandler.Tests/MatFileReaderTests.cs index 41e408d..8645b82 100755 --- a/MatFileHandler.Tests/MatFileReaderTests.cs +++ b/MatFileHandler.Tests/MatFileReaderTests.cs @@ -529,7 +529,7 @@ namespace MatFileHandler.Tests } private static AbstractTestDataFactory GetTests(string factoryName) => - new MatTestDataFactory(Path.Combine(TestDirectory, factoryName)); + new PartialReadMatTestDataFactory(Path.Combine(TestDirectory, factoryName)); private static void CheckLimits(IArrayOf array, T[] limits) where T : struct diff --git a/MatFileHandler.Tests/PartialReadMatTestDataFactory.cs b/MatFileHandler.Tests/PartialReadMatTestDataFactory.cs new file mode 100644 index 0000000..f77f7f1 --- /dev/null +++ b/MatFileHandler.Tests/PartialReadMatTestDataFactory.cs @@ -0,0 +1,35 @@ +// Copyright 2017-2018 Alexander Luzgarev + +using System.IO; + +namespace MatFileHandler.Tests +{ + /// + /// Factory providing the parsed contents of .mat files, + /// wrapped in a . + /// + public class PartialReadMatTestDataFactory : MatTestDataFactory + { + /// + /// Initializes a new instance of the class. + /// + /// Directory containing test files. + public PartialReadMatTestDataFactory(string testDirectory) + : base(testDirectory) + { + } + + /// + /// Read and parse data from a .mat file. + /// + /// Input stream. + /// Parsed contents of the file. + protected override IMatFile ReadDataFromStream(Stream stream) + { + using (var wrapper = new PartialReadStream(stream)) + { + return base.ReadDataFromStream(wrapper); + } + } + } +} diff --git a/MatFileHandler.Tests/PartialReadStream.cs b/MatFileHandler.Tests/PartialReadStream.cs new file mode 100644 index 0000000..b056457 --- /dev/null +++ b/MatFileHandler.Tests/PartialReadStream.cs @@ -0,0 +1,84 @@ +// Copyright 2017-2018 Alexander Luzgarev + +using System; +using System.IO; + +namespace MatFileHandler.Tests +{ + /// + /// A stream which wraps another stream and only reads one byte at a time. + /// + internal class PartialReadStream : Stream + { + private readonly Stream _baseStream; + + /// + /// Initializes a new instance of the class. + /// + /// The stream to wrap. + public PartialReadStream(Stream baseStream) + { + _baseStream = baseStream; + } + + /// + public override bool CanRead => _baseStream.CanRead; + + /// + public override bool CanSeek => _baseStream.CanSeek; + + /// + public override bool CanWrite => false; + + /// + public override long Length => _baseStream.Length; + + /// + public override long Position + { + get => _baseStream.Position; + set => _baseStream.Position = value; + } + + /// + public override void Flush() + { + _baseStream.Flush(); + } + + /// + public override int Read(byte[] buffer, int offset, int count) + { + return _baseStream.Read(buffer, offset, Math.Min(1, count)); + } + + /// + public override long Seek(long offset, SeekOrigin origin) + { + return _baseStream.Seek(offset, origin); + } + + /// + public override void SetLength(long value) + { + _baseStream.SetLength(value); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + _baseStream.Dispose(); + } + + base.Dispose(disposing); + } + } +} diff --git a/MatFileHandler/DataElementReader.cs b/MatFileHandler/DataElementReader.cs index b678566..a116c80 100755 --- a/MatFileHandler/DataElementReader.cs +++ b/MatFileHandler/DataElementReader.cs @@ -354,8 +354,7 @@ namespace MatFileHandler private DataElement ReadCompressed(Tag tag, BinaryReader reader) { reader.ReadBytes(2); - var compressedData = new byte[tag.Length - 6]; - reader.BaseStream.Read(compressedData, 0, tag.Length - 6); + var compressedData = reader.ReadBytes(tag.Length - 6); reader.ReadBytes(4); var resultStream = new MemoryStream(); using (var compressedStream = new MemoryStream(compressedData))