tarabyte
tarabyte

Reputation: 19172

How to parse serialized C structs from binary file in python?

I have a handful of different type of C-structs that are all compressed into a binary file.

struct-id serialized-struct struct-id serialized-struct ...

If it were the same struct over and over, it would make sense to use the struct package, but I want to switch between previously defined structs all the time.

STRUCT1_ID = '\xAA'
STRUCT2_ID = '\xBB'
STRUCT_IDS = frozenset([STRUCT1_ID, STRUCT2_ID])

struct1s = []
struct2s = []

def create_test_file(filepath):
    with open(filepath, 'wb') as f:
        # Write an example struct1 id followed by struct
        f.write(STRUCT1_ID)
        f.write(b'\x01\x02\x03\x04\x05\x06')
        # Write an example struct2 id followed by struct
        f.write(STRUCT2_ID)
        f.write(b'\x07\x08\x09\x0A')

def parse_test_file(filepath):
    with open(filepath, 'rb') as f:
        msg_type = f.read(1)
        while msg_type:
            print(byte)
            if byte in STRUCT_IDS:
                # Parse the next however many bytes needed by struct
                # logic breaks down here
                struct1s.append(turnIntoStruct(f.read(?)))
                msg_type = f.read(1)
            else:
              print('Corrupted file.  Unrecognized id')

In C, the structs would be:

typedef struct struct1_s {
  uint16_t a;
  uint16_t b;
  uint16_t c;
} struct1_t;

typedef struct struct2_s {
  uint16_t d;
  uint16_t e;
} struct2_t;

// Declare and initialize the structs
struct1_t s1 = {
  .a = 0x0201,
  .b = 0x0403,
  .c = 0x0605
};

struct2_t s2 = {
  .d = 0x0807,
  .e = 0x0A09
};

I'm less python than I am C right now. I seem unable to bring construct to python 3.4.3?

Upvotes: 0

Views: 380

Answers (1)

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798676

Map the ID to the struct pattern, and use the appropriate one.

structmap = {
  b'\xaa': ('3H', struct1s),
  b'\xbb': ('2H', struct2s)
}

 ...

structmap[msg_type][1].append(struct.unpack(structmap[msg_type][0],
  f.read(struct.calcsize(structmap[msg_type][0]))))

Upvotes: 1

Related Questions