Loading binary data into a structure

I am trying to populate a structure (not necessarily be a real structure), with data loaded from byte [].

Byte [] there are many different data structures, one of which is a string, which is declared as:

UInt16 stringLenght byte[stringLenght] zeroTerminatedString 
Tongue

I 'c' this can be processed by declaring a structure of a fixed size, and instead of a structure containing the actual string, make a pointer to the string.

Something like:

 UInt16 stringLength char* zeroTerminatedString 

Is there a (smart) way to do something like this in C #? I mean loading binary data from a file / memory and filling it into a structure?

Relationship Jakob Justesen

0
c #
source share
2 answers

This is not how you would declare it in C. If the entry in the file contains a string, you would declare a structure similar to:

 struct Example { int mumble; // Anything, not necessarily a string length char text[42]; // etc... }; 

The corresponding C # declaration would look like this:

  [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct Example { public int mumble; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)] public string text; // etc... } 

Usually you should use BinaryReader to read data. But it cannot handle strings like this directly, you have to read them as byte [] and convert the string yourself. You also cannot use declarative syntax, you need to write a call for each individual member of the structure.

A workaround for this, the marshal class already knows how to convert unmanaged structures to managed ones using the PtrToStructure () method. Here's a general implementation, it works for any type of blittable. Two versions, static, which are read from byte [], and an instance method that has been optimized to be read from the stream again. You would use FileStream or MemoryStream with this.

 using System; using System.IO; using System.Runtime.InteropServices; class StructTranslator { public static bool Read<T>(byte[] buffer, int index, ref T retval) { if (index == buffer.Length) return false; int size = Marshal.SizeOf(typeof(T)); if (index + size > buffer.Length) throw new IndexOutOfRangeException(); var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { IntPtr addr = (IntPtr)((long)handle.AddrOfPinnedObject() + index); retval = (T)Marshal.PtrToStructure(addr, typeof(T)); } finally { handle.Free(); } return true; } public bool Read<T>(Stream stream, ref T retval) { int size = Marshal.SizeOf(typeof(T)); if (buffer == null || size > buffer.Length) buffer = new byte[size]; int len = stream.Read(buffer, 0, size); if (len == 0) return false; if (len != size) throw new EndOfStreamException(); var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { retval = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } finally { handle.Free(); } return true; } private byte[] buffer; } 

Unconfirmed, hope this works.

+4
source share

Marshal should be able to do this for you.

Note that this can only be done for the structure, and you may have to use the StructLayout attribute .

I am not 100% sure how to process a string or arrays, but a BStrWrapper or ArrayWithOffset MAY help, as well as keep track of similar classes / attributes (I know that I did such things before to bind to native functions).

0
source share

All Articles