Skip to content

CSharp bindings: user-defined string encoding and improved safety#14366

Open
Mbucari wants to merge 7 commits intoOSGeo:masterfrom
Mbucari:master
Open

CSharp bindings: user-defined string encoding and improved safety#14366
Mbucari wants to merge 7 commits intoOSGeo:masterfrom
Mbucari:master

Conversation

@Mbucari
Copy link
Copy Markdown
Contributor

@Mbucari Mbucari commented Apr 15, 2026

What does this PR do?

Creates an interface for users to create custom string Encoder/Decoders for Gdal to use for all string operations. This serves a purpose similar to #3825 by allowing users to manage how strings are encoded/decoded to/from Gdal.

Expose $module.IStringEncoder interfaces which have 2 methods:

  • string FromNullTerminated(IntPtr pStr); - Read native null-terminated data from a Gdal pointer and return a managed string.
  • byte[] ToNullTerminated(string str); - Create a null-terminated array of bytes from a managed string to send to Gdal.

It also simplifies string marshalling changes made in recent PR by no longer requires C# to allocate/free any unmanaged memory. All string/byte[] objects are managed.


Here's an example of a custom StringEncoder.

class CustomGdalEncoder : OSGeo.GDAL.Gdal.IStringEncoder, OSGeo.OGR.Ogr.IStringEncoder, OSGeo.OSR.Osr.IStringEncoder
{
    public string FromNullTerminated(IntPtr pStr)
      => Marshal.PtrToStringUTF8(pStr);

    public byte[] ToNullTerminated(string str)
    {
        if (str == null)
            return null;
        int byteCount = Encoding.UTF8.GetByteCount(str);
        var bts = new byte[byteCount + 1];
        Encoding.UTF8.GetBytes(str, 0, str.Length, bts, 0);
        return bts;
    }
}
var encoder = new CustomGdalEncoder();
OSGeo.GDAL.Gdal.StringEncoder = encoder;
OSGeo.OGR.Ogr.StringEncoder = encoder;
OSGeo.OSR.Osr.StringEncoder = encoder;

@runette

What are related issues/pull requests?

#3825
#14283

Tasklist

  • Make sure code is correctly formatted
  • Review
  • Adjust for comments

Environment

Provide environment details, if relevant:
Mono and dotnet

Expose $module.IStringMarshaller interfaces which have 2 methods:
 - `string FromNullTerminated(IntPtr pStr)` - Read native null-terminated data from a Gdal pointer and return a managed string.
 - `byte[] ToNullTerminated(string str)` - Create a null-terminated array of bytes from a managed string to send to Gdal.

Public static properties `$module.StringMarshaller` can be used to get/set a custom marshaller interfaces. The default marshaller is internal `DefaultStringMarshaller`.

String helper callback has been changed.
When `SWIG_csharp_string_callback` is called, it decodes the unmanaged Gdal string to a managed .NET string (using StringMarshaller.ToNullTerminated()) and then returns a pointer to a pinned GCHandle of that string. StringFromPinnedGCHandle() is called from the C# methods to retrieve the string and free the GCHandle.
@runette
Copy link
Copy Markdown
Contributor

runette commented Apr 15, 2026

It is probably going to be next week before I can look at this

@Mbucari Mbucari marked this pull request as draft April 15, 2026 16:14
@Mbucari Mbucari changed the title CSharp bindings: user-defined string marshalling and improved safety CSharp bindings: user-defined string encoding and improved safety Apr 15, 2026
@Mbucari Mbucari marked this pull request as ready for review April 15, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants