Reading a C/C++ Data Structure in C# from a Byte Array

Reading a C/C++ data structure in C# from a byte array

From what I can see in that context, you don't need to copy SomeByteArray into a buffer. You simply need to get the handle from SomeByteArray, pin it, copy the IntPtr data using PtrToStructure and then release. No need for a copy.

That would be:

NewStuff ByteArrayToNewStuff(byte[] bytes)
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
NewStuff stuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff));
}
finally
{
handle.Free();
}
return stuff;
}

Generic version:

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{
T stuff;
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
handle.Free();
}
return stuff;
}

Simpler version (requires unsafe switch):

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
fixed (byte* ptr = &bytes[0])
{
return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
}
}

Use the data in a c# byte array

Structs are perfectly fine in C#, so there should be no issue with the struct pretty much exactly as you've written it, though you might need to add permission modifiers such as public. To convert byte arrays to other primitives, there are a very helpful class of methods that include ToInt64() that will help you convert an array of bytes to another built in type (in this case long). To get the specific sequences of array bytes you'll need, check out this question on various techniques for doing array slices in C#.

How do I read a struct from a Memory byte ?

.Net Core / .Net Standard 2.1 supports MemoryMarshal.Cast<TFrom, TTo> to do a reinterpret cast on a Span<TFrom> to a Span<TTo>. You should be able to use the Memory<T>.Span property to get a Span and then convert it to your struct.

How to read byte blocks into struct

Assuming this is C#, I wouldn't create a struct as a FileEntry type. I would replace char[20] with strings and use a BinaryReader - http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx to read individual fields. You must read the data in the same order as it was written.

Something like:

class FileEntry {
byte Value1;
char[] Filename;
byte Value2;
byte[] FileOffset;
float whatever;
}

using (var reader = new BinaryReader(File.OpenRead("path"))) {
var entry = new FileEntry {
Value1 = reader.ReadByte(),
Filename = reader.ReadChars(12) // would replace this with string
FileOffset = reader.ReadBytes(3),
whatever = reader.ReadFloat()
};
}

If you insist having a struct, you should make your struct immutable and create a constructor with arguments for each of your field.

 

A C# equivalent of C's fread file i/o

There isn't anything wrong with using the P/Invoke marshaller, it is not unsafe and you don't have to use the unsafe keyword. Getting it wrong will just produce bad data. It can be a lot easier to use than explicitly writing the deserialization code, especially when the file contains strings. You can't use BinaryReader.ReadString(), it assumes that the string was written by BinaryWriter. Make sure however that you declare the structure of the data with a struct declaration, this.GetType() is not likely to work out well.

Here's a generic class that will make it work for any structure declaration:

  class StructureReader<T> where T : struct {
private byte[] mBuffer;
public StructureReader() {
mBuffer = new byte[Marshal.SizeOf(typeof(T))];
}
public T Read(System.IO.FileStream fs) {
int bytes = fs.Read(mBuffer, 0, mBuffer.Length);
if (bytes == 0) throw new InvalidOperationException("End-of-file reached");
if (bytes != mBuffer.Length) throw new ArgumentException("File contains bad data");
T retval;
GCHandle hdl = GCHandle.Alloc(mBuffer, GCHandleType.Pinned);
try {
retval = (T)Marshal.PtrToStructure(hdl.AddrOfPinnedObject(), typeof(T));
}
finally {
hdl.Free();
}
return retval;
}

A sample declaration for the structure of the data in the file:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Sample {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string someString;
}

You'll need to tweak the structure declaration and the attributes to get a match with the data in the file. Sample code that reads a file:

  var data = new List<Sample>();
var reader = new StructureReader<Sample>();
using (var stream = new FileStream(@"c:\temp\test.bin", FileMode.Open, FileAccess.Read)) {
while(stream.Position < stream.Length) {
data.Add(reader.Read(stream));
}
}

Passing a struct with array of structures from c# to c++

Try:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public Location[] locations;

Array in c# is a reference type.

Recreate Class based on Serialized Byte Array

There is no an easy answer to your question because there is no default C++ binary serialization format like in .NET. Hence you will have to make binary reverse engineering of this data.

Because you said a class contains at least few floating points along with two strings, I would start from serializing similar class with one string and float field with two typical C++ serialization libraries:

  • boost:serialization
  • MFC

and compare with your data. If you know the values stored in sample data, try to find them and compare with similar data from those serializers.

However, answering your main questions, automatic tools do exists that can help you. I would start from searching for automated protocol analysis because most of the work and tools are related to network protocols analysis - which is similar to your problems as both tries to understand unknown structure of binary data. Nevertheless, most tools I've seen so far were more academical one, like Polyglot, The Protocol Informatics Project or PROTOS. If you are happy to have Mac OS X based system, you can use great Synalaze It! tool to help you a little.

How do you convert a C data structure to a C# struct that will allow you to read the data type from a file?

I think your first link https://stackoverflow.com/a/3863658/201021 is a good way to follow. So I guess the next thing would be constructing a C# struct to map C struct. Here is the map for different types from MSDN http://msdn.microsoft.com/en-us/library/ac7ay120(v=vs.110).aspx

Cheers!



Related Topics



Leave a reply



Submit