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
5 changes: 2 additions & 3 deletions PDFiumSharp/PDFium.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,13 @@ public static FPDF_DOCUMENT FPDF_LoadDocument(byte[] data, int index = 0, int co
/// <summary>
/// Loads a PDF document from '<paramref name="count" />' bytes read from a stream.
/// </summary>
/// <param name="fileRead"></param>
/// <param name="count">
/// The number of bytes to read from the <paramref name="stream" />.
/// If the value is equal to or smaller than 0, the stream is read to the end.
/// </param>
/// <param name="stream"></param>
/// <param name="fileRead">The FILEREAD structure ready for reading.</param>
/// <param name="password">Pdf password</param>
public static FPDF_DOCUMENT FPDF_LoadDocument(Stream stream, FPDF_FILEREAD fileRead, int count = 0, string password = null)
public static FPDF_DOCUMENT FPDF_LoadDocument(FPDF_FILEREAD fileRead, string password = null)
=> FPDF_LoadCustomDocument(fileRead, password);

//public static string FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, string key)
Expand Down
22 changes: 17 additions & 5 deletions PDFiumSharp/PdfDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public sealed class PdfDocument : NativeWrapper<FPDF_DOCUMENT>
private FPDF_FORMFILLINFO formCallbacks;

private GCHandle formCallbacksHandle;

private FPDF_FILEREAD fileRead;

private FPDF_FORMHANDLE form;

Expand Down Expand Up @@ -138,15 +140,23 @@ public PdfDocument(byte[] data, int index = 0, int count = -1, string password =
/// Loads a <see cref="PdfDocument"/> from '<paramref name="count"/>' bytes read from a <paramref name="stream"/>.
/// <see cref="Close"/> must be called in order to free unmanaged resources.
/// </summary>
/// <param name="stream"></param>
/// <param name="fileRead"></param>
/// <param name="data">Stream containing the bytes of the PDF document to load. Must remain open and accessible as long as the document is being used.</param>
/// <param name="count">
/// The number of bytes to read from the <paramref name="stream"/>.
/// If the value is equal to or smaller than 0, the stream is read to the end.
/// </param>
/// <param name="password"></param>
public PdfDocument(Stream stream, FPDF_FILEREAD fileRead, int count = 0, string password = null)
: this(PDFium.FPDF_LoadDocument(stream, fileRead, count, password)) { }
/// <param name="password">Password.</param>
public PdfDocument(Stream stream, int count = 0, string password = null)
: this(FPDF_FILEREAD.FromStream(stream, count), password) { }

/// <summary>
/// Private overload which keeps the FILEREAD reference so that the delegate and its callback stub remain valid for the lifetime of the document.
/// </summary>
private PdfDocument(FPDF_FILEREAD fileRead, string password)
: this(PDFium.FPDF_LoadDocument(fileRead, password))
{
this.fileRead = fileRead;
}

/// <summary>
/// Closes the <see cref="PdfDocument"/> and frees unmanaged resources.
Expand Down Expand Up @@ -209,6 +219,8 @@ protected override void Dispose(FPDF_DOCUMENT handle)

((IDisposable)this.Pages).Dispose();
PDFium.FPDF_CloseDocument(handle);

this.fileRead = null;
}
}
}
51 changes: 37 additions & 14 deletions PDFiumSharp/Types/FPDF_FILEACCESS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
namespace PDFiumSharp.Types
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool FileReadBlockHandler(IntPtr ignore, int position, IntPtr buffer, int size);
public delegate bool FileReadBlockHandler(IntPtr param, int position, IntPtr buffer, int size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool FileWriteBlockHandler(IntPtr ignore, IntPtr data, int size);
public delegate bool FileWriteBlockHandler(IntPtr self, IntPtr data, int size);

[StructLayout(LayoutKind.Sequential)]
public class FPDF_FILEREAD
Expand All @@ -26,29 +26,52 @@ public class FPDF_FILEREAD

readonly IntPtr _param;

public FPDF_FILEREAD(int fileLength, FileReadBlockHandler readBlock)
public FPDF_FILEREAD(int fileLength, FileReadBlockHandler readBlock, IntPtr param = default)
{
_fileLength = fileLength;
_readBlock = readBlock;
_param = IntPtr.Zero;
_param = param;
}

public static FPDF_FILEREAD FromStream(Stream stream, int count = 0)
{
if (count <= 0)
count = (int)(stream.Length - stream.Position);
var start = stream.Position;

var memoryStream = stream as MemoryStream;
if (memoryStream != null) {
try {
memoryStream.GetBuffer();
} catch (UnauthorizedAccessException) {
// Buffer is not public, and thus not directly usable
memoryStream = null;
}
}

byte[] data = null;
FPDF_FILEREAD fileRead = new FPDF_FILEREAD(count, (ignore, position, buffer, size) =>
{
stream.Position = start + position;
if (data == null || data.Length < size)
data = new byte[size];
if (stream.Read(data, 0, size) != size)
return false;
Marshal.Copy(data, 0, buffer, size);
return true;
});
FPDF_FILEREAD fileRead = memoryStream != null
? new FPDF_FILEREAD(count, (_, position, buffer, size) =>
{
if (position < 0 || size <= 0 || start+position+size > memoryStream.Length)
return false;
var streamBuffer = memoryStream.GetBuffer();
Marshal.Copy(streamBuffer, (int)start+position, buffer, size);
return true;
})
: new FPDF_FILEREAD(count, (_, position, buffer, size) =>
{
if (position < 0 || size <= 0)
return false;
stream.Seek(start + position, SeekOrigin.Begin);
if (data == null || data.Length < size)
data = new byte[size];
if (stream.Read(data, 0, size) != size)
return false;

Marshal.Copy(data, 0, buffer, size);
return true;
});
return fileRead;
}
}
Expand Down