Seal and update IFilters to return ReadOnlyMemory<byte> (#843)

* Avoid ToArray() in memoryFactory

* Seal and update IFilters to return ReadOnlyMemory<byte>

* Fix filter tests

* Seal and update IFilters to return ReadOnlyMemory<byte>
This commit is contained in:
BobLd
2024-06-08 06:16:09 +01:00
committed by GitHub
parent 65a18b200f
commit affc1ed8b5
18 changed files with 41 additions and 49 deletions

View File

@@ -22,7 +22,7 @@ O<DJ+*.@<*K0@<6L(Df-\0Ec5e;DffZ(EZee.Bl.9pF""AGXBPCsi + DGm >@3BB / F * &OCAfu2
var result = filter.Decode(bytes, dictionary, 0);
var text = Encoding.ASCII.GetString(result);
var text = Encoding.ASCII.GetString(result.ToArray());
Assert.Equal("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, " +
"that by a perseverance of delight in the continued and indefatigable generation of knowledge, " +
@@ -37,7 +37,7 @@ O<DJ+*.@<*K0@<6L(Df-\0Ec5e;DffZ(EZee.Bl.9pF""AGXBPCsi + DGm >@3BB / F * &OCAfu2
var result = filter.Decode(bytes, dictionary, 1);
var text = Encoding.ASCII.GetString(result);
var text = Encoding.ASCII.GetString(result.ToArray());
Assert.Equal("Man \0\0\0\0is d", text);
}
@@ -104,7 +104,7 @@ Li?EZek1DKKT1F`2DD/TboKAKY](@:s.m/h%oBC'mC/$>""*cF*)G6@;Q?_DIdZpC&~>";
var result = filter.Decode(Encoding.ASCII.GetBytes(input), dictionary, 0);
var text = Encoding.ASCII.GetString(result);
var text = Encoding.ASCII.GetString(result.ToArray());
Assert.Equal(PdfContent.Replace("\r\n", "\n"), text);
}
@@ -124,7 +124,7 @@ Li?EZek1DKKT1F`2DD/TboKAKY](@:s.m/h%oBC'mC/$>""*cF*)G6@;Q?_DIdZpC&";
var result = filter.Decode(Encoding.ASCII.GetBytes(input), dictionary, 0);
var text = Encoding.ASCII.GetString(result);
var text = Encoding.ASCII.GetString(result.ToArray());
Assert.Equal(PdfContent.Replace("\r\n", "\n"), text);
}

View File

@@ -18,7 +18,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
var decodedText = Encoding.ASCII.GetString(decoded);
var decodedText = Encoding.ASCII.GetString(decoded.ToArray());
Assert.Equal(text, decodedText);
}
@@ -33,7 +33,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
var decodedText = Encoding.ASCII.GetString(decoded);
var decodedText = Encoding.ASCII.GetString(decoded.ToArray());
Assert.Equal(text, decodedText);
}
@@ -49,7 +49,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
var decodedText = Encoding.ASCII.GetString(decoded);
var decodedText = Encoding.ASCII.GetString(decoded.ToArray());
Assert.Equal(text, decodedText);
}
@@ -63,7 +63,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
var decodedText = Encoding.ASCII.GetString(decoded);
var decodedText = Encoding.ASCII.GetString(decoded.ToArray());
Assert.Equal(text, decodedText);
}
@@ -88,7 +88,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
#pragma warning disable SYSLIB0001
var decodedText = Encoding.UTF7.GetString(decoded);
var decodedText = Encoding.UTF7.GetString(decoded.ToArray());
#pragma warning restore SYSLIB0001
Assert.Equal("®P", decodedText);
@@ -103,7 +103,7 @@
var decoded = new AsciiHexDecodeFilter().Decode(input, dictionary, 1);
var decodedText = Encoding.ASCII.GetString(decoded);
var decodedText = Encoding.ASCII.GetString(decoded.ToArray());
Assert.Equal(text, decodedText);
}

View File

@@ -32,7 +32,7 @@
var expectedBytes = ImageHelpers.LoadFileBytes("ccittfax-decoded.bin");
var decodedBytes = filter.Decode(encodedBytes, new DictionaryToken(dictionary), 0);
Assert.Equal(expectedBytes, decodedBytes);
Assert.Equal(expectedBytes, decodedBytes.ToArray());
}
}
}

View File

@@ -18,7 +18,7 @@
inputStream.Seek(0, SeekOrigin.Begin);
var result = filter.Encode(inputStream, parameters, 0);
var decoded = filter.Decode(result, parameters, 0);
Assert.Equal(input, decoded);
Assert.Equal(input, decoded.ToArray());
}
}
}

View File

@@ -35,7 +35,7 @@
10, 19
};
Assert.Equal(expectedResult, decoded);
Assert.Equal(expectedResult, decoded.ToArray());
}
[Fact]
@@ -61,7 +61,7 @@
128, 50
};
Assert.Equal(expectedResult, decoded);
Assert.Equal(expectedResult, decoded.ToArray());
}
}
}

View File

@@ -96,14 +96,14 @@
});
var filter = new FlateFilter();
var filtered = filter.Decode(streamBytes, dictionary, 0);
var filtered = filter.Decode(streamBytes, dictionary, 0).ToArray();
var expected =
"1 0 15 0 1 0 216 0 1 2 160 0 1 2 210 0 1 3 84 0 1 4 46 0 1 7 165 0 1 70 229 0 1 72 84 0 1 96 235 0 1 98 18 0 2 0 12 0 2 0 12 1 2 0 12 2 2 0 12 3 2 0 12 4 2 0 12 5 2 0 12 6 2 0 12 7 2 0 12 8"
.Split(' ')
.Select(byte.Parse).ToArray();
Assert.Equal(filtered, expected);
Assert.Equal(expected, filtered);
}
/// <summary>

View File

@@ -93,14 +93,14 @@
memoryFactory = supportsFilters ? new Lazy<ReadOnlyMemory<byte>>(() =>
{
var b = rawMemory.Span;
var b = RawMemory;
for (var i = 0; i < filters.Count; i++)
{
var filter = filters[i];
b = filter.Decode(b, streamDictionary, i);
b = filter.Decode(b.Span, streamDictionary, i);
}
return b.ToArray();
return b;
}) : null;
}

View File

@@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.Filters
{
using System;
using System.Collections.Generic;
using Core;
using Tokens;
@@ -9,7 +8,7 @@
/// <summary>
/// ASCII 85 (Base85) is a binary to text encoding using 5 ASCII characters per 4 bytes of data.
/// </summary>
internal class Ascii85Filter : IFilter
internal sealed class Ascii85Filter : IFilter
{
private const byte EmptyBlock = (byte)'z';
private const byte Offset = (byte)'!';
@@ -29,7 +28,7 @@
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
var asciiBuffer = new byte[5];
@@ -98,8 +97,7 @@
WriteData(asciiBuffer, index, writer);
}
return writer.WrittenSpan.ToArray();
return writer.WrittenMemory;
}
private static void WriteData(Span<byte> ascii, int index, ArrayPoolBufferWriter<byte> writer)

View File

@@ -29,7 +29,7 @@
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
Span<byte> pair = stackalloc byte[2];
var index = 0;
@@ -69,7 +69,7 @@
WriteHexToByte(pair, writer);
}
return writer.WrittenSpan.ToArray();
return writer.WrittenMemory;
}
private static void WriteHexToByte(ReadOnlySpan<byte> hexBytes, ArrayPoolBufferWriter<byte> writer)

View File

@@ -16,7 +16,7 @@
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
var decodeParms = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);

View File

@@ -3,13 +3,13 @@
using System;
using Tokens;
internal class DctDecodeFilter : IFilter
internal sealed class DctDecodeFilter : IFilter
{
/// <inheritdoc />
public bool IsSupported { get; } = false;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
throw new NotSupportedException("The DST (Discrete Cosine Transform) Filter indicates data is encoded in JPEG format. " +
"This filter is not currently supported but the raw data can be supplied to JPEG supporting libraries.");

View File

@@ -32,7 +32,7 @@
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
var parameters = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);
@@ -52,9 +52,7 @@
var bitsPerComponent = parameters.GetIntOrDefault(NameToken.BitsPerComponent, DefaultBitsPerComponent);
var columns = parameters.GetIntOrDefault(NameToken.Columns, DefaultColumns);
var result = PngPredictor.Decode(decompressed, predictor, colors, bitsPerComponent, columns);
return result;
return PngPredictor.Decode(decompressed, predictor, colors, bitsPerComponent, columns);
}
catch
{
@@ -64,7 +62,7 @@
return bytes;
}
private byte[] Decompress(byte[] input)
private static byte[] Decompress(byte[] input)
{
using (var memoryStream = new MemoryStream(input))
using (var output = new MemoryStream())

View File

@@ -20,6 +20,6 @@
/// <param name="streamDictionary">The dictionary of the <see cref="StreamToken"/> (or other dictionary types, e.g. inline images) containing these bytes.</param>
/// <param name="filterIndex">The position of this filter in the pipeline used to encode data.</param>
/// <returns>The decoded bytes.</returns>
byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex);
ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex);
}
}

View File

@@ -9,7 +9,7 @@
public bool IsSupported { get; } = false;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
throw new NotSupportedException("The JBIG2 Filter for monochrome image data is not currently supported. " +
"Try accessing the raw compressed data directly.");

View File

@@ -3,13 +3,13 @@
using System;
using Tokens;
internal class JpxDecodeFilter : IFilter
internal sealed class JpxDecodeFilter : IFilter
{
/// <inheritdoc />
public bool IsSupported { get; } = false;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
throw new NotSupportedException("The JPX Filter (JPEG2000) for image data is not currently supported. " +
"Try accessing the raw compressed data directly.");

View File

@@ -29,7 +29,7 @@ namespace UglyToad.PdfPig.Filters
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
var parameters = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);
@@ -45,14 +45,10 @@ namespace UglyToad.PdfPig.Filters
var bitsPerComponent = parameters.GetIntOrDefault(NameToken.BitsPerComponent, DefaultBitsPerComponent);
var columns = parameters.GetIntOrDefault(NameToken.Columns, DefaultColumns);
var result = PngPredictor.Decode(decompressed, predictor, colors, bitsPerComponent, columns);
return result;
return PngPredictor.Decode(decompressed, predictor, colors, bitsPerComponent, columns);
}
var data = Decode(input, earlyChange == 1);
return data;
return Decode(input, earlyChange == 1);
}
private static byte[] Decode(ReadOnlySpan<byte> input, bool isEarlyChange)

View File

@@ -17,7 +17,7 @@
public bool IsSupported { get; } = true;
/// <inheritdoc />
public byte[] Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, int filterIndex)
{
using var output = new ArrayPoolBufferWriter<byte>(input.Length);
@@ -63,7 +63,7 @@
}
}
return output.WrittenSpan.ToArray();
return output.WrittenMemory;
}
}
}

View File

@@ -1,10 +1,10 @@
#if NETFRAMEWORK || NETSTANDARD2_0
#if !NET
namespace System.Text;
internal static class EncodingExtensions
{
public static string GetString(this Encoding encoding, ReadOnlySpan<byte> bytes)
internal static string GetString(this Encoding encoding, ReadOnlySpan<byte> bytes)
{
if (bytes.IsEmpty)
{