dotfiles/.local/bin/packedstruct.py

62 lines
2.0 KiB
Python

# 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))