FieldType

Bases: object

Struct/Union field

Attributes:

Name Type Description
kind Kind

struct/union/native

c_type str

field type

ref AbstractCStruct

struct/union class ref

vlen int

number of elements

flexible_array bool

True for flexible arrays

offset int

relative memory position of the field (relative to the struct)

padding int

padding

Source code in cstruct/field.py
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
class FieldType(object):
    """
    Struct/Union field

    Attributes:
        kind (Kind): struct/union/native
        c_type (str): field type
        ref (AbstractCStruct): struct/union class ref
        vlen (int): number of elements
        flexible_array (bool): True for flexible arrays
        offset (int): relative memory position of the field (relative to the struct)
        padding (int): padding
    """

    def __init__(
        self,
        kind: Kind,
        c_type: str,
        ref: Optional[Type["AbstractCStruct"]],
        vlen: int,
        flexible_array: bool,
        byte_order: Optional[str],
        offset: int,
    ) -> None:
        """
        Initialize a Struct/Union field

        Args:
            kind: struct/union/native
            c_type: field type
            ref: struct/union class ref
            vlen: number of elements
            flexible_array: True for flexible arrays
            offset: relative memory position of the field (relative to the struct)
        """
        self.kind = kind
        self.c_type = c_type
        self.ref = ref
        self.vlen = vlen
        self.flexible_array = flexible_array
        self.byte_order = byte_order
        self.offset = self.base_offset = offset
        self.padding = 0

    def unpack_from(self, buffer: bytes, offset: int = 0) -> Any:
        """
        Unpack bytes containing packed C structure data

        Args:
            buffer: bytes to be unpacked
            offset: optional buffer offset

        Returns:
            data: The unpacked data
        """
        if self.is_native or self.is_enum:
            result = struct.unpack_from(self.fmt, buffer, self.offset + offset)

            if self.is_enum:
                result = tuple(map(self.ref, result))

            if self.is_array:
                return list(result)
            else:
                return result[0]
        else:  # struct/union
            if self.vlen == 1:  # single struct/union
                instance: AbstractCStruct = self.ref()  # type: ignore
                instance.unpack_from(buffer, self.offset + offset)
                return instance
            else:  # multiple struct/union
                instances: List[AbstractCStruct] = []
                for j in range(0, self.vlen):
                    instance: AbstractCStruct = self.ref()  # type: ignore
                    instance.unpack_from(buffer, self.offset + offset + j * instance.size)
                    instances.append(instance)
                return instances

    def pack(self, data: Any) -> bytes:
        """
        Pack the field into bytes

        Args:
            data: data to be packed

        Returns:
            bytes: The packed structure
        """
        if self.flexible_array:
            self.vlen = len(data)  # set flexible array size
            return struct.pack(self.fmt, *data)
        elif self.is_array:
            return struct.pack(self.fmt, *data)
        else:
            return struct.pack(self.fmt, data)

    @property
    def is_array(self) -> bool:
        "True if field is an array/flexible array"
        return self.flexible_array or (not (self.vlen == 1 or self.c_type == "char"))

    @property
    def is_native(self) -> bool:
        "True if the field is a native type (e.g. int, char)"
        return self.kind == Kind.NATIVE

    @property
    def is_enum(self) -> bool:
        "True if the field is an enum"
        return self.kind == Kind.ENUM

    @property
    def is_struct(self) -> bool:
        "True if the field is a struct"
        return self.kind == Kind.STRUCT

    @property
    def is_union(self) -> bool:
        "True if the field is an union"
        return self.kind == Kind.UNION

    @property
    def native_format(self) -> str:
        "Field format (struct library format)"
        if self.is_native:
            try:
                return get_native_type(self.c_type).native_format
            except KeyError:
                raise ParserError(f"Unknow type `{self.c_type}`")
        elif self.is_enum:
            return self.ref.__native_format__
        else:
            return "c"

    @property
    def fmt(self) -> str:
        "Field format prefixed by byte order (struct library format)"
        if self.is_native or self.is_enum:
            fmt = (str(self.vlen) if self.vlen > 1 or self.flexible_array else "") + self.native_format
        else:  # Struct/Union
            fmt = str(self.vlen * self.ref.sizeof()) + self.native_format
        if self.byte_order:
            return self.byte_order + fmt
        else:
            return fmt

    @property
    def vsize(self) -> int:
        "Field size in bytes"
        return struct.calcsize(self.fmt)

    @property
    def alignment(self) -> int:
        "Alignment"
        if self.is_native or self.is_enum:
            if self.byte_order is not None:
                return struct.calcsize(self.byte_order + self.native_format)
            else:
                return struct.calcsize(self.native_format)
        else:  # struct/union
            return self.ref.__alignment__

    def align_filed_offset(self) -> None:
        "If the byte order is native, align the field"
        if align(self.byte_order) and self.c_type != "char":
            self.padding = calculate_padding(self.byte_order, self.alignment, self.base_offset)
            self.offset = self.base_offset + self.padding

    def copy(self) -> "FieldType":
        "Return a shallow copy of this FieldType"
        return copy.copy(self)

    def __repr__(self) -> str:  # pragma: no cover
        return repr(self.__dict__)

alignment: int property

Alignment

fmt: str property

Field format prefixed by byte order (struct library format)

is_array: bool property

True if field is an array/flexible array

is_enum: bool property

True if the field is an enum

is_native: bool property

True if the field is a native type (e.g. int, char)

is_struct: bool property

True if the field is a struct

is_union: bool property

True if the field is an union

native_format: str property

Field format (struct library format)

vsize: int property

Field size in bytes

__init__(kind, c_type, ref, vlen, flexible_array, byte_order, offset)

Initialize a Struct/Union field

Parameters:

Name Type Description Default
kind Kind

struct/union/native

required
c_type str

field type

required
ref Optional[Type[AbstractCStruct]]

struct/union class ref

required
vlen int

number of elements

required
flexible_array bool

True for flexible arrays

required
offset int

relative memory position of the field (relative to the struct)

required
Source code in cstruct/field.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def __init__(
    self,
    kind: Kind,
    c_type: str,
    ref: Optional[Type["AbstractCStruct"]],
    vlen: int,
    flexible_array: bool,
    byte_order: Optional[str],
    offset: int,
) -> None:
    """
    Initialize a Struct/Union field

    Args:
        kind: struct/union/native
        c_type: field type
        ref: struct/union class ref
        vlen: number of elements
        flexible_array: True for flexible arrays
        offset: relative memory position of the field (relative to the struct)
    """
    self.kind = kind
    self.c_type = c_type
    self.ref = ref
    self.vlen = vlen
    self.flexible_array = flexible_array
    self.byte_order = byte_order
    self.offset = self.base_offset = offset
    self.padding = 0

align_filed_offset()

If the byte order is native, align the field

Source code in cstruct/field.py
228
229
230
231
232
def align_filed_offset(self) -> None:
    "If the byte order is native, align the field"
    if align(self.byte_order) and self.c_type != "char":
        self.padding = calculate_padding(self.byte_order, self.alignment, self.base_offset)
        self.offset = self.base_offset + self.padding

copy()

Return a shallow copy of this FieldType

Source code in cstruct/field.py
234
235
236
def copy(self) -> "FieldType":
    "Return a shallow copy of this FieldType"
    return copy.copy(self)

pack(data)

Pack the field into bytes

Parameters:

Name Type Description Default
data Any

data to be packed

required

Returns:

Name Type Description
bytes bytes

The packed structure

Source code in cstruct/field.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def pack(self, data: Any) -> bytes:
    """
    Pack the field into bytes

    Args:
        data: data to be packed

    Returns:
        bytes: The packed structure
    """
    if self.flexible_array:
        self.vlen = len(data)  # set flexible array size
        return struct.pack(self.fmt, *data)
    elif self.is_array:
        return struct.pack(self.fmt, *data)
    else:
        return struct.pack(self.fmt, data)

unpack_from(buffer, offset=0)

Unpack bytes containing packed C structure data

Parameters:

Name Type Description Default
buffer bytes

bytes to be unpacked

required
offset int

optional buffer offset

0

Returns:

Name Type Description
data Any

The unpacked data

Source code in cstruct/field.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def unpack_from(self, buffer: bytes, offset: int = 0) -> Any:
    """
    Unpack bytes containing packed C structure data

    Args:
        buffer: bytes to be unpacked
        offset: optional buffer offset

    Returns:
        data: The unpacked data
    """
    if self.is_native or self.is_enum:
        result = struct.unpack_from(self.fmt, buffer, self.offset + offset)

        if self.is_enum:
            result = tuple(map(self.ref, result))

        if self.is_array:
            return list(result)
        else:
            return result[0]
    else:  # struct/union
        if self.vlen == 1:  # single struct/union
            instance: AbstractCStruct = self.ref()  # type: ignore
            instance.unpack_from(buffer, self.offset + offset)
            return instance
        else:  # multiple struct/union
            instances: List[AbstractCStruct] = []
            for j in range(0, self.vlen):
                instance: AbstractCStruct = self.ref()  # type: ignore
                instance.unpack_from(buffer, self.offset + offset + j * instance.size)
                instances.append(instance)
            return instances

Kind

Bases: Enum

Field type

Source code in cstruct/field.py
51
52
53
54
55
56
57
58
59
60
61
62
63
class Kind(Enum):
    """
    Field type
    """

    NATIVE = 0
    "Native type (e.g. int, char)"
    STRUCT = 1
    "Struct type"
    UNION = 2
    "Union type"
    ENUM = 3
    "Enum type"

ENUM = 3 class-attribute

Enum type

NATIVE = 0 class-attribute

Native type (e.g. int, char)

STRUCT = 1 class-attribute

Struct type

UNION = 2 class-attribute

Union type