Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] CoreGraphics convert strings in pinvokes #17135

Merged
merged 2 commits into from
Jan 6, 2023
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
21 changes: 13 additions & 8 deletions src/CoreGraphics/CGContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ public void SetFontSize (nfloat size)
#endif
[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGContextSelectFont (/* CGContextRef */ IntPtr c,
/* const char* __nullable */ string? name, /* CGFloat */ nfloat size, CGTextEncoding textEncoding);
/* const char* __nullable */ IntPtr name, /* CGFloat */ nfloat size, CGTextEncoding textEncoding);

#if NET
[SupportedOSPlatform ("ios")]
Expand All @@ -875,7 +875,8 @@ extern static void CGContextSelectFont (/* CGContextRef */ IntPtr c,
#endif
public void SelectFont (string? name, nfloat size, CGTextEncoding textEncoding)
{
CGContextSelectFont (Handle, name, size, textEncoding);
using var namePtr = new TransientString (name);
CGContextSelectFont (Handle, namePtr, size, textEncoding);
}

[DllImport (Constants.CoreGraphicsLibrary)]
Expand Down Expand Up @@ -904,7 +905,7 @@ public void ShowGlyphsAtPositions (ushort []? glyphs, CGPoint []? positions, int
[Deprecated (PlatformName.MacOSX, 10, 9)]
#endif
[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGContextShowText (/* CGContextRef */ IntPtr c, /* const char* __nullable */ string? s, /* size_t */ nint length);
extern static void CGContextShowText (/* CGContextRef */ IntPtr c, /* const char* __nullable */ IntPtr s, /* size_t */ nint length);

#if NET
[SupportedOSPlatform ("ios")]
Expand All @@ -923,7 +924,8 @@ public void ShowText (string? str, int count)
count = 0;
else if (count > str.Length)
throw new ArgumentException (nameof (count));
CGContextShowText (Handle, str, count);
using var strPtr = new TransientString (str);
CGContextShowText (Handle, strPtr, count);
}

#if NET
Expand All @@ -939,7 +941,8 @@ public void ShowText (string? str, int count)
#endif
public void ShowText (string? str)
{
CGContextShowText (Handle, str, str is null ? 0 : str.Length);
using var strPtr = new TransientString (str);
CGContextShowText (Handle, strPtr, str is null ? 0 : str.Length);
}

#if NET
Expand Down Expand Up @@ -1005,7 +1008,7 @@ public void ShowText (byte []? bytes)
#endif
[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGContextShowTextAtPoint (/* CGContextRef __nullable */ IntPtr c, /* CGFloat */ nfloat x,
/* CGFloat */ nfloat y, /* const char* __nullable */ string? str, /* size_t */ nint length);
/* CGFloat */ nfloat y, /* const char* __nullable */ IntPtr str, /* size_t */ nint length);

#if NET
[SupportedOSPlatform ("ios")]
Expand All @@ -1020,7 +1023,8 @@ extern static void CGContextShowTextAtPoint (/* CGContextRef __nullable */ IntPt
#endif
public void ShowTextAtPoint (nfloat x, nfloat y, string? str, int length)
{
CGContextShowTextAtPoint (Handle, x, y, str, length);
using var strPtr = new TransientString (str);
CGContextShowTextAtPoint (Handle, x, y, strPtr, length);
}

#if NET
Expand All @@ -1036,7 +1040,8 @@ public void ShowTextAtPoint (nfloat x, nfloat y, string? str, int length)
#endif
public void ShowTextAtPoint (nfloat x, nfloat y, string? str)
{
CGContextShowTextAtPoint (Handle, x, y, str, str is null ? 0 : str.Length);
using var strPtr = new TransientString (str);
CGContextShowTextAtPoint (Handle, x, y, strPtr, str is null ? 0 : str.Length);
}

#if NET
Expand Down
8 changes: 5 additions & 3 deletions src/CoreGraphics/CGDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,15 @@ protected internal override void Release ()

#if !COREBUILD
[DllImport (Constants.CoreGraphicsLibrary)]
extern static /* CGDataProviderRef */ IntPtr CGDataProviderCreateWithFilename (/* const char* */ string filename);
extern static /* CGDataProviderRef */ IntPtr CGDataProviderCreateWithFilename (/* const char* */ IntPtr filename);

static public CGDataProvider? FromFile (string file)
{
if (file is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (file));

var handle = CGDataProviderCreateWithFilename (file);
using var filePtr = new TransientString (file);
var handle = CGDataProviderCreateWithFilename (filePtr);
if (handle == IntPtr.Zero)
return null;

Expand All @@ -101,7 +102,8 @@ static IntPtr Create (string file)
if (file is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (file));

var handle = CGDataProviderCreateWithFilename (file);
using var filePtr = new TransientString (file);
var handle = CGDataProviderCreateWithFilename (filePtr);
if (handle == IntPtr.Zero)
throw new ArgumentException ("Could not create provider from the specified file");
return handle;
Expand Down
6 changes: 4 additions & 2 deletions src/CoreGraphics/CGPDFContentStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ protected internal override void Release ()
}

[DllImport (Constants.CoreGraphicsLibrary)]
extern static /* CGPDFObjectRef */ IntPtr CGPDFContentStreamGetResource (/* CGPDFContentStreamRef */ IntPtr cs, /* const char* */ string category, /* const char* */ string name);
extern static /* CGPDFObjectRef */ IntPtr CGPDFContentStreamGetResource (/* CGPDFContentStreamRef */ IntPtr cs, /* const char* */ IntPtr category, /* const char* */ IntPtr name);

public CGPDFObject? GetResource (string category, string name)
{
Expand All @@ -104,7 +104,9 @@ protected internal override void Release ()
if (name is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (name));

var h = CGPDFContentStreamGetResource (Handle, category, name);
using var categoryPtr = new TransientString (category);
using var namePtr = new TransientString (name);
var h = CGPDFContentStreamGetResource (Handle, categoryPtr, namePtr);
return (h == IntPtr.Zero) ? null : new CGPDFObject (h);
}
}
Expand Down
45 changes: 29 additions & 16 deletions src/CoreGraphics/CGPDFDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,89 +78,100 @@ public int Count {

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetBoolean (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFBoolean* */ [MarshalAs (UnmanagedType.I1)] out bool value);
extern static bool CGPDFDictionaryGetBoolean (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFBoolean* */ [MarshalAs (UnmanagedType.I1)] out bool value);

public bool GetBoolean (string key, out bool result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
return CGPDFDictionaryGetBoolean (Handle, key, out result);
using var keyPtr = new TransientString (key);
return CGPDFDictionaryGetBoolean (Handle, keyPtr, out result);
}

// CGPDFInteger -> long int so 32/64 bits -> CGPDFObject.h

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetInteger (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFInteger* */ out nint value);
extern static bool CGPDFDictionaryGetInteger (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFInteger* */ out nint value);

public bool GetInt (string key, out nint result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
return CGPDFDictionaryGetInteger (Handle, key, out result);
using var keyPtr = new TransientString (key);
return CGPDFDictionaryGetInteger (Handle, keyPtr, out result);
}

// CGPDFReal -> CGFloat -> CGPDFObject.h

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetNumber (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFReal* */ out nfloat value);
extern static bool CGPDFDictionaryGetNumber (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFReal* */ out nfloat value);

public bool GetFloat (string key, out nfloat result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
return CGPDFDictionaryGetNumber (Handle, key, out result);

using var keyPtr = new TransientString (key);
return CGPDFDictionaryGetNumber (Handle, keyPtr, out result);
}

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetName (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* const char ** */ out IntPtr value);
extern static bool CGPDFDictionaryGetName (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* const char ** */ out IntPtr value);

public bool GetName (string key, out string? result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
var r = CGPDFDictionaryGetName (Handle, key, out var res);
using var keyPtr = new TransientString (key);
var r = CGPDFDictionaryGetName (Handle, keyPtr, out var res);
result = r ? Marshal.PtrToStringAnsi (res) : null;
return r;
}

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetDictionary (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFDictionaryRef* */ out IntPtr result);
extern static bool CGPDFDictionaryGetDictionary (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFDictionaryRef* */ out IntPtr result);

public bool GetDictionary (string key, out CGPDFDictionary? result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
var r = CGPDFDictionaryGetDictionary (Handle, key, out var res);

using var keyPtr = new TransientString (key);
var r = CGPDFDictionaryGetDictionary (Handle, keyPtr, out var res);
result = r ? new CGPDFDictionary (res) : null;
return r;
}

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetStream (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFStreamRef* */ out IntPtr value);
extern static bool CGPDFDictionaryGetStream (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFStreamRef* */ out IntPtr value);

public bool GetStream (string key, out CGPDFStream? result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
var r = CGPDFDictionaryGetStream (Handle, key, out var ptr);

using var keyPtr = new TransientString (key);
var r = CGPDFDictionaryGetStream (Handle, keyPtr, out var ptr);
result = r ? new CGPDFStream (ptr) : null;
return r;
}

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetArray (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFArrayRef* */ out IntPtr value);
extern static bool CGPDFDictionaryGetArray (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFArrayRef* */ out IntPtr value);

public bool GetArray (string key, out CGPDFArray? array)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
var r = CGPDFDictionaryGetArray (Handle, key, out var ptr);

using var keyPtr = new TransientString (key);
var r = CGPDFDictionaryGetArray (Handle, keyPtr, out var ptr);
array = r ? new CGPDFArray (ptr) : null;
return r;
}
Expand Down Expand Up @@ -246,13 +257,15 @@ public void Apply (Action<string?, CGPDFObject> callback)

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDictionaryGetString (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ string key, /* CGPDFStringRef* */ out IntPtr value);
extern static bool CGPDFDictionaryGetString (/* CGPDFDictionaryRef */ IntPtr dict, /* const char* */ IntPtr key, /* CGPDFStringRef* */ out IntPtr value);

public bool GetString (string key, out string? result)
{
if (key is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key));
var r = CGPDFDictionaryGetString (Handle, key, out var res);

using var keyPtr = new TransientString (key);
var r = CGPDFDictionaryGetString (Handle, keyPtr, out var res);
result = r ? CGPDFString.ToString (res) : null;
return r;
}
Expand Down
5 changes: 3 additions & 2 deletions src/CoreGraphics/CGPDFDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,12 @@ public bool IsEncrypted {

[DllImport (Constants.CoreGraphicsLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool CGPDFDocumentUnlockWithPassword (/* CGPDFDocumentRef */ IntPtr document, /* const char* */ string password);
extern static bool CGPDFDocumentUnlockWithPassword (/* CGPDFDocumentRef */ IntPtr document, /* const char* */ IntPtr password);

public bool Unlock (string password)
{
return CGPDFDocumentUnlockWithPassword (Handle, password);
using var passwordPtr = new TransientString (password);
return CGPDFDocumentUnlockWithPassword (Handle, passwordPtr);
}

[DllImport (Constants.CoreGraphicsLibrary)]
Expand Down
17 changes: 10 additions & 7 deletions src/CoreGraphics/CGPDFOperatorTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,33 +76,34 @@ protected internal override void Release ()
// We need this P/Invoke for legacy AOT scenarios (since we have public API taking a 'Action<IntPtr, IntPtr>', and with this particular native function we can't wrap the delegate)
// Unfortunately CoreCLR doesn't support generic Action delegates in P/Invokes: https://github.com/dotnet/runtime/issues/32963
[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ string name, /* CGPDFOperatorCallback */ Action<IntPtr, IntPtr>? callback);
extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ IntPtr name, /* CGPDFOperatorCallback */ Action<IntPtr, IntPtr>? callback);
#endif

#if NET
// This signature requires C# 9 (so .NET only).
// The good part about this signature is that it enforces at compile time that 'callback' is callable from native code in a FullAOT scenario.
// The bad part is that it's unsafe code (and callers must be in unsafe mode as well).
[DllImport (Constants.CoreGraphicsLibrary)]
unsafe extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ string name, /* CGPDFOperatorCallback */ delegate* unmanaged<IntPtr, IntPtr, void> callback);
unsafe extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ IntPtr name, /* CGPDFOperatorCallback */ delegate* unmanaged<IntPtr, IntPtr, void> callback);
#endif

#if MONOMAC && !NET
// This signature can work everywhere, but we can't enforce at compile time that 'callback' is a delegate to a static function (which is required for FullAOT scenarios),
// so limit it to non-FullAOT platforms (macOS)
[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ string name, /* CGPDFOperatorCallback */ CGPDFOperatorCallback? callback);
extern static void CGPDFOperatorTableSetCallback (/* CGPDFOperatorTableRef */ IntPtr table, /* const char */ IntPtr name, /* CGPDFOperatorCallback */ CGPDFOperatorCallback? callback);

// this won't work with AOT since the callback must be decorated with [MonoPInvokeCallback]
public void SetCallback (string name, Action<CGPDFScanner?,object?>? callback)
{
if (name is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (name));

using var namePtr = new TransientString (name);
if (callback is null)
CGPDFOperatorTableSetCallback (Handle, name, (CGPDFOperatorCallback?) null);
CGPDFOperatorTableSetCallback (Handle, namePtr, (CGPDFOperatorCallback?) null);
else
CGPDFOperatorTableSetCallback (Handle, name, new CGPDFOperatorCallback (delegate (IntPtr reserved, IntPtr gchandle) {
CGPDFOperatorTableSetCallback (Handle, namePtr, new CGPDFOperatorCallback (delegate (IntPtr reserved, IntPtr gchandle) {
// we could do 'new CGPDFScanner (reserved, true)' but we would not get `UserInfo` (managed state) back
// we could GCHandle `userInfo` but that would (even more) diverge both code bases :(
var scanner = GetScannerFromInfo (gchandle);
Expand All @@ -120,7 +121,8 @@ public void SetCallback (string name, Action<IntPtr, IntPtr>? callback)
if (name is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (name));

CGPDFOperatorTableSetCallback (Handle, name, callback);
using var namePtr = new TransientString (name);
CGPDFOperatorTableSetCallback (Handle, namePtr, callback);
}
#endif // !NET

Expand All @@ -131,7 +133,8 @@ public unsafe void SetCallback (string name, delegate* unmanaged<IntPtr, IntPtr,
if (name is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (name));

CGPDFOperatorTableSetCallback (Handle, name, callback);
using var namePtr = new TransientString (name);
CGPDFOperatorTableSetCallback (Handle, namePtr, callback);
}
#endif

Expand Down