blob: bd755ce55f97e7d754d7b0f3f65f5784151c298b [file] [log] [blame]
Chirayu Desai7119eb62021-12-07 03:07:13 +05301# Copyright 2021 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
Michael Bestas0382f302023-06-12 02:22:51 +030015import collections
Chirayu Desai7119eb62021-12-07 03:07:13 +053016import struct
17
18
19class PackedStruct(object):
Michael Bestas0382f302023-06-12 02:22:51 +030020 """Class representing a C style packed structure.
Chirayu Desai7119eb62021-12-07 03:07:13 +053021
Michael Bestas0382f302023-06-12 02:22:51 +030022 Derived classes need to provide a dictionary where the keys are the attributes
23 and the values are the format characters for each field. e.g.
Chirayu Desai7119eb62021-12-07 03:07:13 +053024
Michael Bestas0382f302023-06-12 02:22:51 +030025 class Foo(PackedStruct):
26 _FIELDS = {
27 x: 'I',
28 name: '64s',
29 }
Chirayu Desai7119eb62021-12-07 03:07:13 +053030
Michael Bestas0382f302023-06-12 02:22:51 +030031 In this case Foo.x will represent an "unsigned int" C value, while Foo.name
32 will be a "char[64]" C value.
33 """
34 _FIELDS: collections.OrderedDict
Chirayu Desai7119eb62021-12-07 03:07:13 +053035
Michael Bestas0382f302023-06-12 02:22:51 +030036 def __init__(self, *args, **kwargs):
37 self._fmt = '<' + ''.join(fmt for fmt in self._FIELDS.values())
38 for name in self._FIELDS:
39 setattr(self, name, None)
Chirayu Desai7119eb62021-12-07 03:07:13 +053040
Michael Bestas0382f302023-06-12 02:22:51 +030041 for name, val in zip(self._FIELDS.keys(), args):
42 setattr(self, name, val)
43 for name, val in kwargs.items():
44 setattr(self, name, val)
Chirayu Desai7119eb62021-12-07 03:07:13 +053045
Michael Bestas0382f302023-06-12 02:22:51 +030046 def __repr__(self):
47 return '{} {{\n'.format(self.__class__.__name__) + ',\n'.join(
48 ' {!r}: {!r}'.format(k, getattr(self, k))
49 for k in self._FIELDS) + '\n}'
Chirayu Desai7119eb62021-12-07 03:07:13 +053050
Michael Bestas0382f302023-06-12 02:22:51 +030051 def __str__(self):
52 return struct.pack(self._fmt, *(getattr(self, x) for x in self._FIELDS))
Chirayu Desai7119eb62021-12-07 03:07:13 +053053
Michael Bestas0382f302023-06-12 02:22:51 +030054 def __bytes__(self):
55 return struct.pack(self._fmt, *(getattr(self, x) for x in self._FIELDS))
Chirayu Desai7119eb62021-12-07 03:07:13 +053056
Michael Bestas0382f302023-06-12 02:22:51 +030057 def __len__(self):
58 return struct.calcsize(self._fmt)
Chirayu Desai7119eb62021-12-07 03:07:13 +053059
Michael Bestas0382f302023-06-12 02:22:51 +030060 @classmethod
61 def from_bytes(cls, data):
62 fmt_str = '<' + ''.join(fmt for fmt in cls._FIELDS.values())
63 return cls(*struct.unpack(fmt_str, data))