Fix partial reads on compressed data #27

Merged
Rob-Hague merged 1 commits from partialread into master 2025-01-09 16:57:44 +00:00
4 changed files with 121 additions and 3 deletions

View File

@ -529,7 +529,7 @@ namespace MatFileHandler.Tests
}
private static AbstractTestDataFactory<IMatFile> GetTests(string factoryName) =>
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
new PartialReadMatTestDataFactory(Path.Combine(TestDirectory, factoryName));
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
where T : struct

View File

@ -0,0 +1,35 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// Factory providing the parsed contents of .mat files,
/// wrapped in a <see cref="PartialReadStream"/>.
/// </summary>
public class PartialReadMatTestDataFactory : MatTestDataFactory
{
/// <summary>
/// Initializes a new instance of the <see cref="PartialReadMatTestDataFactory"/> class.
/// </summary>
/// <param name="testDirectory">Directory containing test files.</param>
public PartialReadMatTestDataFactory(string testDirectory)
: base(testDirectory)
{
}
/// <summary>
/// Read and parse data from a .mat file.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <returns>Parsed contents of the file.</returns>
protected override IMatFile ReadDataFromStream(Stream stream)
{
using (var wrapper = new PartialReadStream(stream))
{
return base.ReadDataFromStream(wrapper);
}
}
}
}

View File

@ -0,0 +1,84 @@
// Copyright 2017-2018 Alexander Luzgarev
using System;
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// A stream which wraps another stream and only reads one byte at a time.
/// </summary>
internal class PartialReadStream : Stream
{
private readonly Stream _baseStream;
/// <summary>
/// Initializes a new instance of the <see cref="PartialReadStream"/> class.
/// </summary>
/// <param name="baseStream">The stream to wrap.</param>
public PartialReadStream(Stream baseStream)
{
_baseStream = baseStream;
}
/// <inheritdoc/>
public override bool CanRead => _baseStream.CanRead;
/// <inheritdoc/>
public override bool CanSeek => _baseStream.CanSeek;
/// <inheritdoc/>
public override bool CanWrite => false;
/// <inheritdoc/>
public override long Length => _baseStream.Length;
/// <inheritdoc/>
public override long Position
{
get => _baseStream.Position;
set => _baseStream.Position = value;
}
/// <inheritdoc/>
public override void Flush()
{
_baseStream.Flush();
}
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, Math.Min(1, count));
}
/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
/// <inheritdoc/>
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (disposing)
{
_baseStream.Dispose();
}
base.Dispose(disposing);
}
}
}

View File

@ -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))