62 lines
2.0 KiB
Python
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))
|