2012-05-27 8 views
5

Creé esos dos métodos para convertir cadenas utf-8 nativas (char *) en cadenas administradas y viceversa. El siguiente código hace el trabajo:Conversión en .net: Nativo Utf-8 <-> Cadena administrada

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

Mientras NativeUtf8FromString está bien, StringFromNativeUtf8 es un desastre, pero el único código de seguridad que pudiera llegar a funcionar. Usando un código inseguro podría usar un byte * pero no quiero un código inseguro. ¿Hay alguna otra forma en que alguien pueda pensar que no tengo que copiar la cadena por cada byte contenido para encontrar la terminación 0?


simplemente agrego el código unsave aquí:

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

Como se puede ver que no es fea sólo tiene inseguro.

+1

¿Por qué te preocupa no utilizar el código 'inseguro'? – CodesInChaos

+0

@CodelnChaos: No estoy seguro. Porque Procect tiene que activar el interruptor/inseguro que me parece sucio. – Totonga

+1

El interruptor '/ inseguro' no tiene sentido. 'Marshal. *' Es tan inseguro como el código del puntero, incluso si no requiere el cambio. – CodesInChaos

Respuesta

19

Simplemente realice exactamente la misma operación que strlen() realiza. Considere mantener el buffer , el código genera basura a toda prisa.

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 = new byte [len - 1]; debe ser byte [] buffer = new byte [len]; – Jaska

+0

Pero su código incluye incluir todo hasta (pero sin incluir) el terminador nulo. Así que Len contiene la cantidad de caracteres sin terminador nulo. – Jaska

+0

Podría haber jurado que probé esto. Los insectos desaprovechados chupan. Gracias. –

Cuestiones relacionadas