I have the following native c++ function:
// Decode binary format from file 'filename' into stream 'output'
bool read_private_format(const char * filename, std::ostringstream & output);
Reading previous post on SO on StringBuilder and delegate, I have created an intermediate C function to be exposed to the C# layer as:
extern "C" {
typedef char *(*StringBuilderCallback)(int len);
__attribute__ ((visibility ("default")))
bool c_read_private_format(const char * filename, StringBuilderCallback ensureCapacity, char *out, int len) {
std::ostringstream oss;
if( read_private_format(filename, oss) ) {
const std::string str = oss.str();
if( str.size() > len )
out = ensureCapacity(str.size());
strcpy(out, str.c_str());
return true;
}
return false;
}
}
while on the C# side:
private delegate System.Text.StringBuilder StringBuilderEnsureCapacity(int capacity);
[System.Runtime.InteropServices.DllImport(NativeLibraryName, EntryPoint="c_read_private_format")]
private static extern bool c_read_private_format(string filename, System.IntPtr aCallback, System.Text.StringBuilder data, int size);
private static System.Text.StringBuilder callback(int capacity)
{
buffer.EnsureCapacity( capacity );
return buffer;
}
public static string readIntoString(string filename) {
StringBuilderEnsureCapacity del = new StringBuilderEnsureCapacity(callback);
System.IntPtr ptr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(del)
if( c_read_private_format( ptr, buffer, buffer.Capacity ) ) {
string str = buffer.ToString();
return str;
}
return null;
}
For some reason this is not working as expected, when printing the adress of the char*
as returned by callback
it acts as if the pointer returned was the one before the call to EnsureCapacity
(I can verify by doing a second call, in which case the char*
in the C layer is different).
My questions is:
- How can I efficiently retrieve a UTF-8 string from C in .NET SDK (5.0.202) ?
I do not know in advance how long the string will be. Technically I could overestimate the StringBuilder Capacity so that I can re-use across my files, but it feels as if there could a better approach to passing a growing stream to the c layer.