Parsing a byte stream into struct / class

I have a stream of bytes that I need to parse into a struct and I also need to be able to parse the structure back into a stream of bytes.

Below is an example of what I want, where I used BitConverter to parse the values. I hope there is a more efficient way to do this, because my structures are HUGE!

ref struct TestStruct
{
    int TestInt;
    float TestFloat;
};

int main(array<System::String ^> ^args)
{
    // populating array - just for demo, it really coming from a file
    array<unsigned char>^ arrBytes = gcnew array<unsigned char>(8);
    Array::Copy(BitConverter::GetBytes((int)1234), arrBytes, 4);
    Array::Copy(BitConverter::GetBytes((float)12.34), 0, arrBytes, 4, 4);

    // parsing to struct - I want help
    TestStruct^ myStruct = gcnew TestStruct();
    myStruct->TestInt = BitConverter::ToInt32(arrBytes, 0);
    myStruct->TestFloat = BitConverter::ToSingle(arrBytes, 4);

    String^ str = Console::ReadLine();
    return 0;
}

      

0


source to share


4 answers


A code generator is usually used for such things. Let's assume the source looks like this:

struct a {
    int i;
}

struct b {
    string name;
    struct a a;
}

      

What you do is write a simple parser that looks up the source (maybe some header file) for a "struct", and then you read the name of the structure (anything between "struct" and "{"). Write this to the output:

cout << "struct " << name << " * read_struct_" << name << " (stream in) {" << NL
    << "    struct " << name << " * result = malloc (sizeof(struct " << name << "));" NL
parseFields (headerStream);
cout << "    return result;" << NL << "}" << NL ; } 

      

Note that my C ++ is a little rusty, so it probably won't compile, but you should get the idea.

In parseFields, you read each line and split it into two: anything before the last space (ie "int" in the first example) and stuff between the last space and ";". In this case, it will be "i". You are now writing the output:

cout << "read_" << fieldType << "(in, &result->" << fieldName << ");" << NL;

      



Note. You will need to replace all ub spaces with a field like "_".

In the output, it looks like this:

struct a * read_struct_a (stream in) {
   struct a * result = malloc(sizeof(struct a));
   read_int(in, &result->i);
   return result;
}

      

This allows you to define how to read or write an int somewhere else (in a service module).

You now have code that reads the structure definitions from a header file and creates new code that can read the structure from some stream. Duplicate this to write the structure to the stream. Compile the generated code and you're done.

You will also want to write unit tests to make sure the parsing is working correctly. Just create the structure in memory, use write methods to store it somewhere and read it again. The two structures should now be the same. You will want to write a third code generator to generate code for comparing two structures.

+1


source


Serialization in .NET is explained here



For generic C ++ (not managed) have a look at boost :: serialize

+1


source


Serialization is great, but in my case I don't need the "extras" and I would have to do the same job to have complete control over the bits. For most, this might be the solution I'm guessing.

Give Mr. Digulla the correct answer, as it is most similar to my solution. Also thanks to Mr. Davis who put me straight on doing this ...

0


source


You mention both C ++ and .net. For C ++ only, you can do something in strings

char buffer[sizeof(MYSTRUCT)];
memcopy((char*) &mystruct, buffer, sizeof(MYSTRUCT));

      

For .net, you MUST use serialization if you want to avoid storing each element separately - classes are not guaranteed to be stored in a contiguous block of memory. This is annoying, but this is one of the "features" of managed code β€” you have to let it manage it for you.

-Adam

-1


source







All Articles