diff --git a/MatFileHandler/DataElementReader.cs b/MatFileHandler/DataElementReader.cs
index c5e2679..9da8ab6 100755
--- a/MatFileHandler/DataElementReader.cs
+++ b/MatFileHandler/DataElementReader.cs
@@ -343,30 +343,33 @@ namespace MatFileHandler
return new MatStructureArray(flags, dimensions, name, fields);
}
- private DataElement Read(Stream stream)
- {
- using (var reader = new BinaryReader(stream))
- {
- return Read(reader);
- }
- }
-
private DataElement ReadCompressed(Tag tag, BinaryReader reader)
{
reader.ReadBytes(2);
- var compressedData = reader.ReadBytes(tag.Length - 6);
- reader.ReadBytes(4);
- var resultStream = new MemoryStream();
- using (var compressedStream = new MemoryStream(compressedData))
+
+ DataElement element;
+
+ using (var substream = new Substream(reader.BaseStream, tag.Length - 6))
{
- using (var stream = new DeflateStream(compressedStream, CompressionMode.Decompress, leaveOpen: true))
+ using (var deflateStream = new DeflateStream(substream, CompressionMode.Decompress))
+ using (var bufferedStream = new BufferedStream(deflateStream))
+ using (var positionTrackingStream = new PositionTrackingStream(bufferedStream))
+ using (var innerReader = new BinaryReader(positionTrackingStream))
{
- stream.CopyTo(resultStream);
+ element = Read(innerReader);
+ }
+
+ if (substream.Position != substream.Length)
+ {
+ // In the pathological case that the deflate stream did not read the full
+ // length, then read out the rest manually (normally 1 byte).
+ reader.ReadBytes((int)(substream.Length - substream.Position));
}
}
- resultStream.Position = 0;
- return Read(resultStream);
+ reader.ReadBytes(4);
+
+ return element;
}
private DataElement ReadMatrix(Tag tag, BinaryReader reader)
diff --git a/MatFileHandler/Substream.cs b/MatFileHandler/Substream.cs
new file mode 100644
index 0000000..df32ef0
--- /dev/null
+++ b/MatFileHandler/Substream.cs
@@ -0,0 +1,68 @@
+// Copyright 2017-2018 Alexander Luzgarev
+
+using System;
+using System.IO;
+
+namespace MatFileHandler
+{
+ ///
+ /// A stream which reads a finite section of another stream.
+ ///
+ internal sealed class Substream : Stream
+ {
+ private readonly Stream _baseStream;
+ private long _bytesRead;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to wrap.
+ /// The number of bytes readable from this .
+ public Substream(Stream baseStream, long length)
+ {
+ _baseStream = baseStream;
+ Length = length;
+ }
+
+ ///
+ public override bool CanRead => _baseStream.CanRead;
+
+ ///
+ public override bool CanSeek => false;
+
+ ///
+ public override bool CanWrite => false;
+
+ ///
+ public override long Length { get; }
+
+ ///
+ public override long Position
+ {
+ get => _bytesRead;
+ set => throw new NotSupportedException();
+ }
+
+ ///
+ public override void Flush() => _baseStream.Flush();
+
+ ///
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int bytesRead = _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - _bytesRead));
+
+ _bytesRead += bytesRead;
+
+ return bytesRead;
+ }
+
+ ///
+ public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
+
+ ///
+ public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+
+ ///
+ public override void SetLength(long value) => throw new NotSupportedException();
+ }
+}