Skip to content
Open
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
20 changes: 17 additions & 3 deletions src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,16 +553,30 @@ bool TryReadEndStream(PdfDictionary dict, SizeType streamStart, ref int streamLe
var oldLength = streamLength;
//_lexer.DetermineStreamLength(dict.Reference!.Position, streamLength - length, ref streamLength);

// Try to read 20 extra bytes in case reported stream length is too small.
int scanWindow = streamLength + 20;
// If this mismatch is larger than a few bytes, search up to the next object (or EOF).
// This keeps valid files fast and improves robustness for malformed /Length values.
var behindPosition = _document.IrefTable.GetPositionOfObjectBehind(dict, streamStart);
int scanWindow;
if (behindPosition != -1)
{
// Read up to next object.
scanWindow = (int)(behindPosition - streamStart);
}
else
{
// Object is the last one in the file, so read up to EOF.
scanWindow = (int)(_lexer.PdfLength - streamStart);
}

// Make sure we do not try to read beyond EOF.
if (streamStart + scanWindow > _lexer.PdfLength)
{
// We're close to the EOF, so casting to int is OK here.
scanWindow = (int)(_lexer.PdfLength - streamStart);
Debug.Assert(scanWindow >= oldLength);
}

Debug.Assert(scanWindow >= oldLength);

streamLength = _lexer.DetermineStreamLength(streamStart, scanWindow, suppressObjectOrderExceptions);
if (SuppressExceptions.HasError(suppressObjectOrderExceptions))
return false;
Expand Down
27 changes: 27 additions & 0 deletions src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/ReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
using Xunit;
using FluentAssertions;
using PdfSharp.Diagnostics;
using System.Runtime.CompilerServices;
using static System.Net.Mime.MediaTypeNames;
using System.Text;

#if PDFSHARP_DEBUG
using static PdfSharp.Diagnostics.DebugBreakHelper;
Expand Down Expand Up @@ -567,5 +570,29 @@ static void DrawFooter(PdfPage page, XBrush color, XRect box, string footer)
gfx.DrawString(footer, font, color, box, format);
}
}

[Fact]
public async Task Read_FileWithInvalidStreamLengths_Success()
{
var doc = new PdfDocument();
var page = doc.AddPage();
using var gfx = XGraphics.FromPdfPage(page);

var font = new XFont(UnitTestFontResolver.ArialFont, 20, XFontStyleEx.Regular);

gfx.DrawString(string.Concat(Enumerable.Repeat("Hello World!", 30)), font, XBrushes.Black, new XPoint(100, 100));

using var stream = new MemoryStream();
await doc.SaveAsync(stream, false);

using StreamReader reader = new StreamReader(stream, PdfSharp.Pdf.Internal.PdfEncoders.RawEncoding);
var fullFile = await reader.ReadToEndAsync();
var invalidLengthFile = fullFile.Replace("/Length 417", "/Length 317");
fullFile.Should().NotBe(invalidLengthFile);
MemoryStream newStream = new MemoryStream(PdfSharp.Pdf.Internal.PdfEncoders.RawEncoding.GetBytes(invalidLengthFile));

var doc2 = PdfReader.Open(newStream, PdfDocumentOpenMode.Import);
doc2.Should().NotBeNull();
}
}
}