2012-05-27 8 views
5

Ich habe diese beiden Methoden erstellt, um native utf-8 Zeichenfolgen (char *) in eine verwaltete Zeichenfolge umzuwandeln und umgekehrt. Der folgende Code macht den Job:Konvertierung in .net: Native Utf-8 <-> Verwaltete Zeichenfolge

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); 
} 

Während NativeUtf8FromString ok ist, StringFromNativeUtf8 ein Chaos ist aber der einzige sichere Code, den ich laufen konnte. Mit unsicherem Code könnte ich ein Byte * verwenden, aber ich möchte keinen unsicheren Code. Gibt es eine andere Möglichkeit, an die jemand denken kann, wo ich die Zeichenfolge für jedes enthaltene Byte nicht kopieren muss, um die 0-Beendigung zu finden.


ich fügen Sie einfach den Code unsave hier:

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); 
} 

Wie Sie es nicht hässlich sehen nur unsicher braucht.

+1

Warum kümmern Sie sich nicht um 'unsicheren' Code? – CodesInChaos

+0

@CodelnChaos: Nicht sicher. Weil Procect den/unsafe-Schalter aktivieren muss, der sich für mich schmutzig anfühlt. – Totonga

+1

Der '/ unsafe' Schalter ist ziemlich bedeutungslos. 'Marshal. *' Ist genauso unsicher wie ein Zeigercode, auch wenn der Schalter nicht benötigt wird. – CodesInChaos

Antwort

19

Führen Sie genau die gleiche Operation Strlen() führt. Denken Sie daran, die Puffer herum zu halten, der Code erzeugt Müll in Eile.

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); 
    } 
+0

byte [] buffer = neues Byte [len - 1]; sollte sein byte [] buffer = neues byte [len]; – Jaska

+0

Aber Ihr Code enthält alle bis zu (aber nicht einschließlich) Null-Terminator. So enthält len ​​die Anzahl der Zeichen ohne Nullterminator. – Jaska

+0

Ich hätte schwören können, dass ich das getestet habe. Off-by-One Bugs saugen. Vielen Dank. –