Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions src/UglyToad.PdfPig.Tests/Filters/Ascii85FilterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,39 @@ public void DecodesWikipediaExample()
text);
}

[Fact]
public void ReplacesZWithEmptyBytes()
[Theory]
[InlineData("BE", "h")]
[InlineData("BOq", "he")]
[InlineData("BOtu", "hel")]
[InlineData("BOu!r", "hell")]
[InlineData("BOu!rDZ", "hello")]
[InlineData("BOu!rD]f", "hello ")]
[InlineData("BOu!rD]j6", "hello w")]
[InlineData("BOu!rD]j7B", "hello wo")]
[InlineData("BOu!rD]j7BEW", "hello wor")]
[InlineData("BOu!rD]j7BEbk", "hello worl")]
[InlineData("BOu!rD]j7BEbo7", "hello world")]
[InlineData("BOu!rD]j7BEbo80", "hello world!")]
public void DecodesHelloWorld(string encoded, string decoded)
{
var bytes = Encoding.ASCII.GetBytes("9jqo^zBlbD-");
var result = filter.Decode(
Encoding.ASCII.GetBytes(encoded),
dictionary,
TestFilterProvider.Instance,
0);

Assert.Equal(decoded, Encoding.ASCII.GetString(result.ToArray()));
}

[Theory]
[InlineData("9jqo^zBlbD-", "Man \0\0\0\0is d")]
[InlineData("", "")]
[InlineData("z", "\0\0\0\0")]
[InlineData("zz", "\0\0\0\0\0\0\0\0")]
[InlineData("zzz", "\0\0\0\0\0\0\0\0\0\0\0\0")]
public void ReplacesZWithEmptyBytes(string encoded, string decoded)
{
var bytes = Encoding.ASCII.GetBytes(encoded);

var result = filter.Decode(bytes, dictionary, TestFilterProvider.Instance, 1);

Expand All @@ -47,7 +76,7 @@ public void ReplacesZWithEmptyBytes()
string text = Encoding.ASCII.GetString(result.Span);
#endif

Assert.Equal("Man \0\0\0\0is d", text);
Assert.Equal(decoded, text);
}

[Fact]
Expand All @@ -60,14 +89,17 @@ public void ZInMiddleOf5CharacterSequenceThrows()
Assert.Throws<InvalidOperationException>(action);
}

[Fact]
public void SingleCharacterLastThrows()
[Theory]
[InlineData("@rH:%B", "cool")]
[InlineData("A~>", "")]
[InlineData("@rH:%A~>", "cool")]
public void SingleCharacterLastIgnores(string encoded, string decoded)
{
var bytes = Encoding.ASCII.GetBytes("9jqo^B");
var bytes = Encoding.ASCII.GetBytes(encoded);

Action action = () => filter.Decode(bytes, dictionary, TestFilterProvider.Instance, 1);
var result = filter.Decode(bytes, dictionary, TestFilterProvider.Instance, 1);

Assert.Throws<ArgumentOutOfRangeException>(action);
Assert.Equal(decoded, Encoding.ASCII.GetString(result.ToArray()));
}

private const string PdfContent = @"1 0 obj
Expand Down
25 changes: 19 additions & 6 deletions src/UglyToad.PdfPig/Filters/Ascii85Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using Core;
using System.Text;
using Tokens;

/// <summary>
Expand All @@ -13,7 +14,7 @@ public sealed class Ascii85Filter : IFilter
private const byte Offset = (byte)'!';
private const byte EmptyCharacterPadding = (byte)'u';

private static ReadOnlySpan<byte> EndOfDataBytes => [(byte)'~', (byte)'>'];
private static ReadOnlySpan<byte> EndOfDataBytes => "~>"u8;

private static readonly int[] PowerByIndex =
[
Expand Down Expand Up @@ -52,7 +53,7 @@ public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary,
{
if (index > 0)
{
WriteData(asciiBuffer, index, writer);
WriteData(asciiBuffer, index, writer, true);
}

index = 0;
Expand Down Expand Up @@ -88,24 +89,36 @@ public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary,

if (index == 5)
{
WriteData(asciiBuffer, index, writer);
WriteData(asciiBuffer, index, writer, false);
index = 0;
}
}

if (index > 0)
{
WriteData(asciiBuffer, index, writer);
WriteData(asciiBuffer, index, writer, true);
}

return writer.WrittenMemory.ToArray();
}

private static void WriteData(Span<byte> ascii, int index, ArrayPoolBufferWriter<byte> writer)
private static void WriteData(
Span<byte> ascii,
int index,
ArrayPoolBufferWriter<byte> writer,
bool isAtEnd)
{
if (index < 2)
{
throw new ArgumentOutOfRangeException(nameof(index), "Cannot convert a block padded by 4 'u' characters.");
if (isAtEnd)
{
return;
}

var bufferTxt = Encoding.ASCII.GetString(ascii);
var soFar = Encoding.ASCII.GetString(writer.GetSpan());
throw new ArgumentOutOfRangeException(nameof(index),
$"Cannot convert a this block because we're not at the end of the stream. Chunk: '{bufferTxt}'. Content: '{soFar}'");
}

// Write any empty padding if the block ended early.
Expand Down
Loading