2015-02-17 23 views
11

Otrzymuję tablicę bajtów z gniazda, a struktura bajtów to po prostu duża tablica znaków o stałej szerokości. W niektórych przypadkach ostatnie pole jest dynamiczne (zamiast stałej długości) i próbuję Marshal bajtów do struct. Czytałem, że tablica znaków o zmiennej długości musi być typu IntPtr, ale nie wymyśliłem, jak go marszować z pozostałymi bajtami. W niektórych artykułach przeczytałem też, że potrzebuję drugiej struktury, ale nadal nie mogę wymyślić, jak ją poprawnie sformułować.bajt [] tablica do struct z tablicą o zmiennej długości

Oto jeden z takich site

Jaka jest właściwa droga do czynienia z zmiennej długości tablic char w elemencie?

Struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct Header 
{ 
    #region private member fields 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f1; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f2; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f3; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f4; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f5; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f6; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 
    private char[] _f7; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] 
    private char[] _f8; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    private char[] _f9; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f10; 

    // how would this get filled with a char[] array from the byte array? 
    public IntPtr VariableLengthData; 

    #endregion 
} 

Funkcja:

public static Header FromArray(byte[] array) 
{ 
    IntPtr buff = IntPtr.Zero; 

    try 
    { 
     int objsize = Marshal.SizeOf(typeof(Header)); 
     buff = Marshal.AllocHGlobal(objsize); 
     Marshal.Copy(array, 0, buff, objsize); 
     var result = (Header)Marshal.PtrToStructure(buff, typeof(HostHeader)); 

     // the variable length data needs to be filled in somehow 
     // but also note that an extra 4 bytes was added to the size 
     // of the struct with the IntPtr 
     if(objsize < array.Length) 
     { 
      Marshal.Copy(array, array.Length - objsize, result.VariableLengthData, array.Length - objsize); 
     } 

     return result; 
    } 
    finally 
    { 
     if (buff != IntPtr.Zero) 
     { 
      Marshal.FreeHGlobal(buff); 
      buff = IntPtr.Zero; 
     } 
    } 
} 

To działa - ale teraz Marshal.SizeOf (headerObj) mówi, że jest mniejszy niż jest w rzeczywistości, gdy próbuję przekonwertować go z powrotem do tablica bajtów []. Poza tym, coś nie tak z tym rozwiązaniem?

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct Header 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field1; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field2; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field3; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
    public char[] Field4; 
} 

public static Header DeserializeHeader(byte[] data) 
{ 
    int objsize = Marshal.SizeOf(typeof(Header)); 
    IntPtr buff = Marshal.AllocHGlobal(objsize); 
    Marshal.Copy(data, 0, buff, objsize); 
    var header = (Header)Marshal.PtrToStructure(buff, typeof(Header)); 
    Marshal.FreeHGlobal(buff); 

    // resize Field4 to hold all the remaining bytes 
    if(objsize < data.Length) 
    { 
     header.Field4 = Encoding.ASCII.GetChars(data, objsize - header.Field4.Length, data.Length - objsize - header.Field4.Length); 
    } 
    return header; 
} 
+0

Powinieneś przeformułować i zadać prawdziwe pytanie. –

+0

array + 160 to pozostałe dane. 'Encoding.ASCII.GetString (array, 160, array.Length-160)' – EZI

+0

@EZI - zgadza się. Jeśli tablica bajtów jest większa niż 160, wszystko inne jest polem o zmiennej długości. –

Odpowiedz

10

Po prostu nie próbuj zbyt mocno, aby twoje deklaracje C# dokładnie pasowały do ​​formatu pakietu. Sprzyjałbyś temu:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public class Header { 
    //.... 
} 

public class Packet { 
    public Header Header; 
    public byte[] VariableLengthData; 
} 

Teraz staje się proste. Można zebrać nagłówka za jednym zamachem i po prostu skopiować cokolwiek extra bajty są obecne:

static unsafe Packet FromArray(byte[] data) { 
    var hdrsize = Marshal.SizeOf(typeof(Header)); 
    if (data.Length < hdrsize) throw new ArgumentException(); 
    Packet result = new Packet(); 
    // Marshal the header 
    fixed (byte* pdata = &data[0]) { 
     result.Header = (Header)Marshal.PtrToStructure(new IntPtr(pdata), typeof(Header)); 
    } 
    // Copy the rest 
    var varsize = data.Length - hdrsize; 
    result.VariableLengthData = new byte[varsize]; 
    Array.Copy(data, hdrsize, result.VariableLengthData, 0, varsize); 
    return result; 
} 

i zmodyfikować klasę Packet jak widać pasuje, prawdopodobnie chcesz dodać kilka właściwości do czynienia z char [ ].

+0

Rozważyłem również to rozwiązanie, ale także przeczytałem artykuł, który za pomocą "public fixed char Data [1]" również rozwiązuje ten problem, ale nie mam pełnego źródła, aby określić, w jaki sposób został użyty lub skonstruowany. Mogę skończyć jeżdżąc tą trasą ze względów bezpieczeństwa, ale czy wiesz, co one oznaczają w poniższym artykule? http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_27480829.html –

+0

Wziąłem twój pomysł i uczyniłem go częścią oryginalnej struktury, która może nie być najlepszym rozwiązaniem (zobacz pytanie na przykład), oraz wydaje się działać dla deserializacji, ale serializując ją z powrotem do tablicy byte [], potrzebowałbym rzeczywistego rozmiaru obiektu, a nie tylko sizeof (Header). Myśli?? –

+0

Rozważałem tablicę jednobajtową, ale ją odrzuciłem. Twój program może ulec awarii z AVE, jeśli kiedykolwiek otrzymasz pakiet bez dodatkowych danych. Być może dostaniesz gwarancję, że zawsze jest jakaś, nie mogłem zrobić tego samego założenia. –

Powiązane problemy