# Copyright 2021 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import struct class PackedStruct(object): """Class representing a C style packed structure Derived classes need to provide a dictionary with key will be the attributes and the values are the format characters for each field. e.g. class Foo(PackedStruct): _FIELDS = { x: 'I', name: '64s', } In this case Foo.x will represent an "unsigned int" C value, while Foo.name will be a "char[64]" C value """ def __init__(self, *args, **kwargs): self._fmt = '<' + ''.join(fmt for fmt in self._FIELDS.values()) for name in self._FIELDS: setattr(self, name, None) for name, val in zip(self._FIELDS.keys(), args): setattr(self, name, val) for name, val in kwargs.items(): setattr(self, name, val) def __repr__(self): return '{} {{\n'.format(self.__class__.__name__) + ',\n'.join( ' {!r}: {!r}'.format(k, getattr(self, k)) for k in self._FIELDS) + '\n}' def __str__(self): return struct.pack(self._fmt, *(getattr(self, x) for x in self._FIELDS)) def __bytes__(self): return struct.pack(self._fmt, *(getattr(self, x) for x in self._FIELDS)) def __len__(self): return struct.calcsize(self._fmt) @classmethod def from_bytes(cls, data): fmt_str = '<' + ''.join(fmt for fmt in cls._FIELDS.values()) return cls(*struct.unpack(fmt_str, data))