diff --git a/binding/Binding/SKManagedStream.cs b/binding/Binding/SKManagedStream.cs index 50927a0aa8..8bf6dab1c0 100644 --- a/binding/Binding/SKManagedStream.cs +++ b/binding/Binding/SKManagedStream.cs @@ -87,20 +87,22 @@ protected override void DisposeManaged () private IntPtr OnReadManagedStream (IntPtr buffer, IntPtr size) { - if (buffer == IntPtr.Zero) - throw new ArgumentNullException (nameof (buffer)); if ((int)size < 0) throw new ArgumentOutOfRangeException (nameof (size)); if (size == IntPtr.Zero) return IntPtr.Zero; + // NOTE: some skips still requires a read as some streams cannot seek using var managedBuffer = Utils.RentArray ((int)size); var len = stream.Read (managedBuffer.Array, 0, managedBuffer.Length); - var src = managedBuffer.Span.Slice (0, len); - var dst = buffer.AsSpan (managedBuffer.Length); - src.CopyTo (dst); + if (buffer != IntPtr.Zero) { + // read + var src = managedBuffer.Span.Slice (0, len); + var dst = buffer.AsSpan (managedBuffer.Length); + src.CopyTo (dst); + } if (!stream.CanSeek && (int)size > 0 && len <= (int)size) isAsEnd = true; diff --git a/tests/Content/images/tomato.bmp b/tests/Content/images/tomato.bmp new file mode 100644 index 0000000000..d4c67b501a Binary files /dev/null and b/tests/Content/images/tomato.bmp differ diff --git a/tests/Tests/SKBitmapTest.cs b/tests/Tests/SKBitmapTest.cs index 9f671b4a23..88d58e8c66 100644 --- a/tests/Tests/SKBitmapTest.cs +++ b/tests/Tests/SKBitmapTest.cs @@ -739,5 +739,20 @@ public void CanDecodePotentiallyCorruptPngFiles(string filename) Assert.NotNull(bitmap); } + + [Theory] + [InlineData("tomato.bmp")] + [InlineData("baboon.jpg")] + [InlineData("baboon.png")] + [InlineData("animated-heart.gif")] + public void CanDecodeImageStreams(string filename) + { + var path = Path.Combine(PathToImages, filename); + + using var stream = File.OpenRead(path); + using var bitmap = SKBitmap.Decode(stream); + + Assert.NotNull(bitmap); + } } } diff --git a/tests/Tests/SKManagedStreamTest.cs b/tests/Tests/SKManagedStreamTest.cs index 1ae70ad3ad..9fa99eb86f 100644 --- a/tests/Tests/SKManagedStreamTest.cs +++ b/tests/Tests/SKManagedStreamTest.cs @@ -147,11 +147,83 @@ public void ReadIsCorrect(int dataSize, int readSize, int finalPos, int expected var actualReadSize = managedStream.Read(buffer, readSize); Assert.Equal(expectedReadSize, actualReadSize); + Assert.Equal(finalPos, stream.Position); Assert.Equal(finalPos, managedStream.Position); Assert.Equal(data.Take(readSize), buffer.Take(actualReadSize)); Assert.All(buffer.Skip(actualReadSize), i => Assert.Equal(0, i)); } + [SkippableTheory] + [InlineData(1024, 0, 0, 0)] + [InlineData(1024, 1, 1, 1)] + [InlineData(1024, 10, 10, 10)] + [InlineData(1024, 100, 100, 100)] + [InlineData(1024, 1000, 1000, 1000)] + [InlineData(1024, 10000, 1024, 1024)] + public void SkipIsCorrect(int dataSize, int readSize, int finalPos, int expectedReadSize) + { + var data = new byte[dataSize]; + for (var i = 0; i < data.Length; i++) + { + data[i] = (byte)(i % byte.MaxValue); + } + + var stream = new MemoryStream(data); + var managedStream = new SKManagedStream(stream); + + var actualReadSize = managedStream.Skip(readSize); + + Assert.Equal(expectedReadSize, actualReadSize); + Assert.Equal(finalPos, stream.Position); + Assert.Equal(finalPos, managedStream.Position); + } + + [SkippableTheory] + [InlineData(1024, 0, 0, 0)] + [InlineData(1024, 1, 1, 1)] + [InlineData(1024, 10, 10, 10)] + [InlineData(1024, 100, 100, 100)] + [InlineData(1024, 1000, 1000, 1000)] + [InlineData(1024, 10000, 1024, 1024)] + public void SkipNonSeekableIsCorrect(int dataSize, int readSize, int finalPos, int expectedReadSize) + { + var data = new byte[dataSize]; + for (var i = 0; i < data.Length; i++) + { + data[i] = (byte)(i % byte.MaxValue); + } + + var stream = new MemoryStream(data); + var nonSeekable = new NonSeekableReadOnlyStream(stream); + var managedStream = new SKManagedStream(nonSeekable); + + var actualReadSize = managedStream.Skip(readSize); + + Assert.Equal(expectedReadSize, actualReadSize); + Assert.Equal(finalPos, stream.Position); + } + + [SkippableFact] + public void SkipOffsetChunkCorrectly() + { + var data = new byte[1024]; + for (int i = 0; i < data.Length; i++) + { + data[i] = (byte)(i % byte.MaxValue); + } + + var stream = new MemoryStream(data); + var skManagedStream = new SKManagedStream(stream); + + var offset = 768; + + skManagedStream.Position = offset; + + var taken = skManagedStream.Skip(data.Length); + + Assert.Equal(data.Length - offset, taken); + } + [SkippableFact] public void ManagedStreamReadsChunkCorrectly() {