I'm parsing a binary file format (OpenType font file). The format is a complex tree of many different struct types, but one recurring pattern is to have an array of records of a particular format. I've written code using struct.unpack to get one record at a time. But I'm wondering if there's a way I'm missing to parse the entire array of records?
The following is an example of unpacked results for one particular kind of record array:
[{'glyphID': 288, 'paletteIndex': 0}, {'glyphID': 289, 'paletteIndex': 1}, {'glyphID': 518, 'paletteIndex': 0}, ...] list
This is what I'm doing at present: I've created a generic function to unpack an arbitrary records array (consistent record format in any given call).
def tryReadRecordsArrayFromBuffer(buffer, numRecords, format, fieldNames):
recordLength = struct.calcsize(format)
array = []
index = 0
for i in range(numRecords):
record = {}
vals = struct.unpack(format, buffer[index : index + recordLength])
for k, v in zip(fieldNames, vals):
record[k] = v
array.append(record)
index += recordLength
return array
The buffer parameter is a byte sequence at least the size of the array, with the first record to be unpacked at the start of the sequence.
The format parameter is a struct format string, according to the type of record array being read. In one case, the format string might be ">3H"; in another case, it might be ">4s2H"; etc. For the above example of results, it was ">2H".
The fieldNames parameter is a sequence of strings for the field names in the given record type. For the above example of results, this was ("glyphID", "paletteIndex").
So, I'm stepping through the buffer (byte sequence data), getting sequential slices and unpacking the records one at a time, creating a dict for each record and appending them to the array list.
Is there a better way to do this, a method like unpack in some module that allows defining a format as an array of structs and unpacking the whole shebang at once?
unpack()seems pretty good solution. Just small suggestion -array.append(dict(zip(fieldNames, vals))). Initialization of empty dict, loop and appending new value to list could be done in one line.