Convert to .net: Native Utf-8 & # 8596; Managed string

I created these two methods to convert Native utf-8 strings (char *) to a managed string and vice versa. The following code does the job:

public IntPtr NativeUtf8FromString(string managedString) { byte[] buffer = Encoding.UTF8.GetBytes(managedString); // not null terminated Array.Resize(ref buffer, buffer.Length + 1); buffer[buffer.Length - 1] = 0; // terminating 0 IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length); return nativeUtf8; } string StringFromNativeUtf8(IntPtr nativeUtf8) { int size = 0; byte[] buffer = {}; do { ++size; Array.Resize(ref buffer, size); Marshal.Copy(nativeUtf8, buffer, 0, size); } while (buffer[size - 1] != 0); // till 0 termination found if (1 == size) { return ""; // empty string } Array.Resize(ref buffer, size - 1); // remove terminating 0 return Encoding.UTF8.GetString(buffer); } 

While NativeUtf8FromString is fine, StringFromNativeUtf8 is a mess, but the only safe code I could run. Using unsafe code, I could use byte *, but I don't want unsafe code. Is there any other way that someone might think about where I don't need to copy a string for each byte contained in order to find the completion 0.


I just add insecure code here:

 public unsafe string StringFromNativeUtf8(IntPtr nativeUtf8) { byte* bytes = (byte*)nativeUtf8.ToPointer(); int size = 0; while (bytes[size] != 0) { ++size; } byte[] buffer = new byte[size]; Marshal.Copy((IntPtr)nativeUtf8, buffer, 0, size); return Encoding.UTF8.GetString(buffer); } 

As you can see, its not ugly just unsafe.

+10
source share
2 answers

Just do the same operation as strlen () operation. Think about keeping a buffer around, the code really speeds up garbage collection.

  public static IntPtr NativeUtf8FromString(string managedString) { int len = Encoding.UTF8.GetByteCount(managedString); byte[] buffer = new byte[len + 1]; Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0); IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length); return nativeUtf8; } public static string StringFromNativeUtf8(IntPtr nativeUtf8) { int len = 0; while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len; byte[] buffer = new byte[len]; Marshal.Copy(nativeUtf8, buffer, 0, buffer.Length); return Encoding.UTF8.GetString(buffer); } 
+29
source

A little faster than the Hans solution (1 less buffer):

 private unsafe IntPtr AllocConvertManagedStringToNativeUtf8(string input) { fixed (char* pInput = input) { var len = Encoding.UTF8.GetByteCount(pInput, input.Length); var pResult = (byte*)Marshal.AllocHGlobal(len + 1).ToPointer(); var bytesWritten = Encoding.UTF8.GetBytes(pInput, input.Length, pResult, len); Trace.Assert(len == bytesWritten); pResult[len] = 0; return (IntPtr)pResult; } } private unsafe string MarshalNativeUtf8ToManagedString(IntPtr pStringUtf8) => MarshalNativeUtf8ToManagedString((byte*)pStringUtf8); private unsafe string MarshalNativeUtf8ToManagedString(byte* pStringUtf8) { var len = 0; while (pStringUtf8[len] != 0) len++; return Encoding.UTF8.GetString(pStringUtf8, len); } 

Here I demonstrated the sequence of actions:

 var input = "Hello, World!"; var native = AllocConvertManagedStringToNativeUtf8(input); var copy = MarshalNativeUtf8ToManagedString(native); Marshal.FreeHGlobal(native); // don't leak unmanaged memory! Trace.Assert(input == copy); // prove they're equal! 
0
source

Source: https://habr.com/ru/post/916781/


All Articles